C语言中的scanf函数是如何工作的?

7
为什么在 scanf 函数中需要使用 ampersand (&)。以下 C 代码的输出或错误类型(编译时或运行时)是什么?
#include <stdio.h>

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

5
顺便提一下,main函数返回的是int类型而不是void类型。 - Alok Singhal
7个回答

13
在C语言中,&是一个运算符,它返回操作数的地址。可以这样想,如果您只是给scanf函数提供变量a而没有加上&,它将按值传递,这意味着scanf将无法设置其值以供您查看。通过引用传递(使用&实际上传递指向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

3
在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;
}

程序的输出结果将会是:
foo之前x的值为0
foo之后x的值为0
这是因为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;
}

现在程序的输出结果如下:
foo之前x = 0
foo之后x = 1
这一次,形式参数bar不再是一个int,而是一个指向int的指针,它接收到x地址(由调用foo时的表达式&x给出),而不是x中包含的值。表达式*bar表示“获取bar 指向的位置上的值”,因此*bar = *bar + 1对应于x = x + 1
由于scanf()需要写入其参数,因此它希望那些参数被定义为指针。"%d"转换说明符期望相应的参数为一个指向int的指针(int *),"%u"转换说明符期望一个指向无符号int的指针(unsigned *),"%s"期望一个指向char的指针(char *),"%f"期望一个指向float的指针(float *)等等。在你的例子中,由于a的类型是int,所以你需要使用表达式&a来获取一个指针。
请注意,如果a本身已经是一个指针类型,那么在调用scanf()时就不需要使用&运算符。
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”转换说明符读取字符串时),您不需要使用&运算符;数组表达式将隐式转换为指针类型:
int main(void)
{
  char name[20];
  ...
  scanf("%19s", name); // name implicitly converted from "char [20]" to "char *"
  ...
}

2
如果你问这样的问题,我建议你现在只是学习“它就是这样”。
你将会学到需要一个&符号,因为scanf需要一个或多个指针参数。如果a是一个int变量,它不是一个指针。&a(“a的地址”)是一个指针,所以它可以与scanf一起使用。

2
这是因为在C语言中,函数参数是按值传递的。为了使scanf()函数能够修改主函数中的'a'变量,必须将'a'的地址传递给scanf()函数,因此需要使用取地址符号(&)。

1

因为scanf需要一个指向变量(即引用)的指针,以便将值放入其中。


1

0
< p > 在 < code > scanf 中的“&”仅用于获取变量的地址。您可以通过使用指针来使用 < code > scanf 而不使用“&”:
int myInt;
int * pointer_to_int;
pointer_to_int = &myInt;
scanf("%d", pointer_to_int);

通常情况下,使用'&'比创建指针更容易,以避免使用'&'。

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