关于c中printf和scanf函数是否使用取地址符的疑问

路人甲的世界
  • 35

正在学习C语言,在学到字符数组这一段的时候被绕晕了:

#include <stdio.h>

int main() {
    char str[80];
    int i = 0;
    scanf("%s", str);
    printf("%s", str);
    return 0;
}

1、请问为什么这里的scanf和printf中有无取地址符均能运行?
2、为什么scanf方法在给其他类别对象赋值的时候一定需要加取地址符?

恳请各路大神解惑!谢谢!

回复
阅读 4.4k
5 个回答
✓ 已被采纳

OP需要先知道C语言的data types:

  • the type void
  • basic types

    • the type char
    • signed integer types

      • ...
    • unsigned integer types

      • ...
    • floating types
  • enumerated types
  • derived types

    • array types
    • pointer types
    • ...

很清晰的可以看见, 指针(pointer)和数组(array)两个都是derived type, 而且是两个不同的类型, 但是由于C语言的类型系统太弱了, 有很多隐式转化(implicitly cast). 此处str就是从array type decay 到了pointer type.

为什么scanf方法在给其他类别对象赋值的时候一定需要加取地址符?

因为scanf的parameter是pointer.

更宽泛的说, 所有数组在传参时都会 decay 到指针类型. c++则有了些许变动, 可以允许用引用来传递数组, 但是已经无法按值传递数组.

请问为什么这里的scanf和printf中有无取地址符均能运行?
&是取地址符(addressof)但表达式&arr取的不是地址而是指针, 不过其中蕴含了地址信息.

如果你用&str:

#include <stdio.h>
int main() {
    char str[80];
    int i = 0;
    scanf("%s", &str);
    printf("%s", str);
    return 0;
}
warning: format specifies type 'char ' but the argument has type 'char ()[80]' [-Wformat]

这个warning很明显了. 既然strdecay到指针, 就别在用&了. 只有在不能退化成指针的时候, 再用&, 比如int a; scanf("%d", &a);.

延伸阅读:

int main () {
    char str[80];
    printf("value=%p pointer=%p",str,&str);  
    return 0;
}
//输出: 
value=0x7ffd2e2f3fe0 pointer=0x7ffd2e2f3fe0

str本来就是个指针而已

scanf()函数格式是 scanf("<格式化字符串>",<地址表>);
是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息。
示例 输入一个整型值给变量a : scanf(“%d”,&a); //注意a前有&取地址符,因为语法格式要求此处是变量地址。
printf函数调用的一般形式为:printf(“格式控制字符串”, 输出表列)
示例 输入一个整型值给变量b : printf(“%d”,b);

问题是printf或者scanf的行为。
printf通常是不需要取地址符的,无论是打印基本变量,还是字符串、字符串数组。
scanf需要修改变量的值,对于基本变量要取地址符。但是如果输入的是字符串,只要缓冲区的指针就可以的,数组名本身可以当指针用。

scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息。可以读入任何固有类型的数据并自动。格式是 scanf("<格式化字符串>",<地址表>);
示例 输入一个整型值给变量a : scanf(“%d”,&a); //注意a前有&取地址符,因为语法格式要求此处是变量地址。

宣传栏