【问题标题】:scanf() (C Language ) confused mescanf() (C 语言)让我很困惑
【发布时间】:2010-06-17 01:41:40
【问题描述】:

我什么时候需要在 C 中为 scanf() 插入/不插入 &?谢谢。

int main()
{
    char s1[81], s2[81], s3[81];

    scanf("%s%s%s", s1, s2, s3);

    // If replace scanf() with the expression below, it works too.
    // scanf("%s%s%s", &s1, &s2, &s3);

    printf("\ns1 = %s\ns2 = %s\ns3 = %s", s1, s2, s3);

    return 0;
}

//programming is fun
//
//s1 = programming
//s2 = is
//s3 = fun

【问题讨论】:

  • 我建议阅读 K & R 的 C 编程语言。这实际上不是关于 scanf 的问题,而是关于 C 中内存访问如何工作的问题。

标签: c scanf


【解决方案1】:

scanf 将扫描的值放在它的参数指向的地址中。 & 是地址操作符,用来取变量的地址。

但是,您使用的是数组,当用作函数参数时,数组会降级为指针。因此,对于数组,您不需要使用 & 运算符。

例子:

char s[81];
int n;
int* nptr;
//Initialize nptr to some meaningful value
scanf("%s %d %d",s,&n,nptr);

在这种情况下,我们需要使用 & 运算符来获取被 n 保存的地址。我们不需要将它与 nptr 一起使用,因为它已经是指向内存中某个位置的指针,对于 s 也是如此,因为数组在传递给函数时会降级为指针。

【讨论】:

    【解决方案2】:

    格式说明符后面的参数必须是指针。当一个数组名被传递给一个函数时,初始元素的位置被传递,所以在你的例子中你根本不需要使用&。你可以这样做(来自K&R):

    int day, year;
    char monthname[20];
    
    scanf("%d %s %d", &day, monthname, &year);
    

    由于日期和年份是int,您必须使用& 来获取这些变量的地址。由于monthname 是一个数组,所以不需要&

    【讨论】:

    • 数组名不是指针,而是根据使用的上下文隐式转换为一个。否则sizeof 和操作符地址将无法按预期工作。跨度>
    • @Georg:确实如此。我编辑了我的答案,使其更加明确。
    【解决方案3】:

    在 C 中,当你处理数组时:

    int c_array[24];
    c_array == &c_array == &c_array[0]
    

    是的,这很有趣 - 它们看起来一样(不同之处在于类型)。阅读this

    【讨论】:

    • 比较&s1[1]&(&s1)[1] 这两个地址时,类型的差异会变得明显。索引将 元素的大小 乘以索引值添加到地址。 &s1 处元素的大小是 sizeof(s1),即 81。
    【解决方案4】:

    来自 comp.lang.c 常见问题解答:I thought you always needed an & on each variable passed to scanf.

    我强烈建议您阅读comp.lang.c FAQ 的其余部分。

    【讨论】:

      【解决方案5】:

      s1 返回数组第一个元素的地址,而&s1 返回数组本身的地址。第一个元素的地址和数组本身的地址是相同的,因此这两种表示都有效。

      【讨论】:

        【解决方案6】:

        只是猜测,但我认为这是因为 s1s2s3 是数组。

        【讨论】:

          【解决方案7】:

          如果a 是一个数组,则a&a 在此上下文中都会产生一个指针:

          • a 确实是由于数组衰减为指针(C99,§6.3.2.1/3):

            除非是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串字面量,类型为''数组的表达式'' 被转换为类型为 ''pointer to type'' 的表达式,它指向数组对象的初始元素,并且不是左值。

            ...增加重点

          • &a& 运算符的结果 - 它返回一个指向对象的指针。

          【讨论】:

            【解决方案8】:

            Scanf 接受可变数量的参数。 scanf 的第一个参数是格式,然后是 n 个要存储值的地址,而 n 是格式字符串中指定的格式数。由于您使用的是数组,因此要存储值,您必须提供数组的基地址。

            //如果是整数 诠释我; scanf("%d",&i); // 将 int 值存储在地址 &i 浮动 f; scanf("%f",&f); //将浮点值存储在地址&f 诠释一个[10]; scanf("%s",a); //将字符串或数组值存储在a

            如果在最后一行使用 a 让您感到困惑,您可以尝试使用第一个元素的地址 &a[0] 来做同样的事情。

            希望对你有帮助,
            GG

            【讨论】:

              【解决方案9】:

              通常,您会像在未注释行中那样使用 scanf。 C 数组的工作方式是像 s1、s2 和 s3 这样的数组的名称,实际上是数组第一个元素的地址。但是,对于任何原语,您都必须使用 &variable 语法。例如:

              float f;
              scanf("%f", &f);
              

              【讨论】:

              • 数组名称不是指向第一个元素的指针,请参阅 Bills 答案的评论。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-24
              • 2014-09-28
              • 2013-06-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多