c - 如果我在 scanf 函数中使用带有字符串的“&”会发生什么?
问题描述
我刚刚在博客中看到了一些代码。它使用了
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])
which 的类型为char *
。&T
当您获取数组的地址 ( ) 或其大小 ( )时,不会发生这种衰减sizeof(T)
。
实际上,几乎所有平台都对指向同一地址的所有指针使用相同的表示。T
因此编译器为和生成完全相同的代码&T
。有一些罕见的平台可能会生成不同的代码(我听说过它们,但我说不出来)。一些平台对“字节指针”和“字指针”使用不同的编码,因为它们的处理器本机寻址字,而不是字节。在这样的平台上,anint *
和 achar *
指向同一个地址有不同的编码。这些类型之间的转换会转换值,但在变量参数列表之类的东西中滥用会导致错误的地址。但是,我希望此类平台将字节地址用于 char 数组。还有一些罕见的平台,指针不仅编码数据的地址,还编码一些类型或大小信息。然而,在这样的平台上,类型和大小信息必须是等价的:它是一个 2 字节的块,从 的地址开始T
,并且可以逐字节寻址。所以这个特殊的错误不太可能产生任何实际影响。
请注意,如果您首先使用指针而不是数组,那将是完全不同的:
char *T; // known to point to an array of two characters
scanf("%s", &T); // bad
这&T
是一个指向内存中包含字符数组地址的位置的指针。所以scanf
会将它读取的字符写入指针T
存储在内存中的位置,而不是指向的位置T
。大多数编译器会分析函数的格式字符串,例如printf
andscanf
会发出错误消息。
请注意,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
推荐阅读
- postgresql - Typeorm获取ID数组列的关系
- javascript - 是否有用于检查 cookie 自动删除的 JS 浏览器 API?
- python-2.7 - PYTHON - 从 Azure Cosmos DB 的集合中删除项目
- reactjs - React Component:更新组件,基于另一个没有关系的组件
- angular - 用字符串修补值
- spring - 如何将标头添加到 URI
- puppeteer - 为什么 puppeteer 向我显示 DOMEXCEPTION :“无法在“文档”上执行 'querySelector'?
- javascript - Node js在完成多行代码之前执行函数
- selenium - 如何执行相同的黄瓜功能或场景 n 次?
- javascript - 箭头函数中的Expo Sound