【问题标题】:Arrays as scanf's function arguments. Adress operator数组作为 scanf 函数参数。地址运算符
【发布时间】:2015-05-04 03:13:50
【问题描述】:
#include <stdio.h>

int main(void)
{
  char s[32];

example_1:
  scanf("%s", s);
  printf("%s\n", s);

example_2:
  scanf("%s", &s[0]);
  printf("%s\n", s);

example_3:
  scanf("%s", &s);
  printf("%s\n", s);
}
  1. 为什么#3 的工作方式与其他 2 相同?

  2. #3 是否有效?为什么?

【问题讨论】:

标签: c arrays pointers scanf variadic-functions


【解决方案1】:
  1. 变体一依赖于array decay,因此是有效的。

    (在大多数情况下,数组衰减为指向其第一个元素的指针,例外情况是:地址(&amp;s)、sizeof s_Alignas(s)_Alignof(s)。)

  2. 变体 2 完成了 array-decay 手动执行的操作并且更加冗长,因此更糟。

  3. 变体三严格来说是Undefined Behavior,尽管它恰好适用于大多数实现。
    症结在于&amp;s 在默认促销后不是char* 类型,尽管它指向正确的地址。

似乎工作是 UB 中最危险的子集。

【讨论】:

    【解决方案2】:

    虽然三者的类型不同:

    • s 是一个 char[32](一个由 32 个 chars 组成的数组),它在需要时透明地衰减为 char*
    • &amp;s[0]char*(指向 char 的指针)
    • &amp;schar(*)[32](指向 32 个 chars 的数组的指针)

    它们都解析为相同的值(字符数组的起始地址)。因此,当将它传递给printf 时,它需要char*,结果对于所有3 都是相同的(假设char(*)[32] 的对象表示与char* 的对象表示相同,即实现依赖,但通常是这种情况)。

    只有前两个是有效的 - 第三个只是偶然的。

    【讨论】:

    • 明白。所以,准确地说,假设 case #3 是无效的,因为它违反了标准中的 *printf 函数格式规范(如果提供的参数与格式类型不对应,它会立即调用 UB)是否正确?还是这里有什么违反的?
    • @HighPredator:是的,就是这样。
    • @Deduplicator,谢谢。我还有一个问题要关注这个话题。假设我们有以下内容: > char s[32]; > 字符目的地[32]; > /* 这里有一些代码 */ > memcpy(&dst, &s, sizeof(s));这也是错的吗?附言抱歉,我还在为这里的编辑而苦恼……
    • @HighPredator:因为s 的大小合适(它是char[32]),所以“有效”。但由于不相关,它非常容易出错。
    • @Deduplicator,你能澄清一下“不相关”的部分吗?不确定我是否理解正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    • 1970-01-01
    • 2019-01-10
    • 2013-06-23
    • 2020-09-19
    相关资源
    最近更新 更多