klu*_*utt 1 c printf scanf language-lawyer
我偶然发现了这个代码的问题
int arr[10];
scanf("%s", arr);
printf("%s", arr);
Run Code Online (Sandbox Code Playgroud)
我不知道其目的,但我完全知道这段代码有多么难闻。但我的问题是这是否合法,以及我是否可以期望它重新打印我输入的字符串?(前提是输入字符串不要太长而导致缓冲区溢出)
我还想知道是否有任何例子表明这确实有用。
来自关于 fprintf 的 C 标准https://port70.net/%7Ensz/c/c11/n1570.html#7.21.6.1p8
如果不存在 l 长度修饰符,则参数应为指向字符类型数组的初始元素的指针。
和 fscanf https://port70.net/%7Ensz/c/c11/n1570.html#7.21.6.2p12
如果不存在 l 长度修饰符,则相应的参数应是指向足以接受序列的字符数组的初始元素的指针和一个终止空字符,该字符将自动添加。
在这种情况下,它不是一个字符数组。但我似乎记得有一些关于与 char 指针之间的隐式转换的特殊规则,但我也记得这些规则不适用于可变参数函数。
对于语言律师我会说这是非法的:
来自 C11:7.21.6。
s如果不l存在长度修饰符,则参数应为指向字符类型数组的初始元素的指针。280)
和
9 如果转换规范无效,则行为未定义。282)如果任何参数不是相应转换规范的正确类型,则行为未定义。
对于任何实际用途,我想说,只要您输入的字符数不超过数组的字符数,我就无法想到可能会失败的情况。
问题延长后更新:
但我似乎记得有一些关于与 char 指针之间的隐式转换的特殊规则,但我也记得这些规则不适用于可变参数函数。
仅当目标类型已知时,才会发生正确的隐式转换。对于可变参数函数,不会对指针进行此类转换。
而且,在需要进行隐式转换的情况下,只有其中之一是void *,而不是在int *和之间时,才有可能进行转换char *。