【问题标题】:Why does the program print out an "@" when I enter nothing?为什么当我什么都不输入时程序会打印出一个“@”?
【发布时间】:2016-12-01 13:15:29
【问题描述】:

我写了一个程序来反转一个字符串。但是,当我只输入“回车”键时,它会打印出一个“@”。

代码如下:

#include <stdio.h> 
#include <string.h>
int main(void)
{
    int i, j, temp;
    char str[80];       

    scanf("%[^\n]s", str);
    i =  strlen(str);
    //printf("%d\n", i);
    //printf("%d\n", sizeof(str));
    for (j=0; j<i/2; j++) {
       temp=str[i-j-1];
       str[i-j-1]=str[j];
       str[j]=temp;
    }    
    for(i = 0; str[i] != 0; i++)  
       putchar(str[i]);
}

我尝试使用printf() 函数来查看当我按下“Enter”键时会发生什么。

但是,添加printf("%d\n", i);后,输出变成了“3@”。

添加printf("%d\n", sizeof(str));后,输出变为“0 80”。

似乎“sizeof”已经自动“修复”了问题。

我室友说问题可能是初始化造成的。我尝试将代码char str[80] 更改为char str[80] = {0},一切正常。但是我仍然不明白“sizeof”存在于代码中时的作用。如果真的导致初始化,程序一行行运行为什么会出现这种情况?

【问题讨论】:

  • 在分配变量之前取消引用(使用)变量的值会导致未定义的行为 (UB),这意味着任何事情都可能发生。
  • 具体来说,内存被初始化为0,所以内存位置已经存在的东西仍然存在。通过设置char str[80] = {0},您是说在数组中创建第一个值0,然后用null(即0)填充数组的其余部分。
  • 感谢您的 cmets。但是,我仍然不明白为什么我使用了“sizeof”后问题就解决了。
  • 你混淆了数组长度和字符串长度。 Sizeof 返回元素的字节大小(这里 str 是一个 80 个字符的数组,一个 char 是 1 个字节大小)。但是如果在你的str中你写“toto”,字符串长度是4。但是sizeof(str)仍然是80
  • @Fefux 谢谢你的帮助,但我怕我表达得不好。在此程序中,如果未输入任何内容,则字符串长度应为 0。然而,在我使用“sizeof”之前,由于未定义的行为,“strlen”返回了“3”。但是,我在下一行添加“sizeof”后,“strlen”为什么返回正确的数字“0”?

标签: c


【解决方案1】:

当您声明一个数组而不初始化数组的任何部分时,您会收到一个指向尚未初始化的内存位置的指针。该内存位置可能包含任何东西。事实上,你很幸运,它就停在了@

通过指定char str[80] = {0},您实际上是在说:

char str[80] = {0, 0, 0, /* 77 more times */ };

从而将字符串初始化为所有null 值。这是因为如果数组被部分初始化,编译器会自动用nulls 填充数组。 (但是,当您从堆中分配内存时,不是这种情况,只是一个警告)。

要了解为什么会发生一切,让我们看看你的代码。

当您将i 设置为strlen(str) 返回的值时,strlen 将遍历从str 指向的内存位置开始的位置。由于您的内存没有初始化,它会在位置 0 找到 @,然后在位置 1 找到 0,因此它正确返回 1。

当您不输入任何内容时,循环会发生什么? i 设置为 0,j 设置为 0,因此条件 j&lt;i/2 的计算结果为 0&lt;0,这是错误的,因此它转到第二个条件。第二个条件仅测试数组中的当前位置是否为null。巧合的是,您会返回一个内存位置,其中第一个char@。它打印出来,幸运的是下一个值是null

当您使用sizeof 运算符时,您将收到分配在堆栈上的整个数组的大小(这很重要,如果您开始使用指针,您以后可能会遇到此问题)。如果您使用strlen,您将收到1

建议

我建议不要尝试做i = strlen(str);,而是做i = scanf("%[^\n]s", str);。这是因为scanf 返回读取并放入缓冲区的字符数。另外,尽量使用描述性更强的变量名,这样阅读代码就容易多了。

【讨论】:

  • scanf 返回扫描的 tokens 数(不是字节数)。在这种情况下,如果成功,则返回 1str 已更新。如果失败,则返回0,而str 将不会被更新。
  • @KlasLindbäck 是的,我会在有时间后再更新答案
【解决方案2】:

做一个 str 的 memset 然后它什么都不会代替垃圾

char str[80];       
memset(str,0,80);

【讨论】:

    猜你喜欢
    • 2021-08-21
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多