为什么第一个打印字符串值,而第二个给出段错误?
案例一发生了什么:
staticArray 的类型是char [100],即100char 的数组。
&staticArray 的类型是 char (*)[100]。
scanf() 中的 %s 格式说明符期望参数是指向 char 数组的初始元素的指针,即 char * 类型。
您将char (*)[100] 类型传递给scanf(),因此编译器会对此语句发出警告。
&staticArray 为您提供指向 char (*)[100] 类型数组的指针,它在数值上与数组的基地址相同。
考虑这个例子:
#include <stdio.h>
int main(void)
{
char staticArray[100];
printf ("staticArray: %p\n", (void*)staticArray);
printf ("&staticArray : %p\n", (void*)&staticArray);
return 0;
}
输出:
## ./a.out
staticArray: 0x7ffee4044a70
&staticArray : 0x7ffee4044a70
staticArray 和&staticArray 都产生指向相同地址的指针1),但它们的类型不同。
这就是为什么当您将&staticArray 传递给scanf() 时,由于类型不匹配而在编译期间收到警告,但是当调用scanf() 时,它将该指针视为char * 并读取输入并将结果存储到给定位置。稍后打印时,它会打印字符串值。
案例二发生了什么:
dynamicArray 的类型是char *。
&dynamicArray 的类型是 char **。
因此,您将char ** 类型传递给scanf(),当使用%s 格式说明符时,它需要char *。因此编译器对此语句发出警告。
指针&dynamicArray 与dynamicArray 不同。
考虑这个例子:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* dynamicArray;
dynamicArray = malloc(sizeof(char)*100);
if (dynamicArray == NULL) {
exit(EXIT_FAILURE);
}
printf ("dynamicArray: %p\n", (void*)dynamicArray);
printf ("&dynamicArray : %p\n", (void*)&dynamicArray);
free(dynamicArray);
return 0;
}
输出:
## ./a.out
dynamicArray: 0x7fd615401690
&dynamicArray : 0x7ffee7ab7ad0
dynamicArray 和 &dynamicArray 都产生不同的指针。
当您将&dynamicArray 传递给scanf()(读取输入并将结果存储到给定位置)时,会导致未定义的行为2),因为您的程序最终访问无效内存。
当您使用格式说明符%s、printf() 将&dynamicArray 传递给printf() 时,它访问该地址以写入字符串并最终访问无效内存,导致未定义的行为2)。因此,您遇到了段错误。
1) 数组会自动转换为指向其第一个元素的指针,但此规则很少有例外(C11 标准#6.3.2.1p3):
- 数组是
sizeof运算符的操作数。
- 数组是
_Alignof运算符的操作数。
- 数组是
&的操作数。
- 数组是用于初始化数组的字符串字面量。
2) 一个undefined behavior 包含它可能执行不正确(崩溃或静默生成不正确的结果),或者它可能偶然地完全按照程序员的意图执行。