把地址传递给数组而不是数组本身,会引起问题吗?(涉及IT技术)

8

我遇到了这段代码:

char str[600];
scanf("%s", &str);

当然,这会发出如下警告:
a.c:6:17: warning: format specifies type 'char *' but the argument has type
      'char (*)[600]' [-Wformat]
    scanf("%s", &str);
           ~~   ^~~~~~~

我知道正确的方法是去掉&并输入scanf("%s", str)。但是它确实可行,所以我的问题是这是否会引起任何问题。它是否是未定义的行为?当我将str从数组改为指针时,它(显然)无法工作。但在使用数组时,这会导致任何问题吗?

3个回答

9

是的,代码出现了未定义行为。与%s对应的参数必须具有char *类型。这在C17 7.21.6.2/12中的s说明符下进行了描述:

[...] 相应的参数应该是一个指向足以接受序列和自动添加的终止空字符的字符数组的初始元素的指针。

这很清楚地表明指针应该具有指向字符的类型,而不是整个数组的指针。

未定义行为意味着任何事情都可能发生。它可能会像省略&一样运行,也可能格式化您的硬盘。

考虑到在这种情况下极其容易避免未定义行为,我真的没有看到任何理由争论是否可以依赖于此情况的未定义行为。


7.19.6.1?你是指 7.21.6.1 fprintf函数 吗?为什么 6.2.7 兼容类型和复合类型 不能“保存”UB的发布代码?数组的地址是第一个元素的地址,必须与指向数组元素的相同类型的指针类型兼容吗?我倾向于同意你的答案,即它是UB,因为7.21.6.1说它是UB,但我可以看出通过兼容类型和数组衰减可以进行论证。这非常深奥... - Andrew Henle
1
@AndrewHenle -- “数组的地址是第一个元素的地址,必须与指向该类型元素的指针类型兼容?”:我不确定你想表达什么,但听起来你是在说指向数组和指向该数组第一个元素的指针是兼容的类型。我无法看到标准支持这种方式的任何方法,因为如果两个类型相同,则它们具有兼容的类型(加上一些规则,似乎不适用于此处)。 - ad absurdum
标准文档对 fscanf 的规定如下:如果此对象没有适当类型,或者转换的结果无法表示为该对象,行为将未定义。 - klutt
@AndrewHenle 这是 scanf 函数,而不是 printf 函数。char *char (*)[600] 不是兼容的类型(这个术语由 C17 6.2.7 定义)。 - M.M
1
@AnttiHaapala,这种措辞似乎也允许unsigned char *,因为它符合“字符”的描述。 - M.M
显示剩余9条评论

2
在这种情况下,使用&str而不是str没有引起任何问题,因为这两者的地址相同。有关说明,请参见此前的问题。但正如您所指出的那样,&str的类型是不同的,编译器会发出警告,并且实际行为将取决于架构和实现。

在常见的架构中可能不会引起问题,但严格来说,这是不允许的。可能会导致问题的一件事是:不能保证不同指针类型使用相同的表示来表示相同的地址。因此,在这种情况下,涉及到的类型 char*char (*)[600] 可能具有不同的大小或值表示。 - aschepler
@aschepler 好的。我想,规范中未定义的任何行为都将是实现或架构特定的。最好一开始就写正确。 - Paul
@Paul -- “任何规范未定义的行为”:问题不在于行为未被定义,而是标准明确指出该行为是未定义的。向函数传递错误类型并非灰色地带。 - ad absurdum
是的,虽然行为未定义和明确未定义之间的区别似乎并不那么大。我会更新我的答案,说它在这种情况下“没有”引起任何问题,而不是它“不会”引起任何问题。 - Paul
1
@Paul -- 编译器编写者可以利用某些构造导致显式未定义行为(因此不应出现在有效的C程序中)来进行一些优化。我认为这与省略行为的未定义行为以及标准中给出的许多实现定义行为相比是一个重要的区别。 - ad absurdum

-4
在C语言中,数组的名称也是它的地址(指向数组的开头)。

这不是真的。在C语言中,数组是对象(以C语言的意义),而数组标识符指向数组对象。在大多数表达式中,数组会_衰减_为指向其第一个元素的指针(但并非所有表达式都是如此)。特别地,在char arr[] = "abc"; size_t arr_sz = sizeof arr;中,标识符arr不仅指向一个_数组_,而且在sizeof表达式中不会衰减为指针。 - ad absurdum
你说得对。我想表达的是,“数组名称”可以用作其地址,而不仅仅是数组本身就是地址。 - XsOuLp
@XsOuLp 仍然不正确。实际例子:sizeof(arr),这里的 arr 是一个数组类型,不会衰减。它绝对不是以任何方式、形式或形态表示地址。 - bolov
更多阅读:https://dev59.com/AWEh5IYBdhLWcg3w0WZP - bolov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接