printf 没有正确显示我的字符串 - 为啥?

Posted

技术标签:

【中文标题】printf 没有正确显示我的字符串 - 为啥?【英文标题】:printf doesn't display my string correctly - why?printf 没有正确显示我的字符串 - 为什么? 【发布时间】:2021-10-04 12:42:10 【问题描述】:

这是我的代码

    int wordSize = 8; // defining a word size

    int *myArray = NULL;
    myArray = malloc(sizeof(char)*(wordSize+1)); // using malloc() so I always have a big enough array should wordSize change. Also to practice.

    int index = 0; // defining a variable to browse through myArray

    do
    
        myArray[index] = '*';
        index++;
    
    while(index < wordSize);

    myArray[wordSize] = '\0'; // filling myArray with '*' character and the null terminator /0

    printf("%s", myArray); // trying to display myArray, only a single '*' is printed

    printf("\n\n");

    int i=0;

    while(i < wordSize+1)
    
        printf("%c", myArray[i]);
        i++;
     // trying to display myArray with an other method, this time with success

自从

char string[] = "hello";

    printf("%s", string);

工作得很好,我不明白为什么printf("%s", myArray); 不工作,只显示一个*。 do/while 循环按预期显示 8 *,这意味着我的数组已按应有的方式填充。

编辑:按照 cmets 的要求,简化了我的示例,并尝试了一些解决方案和其他一些可能性。

【问题讨论】:

*displayedSecretWord[characterCount] = '\0'; 是错误的,因为它试图访问索引为characterCount 的元素,但malloc(sizeof(int)*characterCount); 只为从0 到characterCount−1 的索引分配了足够的内存。除此之外,编辑问题以提供minimal reproducible example。 "This is because when my basic game will be working I want to be able to randomly choose from a list of words, so I can't have a fixed array." -- 你可以有一个强制的最大字长,然后你也可以有一个固定大小的数组。但是,如果您愿意,当然也可以使用malloc 如果你想要一个字符数组,那你为什么要创建一个整数数组呢?每次增加指针时,它都会移动 4 个字节(sizeof int),因此您跳过了 3 个字符。 【参考方案1】:

我认为这是问题所在。

int *myArray = NULL;
...
printf("%s", myArray);

您正在尝试打印一个整数数组,就好像它是一个字符串一样。我认为,通过将错误类型的变量传递给printf(),您将调用未定义的行为。您只为wordSize+1字节分配了足够的内存,然后继续将值写入数组,就好像它对wordSize+1整数足够大一样,这也是有问题的。

通过更改 myArray 的定义来解决此问题:

char *myArray = NULL;

访问此数组成员的其余代码现在应该从写入int 值更改为写入char 值。需要明确的是,我认为您不需要更改任何内容。一旦myArray 被正确定义为char 的数组,编译器就会为您完成。

预计到达时间: 详细了解原始代码中发生的情况。

最初,您分配 9 个字节。这个空间足以容纳略多于 2 个整数(假设 sizeof(int) 为 4)。我还假设这个内存最初是用零填充的。

分配给myArray 的内存如下所示:

myArray[0] 00  00  00  00 
myArray[1] 00  00  00  00
myArray[2] 00

然后你遍历并在内存中存储 8 个 '*' 字符,这使内存看起来像这样:

myArray[0] '*' 00  00  00
myArray[1] '*' 00  00  00
myArray[2] '*'

请注意,另外五个星号会写入您不拥有的内存中。 然后在为myArray 分配的内存之外写入一个“终止零”。

然后,您将myArray(即myArray 中第一个字节的地址)传递给printf()。您使用了%s 格式说明符,因此它将打印一个字符串。在它打印出第一个字节(一个星号)之后,它看到的下一个字节是零,所以它停止了。

最后,您可以访问myArray 的各个整数成员,就好像它是一个由八个整数组成的数组一样(即使没有足够的内存来容纳三个)。这意味着,代码将与myArray[0] 对应的四个字节读入一个临时整数,并将其值作为字符打印(因为%c 格式说明符传递给printf())。随着循环的继续,稍后的内存区域会被读取,包括不属于您的内存。观察到的结果是星号还在你写的地方。

请注意,这一切都是基于对您的开发环境、目标架构等的假设。您观察到的确切机制可能很有趣——但重要的是要记住,这都是未定义行为的所有示例。您不应该依赖它,因为在不同的系统或不同的日子,结果可能会完全不同。

【讨论】:

感谢您的解释。现在,有两件事:1)myArray 是一个指针,那么为什么它是 int 或 char 很重要,如果这不是我们正在修改的内容? 2)为什么循环在显示 myArray 时仍然有效,即使它是 int 而 printf 不是? 你的 ETA 说得很清楚,非常感谢!【参考方案2】:

如果 testCharacter 初始化为 0 我认为您应该对显示的SecretWord 使用字符指针类型 然后为displayedSecretWord分配sizeof(char) * (characterCount+1)。

【讨论】:

以上是关于printf 没有正确显示我的字符串 - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 UITableView 单元格的渐变子层没有正确显示?

Android - 为啥 Recycler 视图未显示在设备上? .我认为我的代码是正确的,但视图没有显示

在 iOS 7 下运行我的 iOS 6 应用程序时,为啥我的视图上没有正确显示阴影?

当我写下原因时,我的 AFK 命令只显示一个字。为啥?

为啥我的代码没有为表达式字符串计算正确的值?

为啥visual+studio+code里面用c语言写的printf输出中终端显示问号?