[英]How does %s work in c without `&` in scanf?
我对c中的%s
感到有些困惑。 我是编程新手,我正在学习c作为我的拳头PL
%s
如何在c中工作。 我发现使用%s
时不需要使用&
在scanf中。 为什么会这样呢? 为什么我使用时%s
给出细分错误
char *a="how are you";
printf("%s",*a);
我已经阅读了此链接:- 在C中正确使用%s-非常基本的水平,但是我想以粗体显示问题的答案。
您需要了解指针与char
变量之间的区别。
通常在scanf()
传递一个数组以匹配%s
说明符,然后在该位置使用指向数组第一个元素的指针。 对于%d
等其他说明符,您需要传递目标变量的地址,以允许scanf()
将结果存储在其中。
相反, printf()
不会在任何地方存储结果,因此它只需要变量的值即可, "%s"
说明符除外,该说明符需要终止非'\\0'
char
值数组的第一个元素的地址由'\\0'
。
在您的示例中,您传递了一个char
变量, printf()
将其作为地址并尝试对其进行解除引用,这将导致分段错误,因为它期望该变量是一个充满char
并终止的数组的地址带有' 0'
。
注意 : printf("%s", *a);
等效于printf("%s", a[0]);
因此,您可以清楚地看到传递给"%s"
的变量的类型为char
并且printf()
将使用(char *) 'h'
作为有效指针,执行*(char *) 'h'
操作,但大多数情况下可能不会。
声明“在使用%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);
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
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.