在scanf中没有`&`的情况下%s如何工作?

时间:2017-07-20 12:56:05

标签: c string pointers

我对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但我想要粗体问题的答案。

3 个答案:

答案 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()返回成功分配的数量,应使用健壮的代码检查此值。此外,请注意,在%sscanf()一起使用时,应始终指定最大宽度,以避免缓冲区溢出。这里使用%99s,在数组的末尾为空终止符(\0)留出空间。