繁体   English   中英

如果我在 scanf 函数中使用带有字符串的“&”会发生什么?

[英]What happens if I use "&" with string in scanf function?

我刚刚在博客中看到了一些代码。 它使用

scanf("%s",&T);

但正如我们所知,我们不应该在字符串中使用&符号,因为它会自动分配该字符串的第一个地址。 我确实运行了该代码,令人惊讶的是它正在运行,所以我想知道当我在字符串中使用&时会发生什么?

#include <stdio.h>
int main()
{
    char T[2];
    scanf("%s", &T);
    printf("You entered %s\n", T);
}

从技术上讲,这是一种类型不匹配,导致未定义行为 对于扫描string ,预期参数是指向字符数组初始元素的指针。

当你有一个char[somevalue]类型的数组t时,当你说

scanf("%s",t);

t衰减到指向第一个元素的指针,所以没问题。

另一方面,当你说&t ,它是char (*)[somevalue] - 指向数组的指针,整个数组,而不是指向数组初始元素的指针。

现在,由于数组的地址和数组的第一个元素的地址相同(内存位置),因此,将扫描值写入提供的地址可能不会导致任何问题并按预期工作 - 但这两者都不是定义或推荐。

代码片段的相关部分是:

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生成完全相同的代码。 有一些罕见的平台可能会生成不同的代码(我听说过它们,但我无法命名)。 一些平台对“字节指针”和“字指针”使用不同的编码,因为它们的处理器本机寻址的是字,而不是字节。 在此类平台上,指向同一地址的int *char *具有不同的编码。 这些类型之间的转换会转换值,但在诸如可变参数列表之类的东西中误用会导致错误的地址。 但是,我希望这样的平台对字符数组使用字节地址。 还有一些罕见的平台,其中指针不仅编码数据的地址,还编码一些类型或大小信息。 然而,在这样的平台上,类型和大小信息必须是等效的:它是一个 2 字节的块,从T的地址开始,可逐字节寻址。 所以这个特定的错误不太可能产生任何实际影响。

请注意,如果您首先使用指针而不是数组,情况将完全不同:

char *T; // known to point to an array of two characters
scanf("%s", &T); // bad

这里&T是指向内存中包含字符数组地址的位置的指针。 所以scanf会将它读取的字符写在指针T存储在内存中的位置,而不是T指向的位置。 大多数编译器会分析printfscanfprintf的格式字符串,因此会发出错误消息。

请注意, char T[2]只有两个字符的空间,这包括字符串末尾的空字节。 所以scanf("%s", T)只能读取单个字符。 如果此时输入包含多个非空白字符,程序将溢出缓冲区。 要读取单个字符并使其成为单字符字符串,请使用

char T[2];
scanf("%c", T);
T[1] = 0;

scanf("%s", T) ,它读取任何字符,甚至是空格。 要读取具有长度限制的字符串,请向%s规范添加限制。 你永远不应该在scanf使用无限的%s ,因为这将读取尽可能多的输入,不管有多少空间可以在内存中存储这个输入。

char T[2];
scanf("%1s", T); // one less than the array size

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM