用户是否可以在输入中键入null终止符,使用的是scanf,因此输入的长度为0?
char msg[1000];
scanf("%1000s",msg); // the user would type nothing: '' or '\0'
答案 0 :(得分:8)
在许多系统上,答案是“是”。
通常,魔术序列是 Control - @ 。
@的字符代码通常是64,比A(65)的字符代码少一个。 Control-A是字符代码1;少一个是字符代码0,又名'\0'
。
请注意,要获得零长度输入,您必须键入空字节作为第一个非空格字符,并且仍然需要按返回以输入输入。您的程序会发现很难可靠地识别空字节后输入的其他内容。
答案 1 :(得分:4)
某些系统允许终端用户通过按 Ctrl - @ 输入NUL字节。然后scanf()
将此字节存储到目标数组中,但很可能不会将此字节视为字分隔符,因此输入解析将一直持续到文件结尾或输入空行字符(如换行符)。
如果NUL字节存储在其他字符之后,则无法从目标数组中判断,也不能确切地知道在此NUL字节之后读取了多少其他字符。但是,如果scanf()
返回1
且msg
的长度为零,则唯一的可能是用户在空白字符可能为空的序列之后输入了NUL字节。
这也是fgets()
在传递大小超过1的目标数组时返回空字符串的唯一可能性。
如果从文件而不是终端读取输入,则文件始终可能包含NUL字节,并且应注意避免未定义的行为(如果发生)。例如,这是一个经典的错误:
char msg[1000];
if (fgets(msg, sizeof msg, stdin)) {
int len = strlen(msg);
if (msg[len - 1] == '\n') { // potential undefined behavior!
msg[--len] = '\0' // potential undefined behavior!
}
...
}
另请注意,您的代码存在缺陷:要存储到目标中的最大字符数应为999
,而不是1000
:
char msg[1000];
if (scanf("%999s",msg) == 1) {
/* word was read from the user */
if (*msg == '\0') {
printf("user entered a NUL byte\n");
}
}
答案 2 :(得分:2)
用户是否可以在输入中键入null终止符,使用的是scanf,因此输入的长度为0?
除了用户typing in a null character之外,stdin
还可以使用包含空字符的重定向输入。
foo < data.bin
详细信息:当扫描的第一个字符是空字符或'\0'
时,它会像任何其他字符一样被读取,并像任何其他非空白字符一样保存。因此输入的长度仍然大于0,但strlen(msg)
报告的值被嵌入的空字符欺骗并返回零。
fgets()
与scanf()
存在同样的问题:strlen(msg)
总是 报告读取的字符数。
非标准getline()
确实会返回读取的字符数,并且远离此。
@Stargateur提到使用"%n"
存储msg
中保存的字符数。也许就像
char msg[1000 + 1];
int start, end;
if (1 == scanf(" %n%1000s%n", &start, msg, &end)) {
printf("%d characters read\n", end - start);
}
IAC,我们正在努力应对scanf()
和家人的角落弱点。最好的读取输入解决方案取决于OP未提及的其他因素。
答案 3 :(得分:0)
是的,可能因为'\0'
是非白色空间。 scanf()
会认为这是字符串的结尾。所以%s
可以匹配一个空字符串。
您可以使用m
说明符分配相应的缓冲区来保存输入。请注意,这是POSIX 200112L标准。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char *str;
int n;
if (scanf("%ms%n", &str, &n) == 1) {
printf("I read %d character(s).\n", n);
if (strlen(str) != 0) {
printf("str = %s\n", str);
}
else {
printf("str is empty");
}
free(str);
}
else {
printf("The user enter nothing");
}
}