【问题标题】:What happens if I use "&" with string in scanf function?如果我在 scanf 函数中使用带有字符串的“&”会发生什么?
【发布时间】:2018-11-16 05:54:16
【问题描述】:

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

scanf("%s",&T);

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

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

【问题讨论】:

  • scanf("%s", &amp;T); 有一个更大的问题:没有宽度限制。在这里使用scanf("%1s", T);

标签: c string scanf


【解决方案1】:

代码sn-p的相关部分是:

char T[2];
scanf("%s", &T);

&amp;T 是一个指向两个字符数组 (char (*)[2]) 的指针。这不是scanf 需要%s 说明符的类型:它需要一个指向字符的指针(char *)。所以程序的行为是不确定的。

如你所知,编写这个程序的正确方法是

char T[2];
scanf("%s", T);

由于T 是一个数组,当它在大多数上下文中使用时,它“衰减”为指向第一个字符的指针:T 等效于&amp;(T[0]),其类型为char *。当您获取数组的地址 (&amp;T) 或其大小 (sizeof(T)) 时,不会发生这种衰减。

实际上,几乎所有平台都对指向同一地址的所有指针使用相同的表示。因此编译器为T&amp;T 生成完全相同的代码。有一些罕见的平台可能会生成不同的代码(我听说过它们,但我说不出来)。一些平台对“字节指针”和“字指针”使用不同的编码,因为它们的处理器本机寻址字,而不是字节。在此类平台上,指向同一地址的int *char * 具有不同的编码。这些类型之间的转换会转换值,但在变量参数列表之类的东西中滥用会导致错误的地址。但是,我希望此类平台将字节地址用于 char 数组。还有一些罕见的平台,指针不仅编码数据的地址,还编码一些类型或大小信息。然而,在这样的平台上,类型和大小信息必须是等价的:它是一个 2 字节的块,从地址T 开始,并且可以逐字节寻址。所以这个特殊的错误不太可能产生任何实际影响。

请注意,如果你一开始有一个指针而不是一个数组,那将是完全不同的:

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

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

注意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

【讨论】:

    【解决方案2】:

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

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

    scanf("%s",t);
    

    t 衰减为指向第一个元素的指针,这样就可以了。

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

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

    【讨论】:

    • 虽然从技术上讲是类型不匹配,但是否曾经有过一个平台,或者您认为可能会有一个两个指针可能不同的平台?是否有任何 C 标准允许它们有所不同?
    • @MadPhysicist C 允许指向 char* 的指针和指向 char 的指针在大小、布局、传递约定等方面有所不同。从技术上讲,它是 UB,但很少成为大问题。有能力的编译器会发出警告。
    • @chux。只是为了澄清(因为我似乎从来没有做对),指向数组的指针总是等同于 char * 指针?
    • @MadPhysicist 它们的类型不同 - 而且它们不兼容。例如,尝试对两个指针进行指针运算。
    • @Mad Physicist:专门为这种 C 代码压力测试设计的人工平台可能会故意为这两种指针类型采用不同的对象表示。这是语言规范允许的。
    猜你喜欢
    • 1970-01-01
    • 2016-04-06
    • 1970-01-01
    • 2014-08-20
    • 1970-01-01
    • 2022-08-22
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    相关资源
    最近更新 更多