0

Isn't char* the only valid argument type for the %s format specifier used in the format specifier string of scanf()?If so,in my program why each one of these work exactly the same for both scanf()'s and printf()'s %s format specifier:

scanf("%s",&list[i]);
scanf("%s",list[i]);   
scanf("%s",&list[i][0]);

I'll appreciate if you clear the following confusions that arise from this premise:

1) Why is &name[i] working given it is of type char (*)[].Isn't &name[i][0] is the only valid argument as it is of type char* ?

2) Does name[i] decompose/translate into char* when we pass it as an argument for %s?Is it same as passing &name[i][0],which is the address of the first character of each name we enter?Is it why it works?

#include<stdio.h>
#include<string.h>

int main(void)
{

char list[3][10];
int i;
printf("Enter the three names \n");

for(i=0;i<=2;i++)
scanf("%s",&list[i]);  //Why this works?
//scanf("%s",list[i]);   //Does it decompose into char* type?
//scanf("%s",&list[i][0]);

for(i=0;i<=2;i++)
printf("%s\n",list+i);  //All of these printf() work as well
//printf("%s\n",list[i]);
//printf("%s\n",&list[i][0]);

}
4

3 回答 3

3

list[i]char[10], 并在作为参数传递时进行数组到指针的转换,所以在那个地方,它完全等价于&list[i][0].

&list[i]是一个并且作为or中的转换说明符char(*)[10]的无效参数,调用未定义的行为。%sprintfscanf

但是,由于 in 的第一个字节list[i]与 array 具有相同的地址list[i],通常它可以工作(1),因为printf并且scanf不知道它们的参数的类型并根据格式字符串解释它们。

(1)如果 a 的表示与 a 的表示不同它将失败。这并不常见,但有可能。char*char(*)[10]

于 2013-05-13T14:09:07.333 回答
2

变量参数列表——比如用于printf()scanf()——不能检查它们的变量参数的类型正确性。相反,这些函数依赖于说明正确类型的格式字符串,因为格式字符串定义了从堆栈中提取的参数的数量和类型。

<stdargs.h>(有关变量参数列表如何工作的详细信息,请查看文档。)

如果您声明"%s"为格式说明符,scanf()则将从堆栈中拉出 achar *并将标准输入写入该地址,无论您实际提供了什么作为参数,或者您是否提供了参数。

不用说,如果您的格式说明符在数量、类型和顺序上与您的参数不匹配,您可能很幸运并且实际上得到了结果,但您肯定会调用未定义的行为。

(这是在谈论一般的“为什么这不会给我一个错误”的问题,假设您没有现代编译器并启用了适当的警告,例如-WformatGCC。至于您特定情况下的类型转换,见丹尼尔的回答。)


PS:虽然我们正在这样做,但在任何情况下scanf()与 with 结合使用%s都是非常致命的,因为太长的输入会破坏您的程序。至少限制输入,例如通过%10s. 更好的是,通过读取输入fgets()并在内存中进行正确的输入解析,因为scanf()从格式错误的输入中正常恢复的能力受到严重限制。

于 2013-05-13T14:07:45.023 回答
0

只要参数提供了正确的地址,它就会“做正确的事”。但是,如果您使示例更复杂,或者将它们用作带有特定参数的函数的参数,那么您会发现其中一些是不“正确的”。

scanf使用格式时的参数%s应该是 char 数组的地址,有足够的空间来存储正在读取的字符串。在您的示例&list[i]中实际上并没有提供,它是指向 char 数组的指针的地址。恰好该地址与表示该数组的 char 数组的地址相同。&list[i][0]是一个指向单个字符的指针,但后面跟着另一个 9,所以它“有效”,但它在技术上又是不正确的。list[i]是唯一绝对正确的变体。但是所有替代方案都具有相同的地址,因此在这种情况下在技术上有效。

说到printf,我们再次想要一个 char 数组的地址。

在这种情况下,两者list+ilist[i]含义完全相同——当以这种方式使用数组时,list使其成为指向第一个元素的指针,并+n为您提供第 n 个元素,就像括号表示法一样。&list[i][0]给出单个字符的地址,但它与整个数组的第一个元素的地址相同,因此会产生相同的结果。

顺便说一句,我不认为gcc确实了解格式字符串并且可以检查并产生混淆格式字符串和相应参数的警告,会抱怨大多数这些形式。但并非所有形式在技术上都是正确的。

于 2013-05-13T14:20:07.507 回答