我刚刚在博客中看到了一些代码。
它使用
scanf("%s",&T);
但正如我们所知,我们不应该在字符串中使用&符号,因为它会自动分配该字符串的第一个地址。我确实运行了该代码,令人惊讶的是它正在运行,所以我想知道当我在字符串中使用
&
时会发生什么?#include <stdio.h>
int main()
{
char T[2];
scanf("%s", &T);
printf("You entered %s\n", T);
}
最佳答案
代码片段的相关部分是:
char T[2];
scanf("%s", &T);
&T
是一个指向两个字符数组 ( char (*)[2]
) 的指针。这不是 scanf
需要用于 %s
说明符的类型:它需要一个指向字符 ( char *
) 的指针。所以程序的行为是未定义的。如您所知,编写此程序的正确方法是
char T[2];
scanf("%s", T);
由于
T
是一个数组,当它在大多数情况下使用时,它会“衰减”到指向第一个字符的指针:T
等价于 &(T[0])
,其类型为 char *
。当您获取数组的地址 ( &T
) 或其大小 ( sizeof(T)
) 时,不会发生这种衰减。实际上,几乎所有平台都对指向同一地址的所有指针使用相同的表示。因此编译器为
T
和 &T
生成完全相同的代码。有一些罕见的平台可能会生成不同的代码(我听说过它们,但我无法命名)。一些平台对“字节指针”和“字指针”使用不同的编码,因为它们的处理器 native 寻址的是字,而不是字节。在此类平台上,指向同一地址的 int *
和 char *
具有不同的编码。这些类型之间的转换会转换值,但在诸如可变参数列表之类的东西中误用会导致错误的地址。但是,我希望这样的平台对字符数组使用字节地址。还有一些罕见的平台,其中指针不仅编码数据的地址,还编码一些类型或大小信息。然而,在这样的平台上,类型和大小信息必须是等效的:它是一个 2 字节的块,从 T
的地址开始,并且可以逐字节寻址。所以这个特定的错误不太可能产生任何实际影响。请注意,如果您首先使用指针而不是数组,情况将完全不同:
char *T; // known to point to an array of two characters
scanf("%s", &T); // bad
这里
&T
是指向内存中包含字符数组地址的位置的指针。因此 scanf
会在指针 T
存储在内存中的位置写入它读取的字符,而不是在 T
指向的位置。大多数编译器会分析 printf
和 scanf
等函数的格式字符串,因此会发出错误消息。请注意,
char T[2]
只有两个字符的空间,这包括字符串末尾的空字节。所以 scanf("%s", T)
只能读取单个字符。如果此时输入包含多个非空白字符,程序将溢出缓冲区。要读取单个字符并使其成为单字符字符串,请使用char T[2];
scanf("%c", T);
T[1] = 0;
与
scanf("%s", T)
不同,它读取任何字符,甚至是空格。要读取具有长度限制的字符串,请向 %s
规范添加限制。永远不要在 %s
中使用无限制的 scanf
,因为这将读取尽可能多的输入,而不管有多少空间可以将此输入存储在内存中。char T[2];
scanf("%1s", T); // one less than the array size
关于c - 如果我在 scanf 函数中使用带有字符串的 "&"会发生什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53332187/