我对c中的%s
感到困惑。我是编程新手,我正在学习c作为我的拳头P.L。
%s
如何在c中发挥作用。我发现在使用&
时您不需要在scanf中使用%s
。为什么会这样? 为什么%s
在我使用时会出现细分错误
char *a="how are you";
printf("%s",*a);
我已阅读此链接: - Using %s in C correctly - very basic level但我想要粗体问题的答案。
答案 0 :(得分:4)
您需要了解指针与char
变量之间的区别。
在scanf()
中,您通常传递一个数组以匹配%s
说明符,然后在其位置使用指向数组第一个元素的指针。对于像%d
这样的其他说明符,您需要传递目标变量的地址以允许scanf()
将结果存储在其中。
相反,printf()
不会将结果存储在任何地方,因此它只需要变量的值,除了"%s"
说明符,它需要地址到非数组{的第一个元素{ {1}} '\0'
个值以char
终止。
在您的示例中,您传递的是'\0'
变量,char
会将其作为地址并尝试取消引用它,这将导致分段错误,因为它期望变量是地址数组填充printf()
并以char
结尾。
注意:'
0'
相当于printf("%s", *a);
,因此您可以清楚地看到为printf("%s", a[0]);
传递的变量的类型为"%s"
}和char
将使用printf()
作为有效指针执行*(char *) 'h'
之类的操作,但很可能不是。
答案 1 :(得分:2)
声明“你在使用%s时不需要在scanf中使用&”可能会产生误导。
一个scanf
格式说明符,用于读入和存储值始终需要指向相应类型的对象的指针。这通常由一元&
- 运算符实现,它返回一个对象的地址。然而,像数组这样的类型会自动衰减到指向数组第一个元素的指针,这样下面的代码实际上会传递一个指针:
char text[100] = "";
scanf("%s", text); // array automatically decays to a pointer to the first element.
scanf("%s", &text[0]); // explicitly take the address of the first element
如果您没有数组但是指向char的指针,则代码更改如下:
char *text2 = malloc(100);
scanf("%s", text2); // text2 is a pointer, not an array
同样,您不需要&
,因为您已经传递了指针值。
所以声明“你在使用%s时不需要在scanf中使用&”是正确的,因为%s
总是需要一个指向字符序列的指针,并且你要么传递一个自动衰减到指针的数组或者直接传递指针。
从两个角度看你的代码是错误的:
char *a="how are you";
printf("%s",*a);
首先,*a
不是指针而是单个字符值(在您的情况下为'h'
),当转换为指针值时,它将类似于内存地址0x0000001A
。访问它会产生未定义的行为/ seg错误。
其次,它是printf
,而不是scanf
。如果你想要printf,请写:
char *a="how are you";
printf("%s",a);
如果你想要scanf,请写:
char a[100];;
scanf("%s",a);
答案 2 :(得分:2)
scanf()
函数要求指针将字符数组的第一个元素作为带有%s
指令的参数。由于数组标识符衰减为指向数组第一个元素的指针(在大多数表达式中,包括函数调用),因此只使用不带&
地址运算符的数组名称即可提供正确的指针。事实上,在这里使用&
运算符是错误的。
鉴于代码:
char array[100];
int ret_val = scanf("%99s", array);
此处标识符array
衰减到指向array[]
的第一个元素的指针,这是scanf()
所期望的。相反,如果:
int ret_val = scanf("%99s", &array);
这是不正确的,因为&array
是指向数组array[]
的指针。区别在于,array
衰减到指向一个字节的指针,而&array
是指向100个字节的指针(在这种情况下)。例如,当涉及指针算法时,这种差异很重要。
在你的第二个例子中:
char *a = "how are you";
printf("%s", *a);
这里,a
已经是指向数组第一个元素的指针(因为a
是指向char
的指针,而"how are you"
是一个字符串文字,表示为内存为char
的空终止数组,它衰减到指向表达式中此数组的第一个元素的指针。通过使用*a
而不是a
,值'h'
将作为printf()
的参数而不是预期的指针,从而导致未定义的行为。
另请注意,在我的第一个示例中,scanf()
的返回值存储在int
变量ret_val
中。 scanf()
返回成功分配的数量,应使用健壮的代码检查此值。此外,请注意,在%s
与scanf()
一起使用时,应始终指定最大宽度,以避免缓冲区溢出。这里使用%99s
,在数组的末尾为空终止符(\0
)留出空间。