【问题标题】:How does the scanf function work in C?scanf 函数在 C 中是如何工作的?
【发布时间】:2010-01-14 06:57:15
【问题描述】:

为什么scanf 函数中需要和号 (&)。以下 C 代码中的输出或错误类型(编译或运行时)是什么?

#include <stdio.h>

void main() {
    int a;
    printf("enter integer:");
    scanf("%d", a);
}

【问题讨论】:

  • 顺便说一句,main 返回 int,而不是 void

标签: c scanf


【解决方案1】:

C 中的&amp; 是一个返回操作数地址的运算符。这样想,如果你只是给scanf 变量a 而没有&amp;,它将按值传递给它,这意味着scanf 将无法为你设置它的值查看。通过引用传递它(使用&amp; 实际上传递一个指向a 的指针)允许scanf 设置它,以便调用函数也能看到变化。

关于具体的错误,你真的说不出来。行为未定义。有时,它可能会默默地继续运行,而您却不知道scanf 更改了程序中某处的某些值。有时它会导致程序立即崩溃,比如这种情况:

#include <stdio.h>
int main()
{
    int a;
    printf("enter integer: ");
    scanf("%d",a);
    printf("entered integer: %d\n", a);
    return 0;
}

编译显示如下:

$ gcc -o test test.c
test.c: In function ‘main’:
test.c:6: warning: format ‘%d’ expects type ‘int *’, but argument 2 has type ‘int’

并且执行显示分段错误:

$ ./test 
enter integer: 2
Segmentation fault

【讨论】:

    【解决方案2】:

    在 C 中,所有函数参数都是按值传递的;对函数形式参数的任何更改都不会反映在实际参数中。例如:

    void foo(int bar)
    {
      bar = bar + 1;
    }
    
    int main(void)
    {
      int x = 0;
      printf("x before foo = %d\n", x);
      foo(x);
      printf("x after foo = %d\n", x);
      return 0;
    }
    

    程序的输出将是

    x 之前的 foo = 0 foo = 0 之后的 x

    因为bar 接收到x (0) 的值,而不是对x 本身的引用。更改barx 没有影响。

    在 C 中,解决此问题的方法是将 指针 传递给变量:

    void foo(int *bar)
    {
      *bar = *bar + 1;
    }
    
    int main(void)
    {
      int x = 0;
      printf("x before foo = %d\n", x);
      foo(&x);
      printf("x after foo = %d\n", x);
      return 0;
    }
    

    现在程序的输出是

    x 之前的 foo = 0 foo = 1 之后的 x

    这一次,形参bar不是一个int,而是一个指向int的指针,它接收到x地址(由在对foo 的调用中表达&amp;x),而不是x 中包含的值。表达式*bar 的意思是“获取位置栏中的值指向”,所以*bar = *bar + 1 对应于x = x + 1

    由于scanf() 需要写入其参数,因此它希望将这些参数键入为指针。 "%d" 转换说明符期望对应的参数是一个指向 int (int *) 的指针,"%u" 转换说明符期望一个指向 unsigned int (unsigned *) 的指针,"%s" 期望一个指向char (char *), "%f" 需要一个指向 float (float *) 的指针,等等。在您的示例中,由于 a 的类型为 int,您需要使用表达式 &amp;a 来获得指针。

    请注意,如果a 已经是指针类型,则您无需在调用scanf() 时使用&amp; 运算符:

    int main(void)
    {
      int a, *pa;      // declare pa as a pointer to int
      ...
      pa = &a;         // assign address of a to pa
      scanf("%d", pa); // scanf() will write to a through pa
      ...
    }
    

    还要注意,将数组传递给函数时(例如使用“%s”转换说明符读取字符串时),您不需要使用&amp; 运算符;数组表达式将隐式转换为指针类型:

    int main(void)
    {
      char name[20];
      ...
      scanf("%19s", name); // name implicitly converted from "char [20]" to "char *"
      ...
    }
    

    【讨论】:

      【解决方案3】:

      如果您要问这样的问题,我建议现在只学习“它就是这样”。

      您将了解到您需要一个 & 符号,因为 scanf 需要一个或多个指针参数。如果 a 是 int 变量,则它不是指针。 &a ("a 的地址") 是一个指针,所以它可以与scanf 一起使用。

      【讨论】:

        【解决方案4】:

        这是因为在 C 中,函数参数是按值传递。为了让scanf() 函数修改 main() 函数中的 'a' 变量,'a' 的 地址 应赋予scanf(),因此使用和号的(地址)。

        【讨论】:

          【解决方案5】:

          因为scanf 需要一个指向该值将进入的变量(即引用)的指针。

          【讨论】:

            【解决方案6】:

            您并不总是需要将&amp;scanf 一起使用。您需要做的是传递指针。如果您是 C 新手,您应该花一些时间阅读 comp.lang.c 常见问题解答:

            http://c-faq.com/

            具体来说:

            【讨论】:

              【解决方案7】:

              scanf 中的 '&' 仅用于获取变量的地址。你可以通过使用指针来使用scanf而不使用'&':

              int myInt;
              int * pointer_to_int;
              pointer_to_int = &myInt;
              scanf("%d", pointer_to_int);
              

              一般来说,使用“&”通常比创建指针来避免使用“&”更容易。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多