奇怪的行为scanf、strings和C
我对C中的一些代码有问题:奇怪的行为scanf、strings和C,c,string,scanf,C,String,Scanf,我对C中的一些代码有问题: char opt, name[10], path[25]; printf("Things\nMore things\n"); printf("Even more things\n"); printf("\nChar: "); scanf("\n%c",&opt); printf("\nTask name: "); scanf("%s",name); printf("Name: %s\n", name); printf("\nFolder name: "); s
char opt, name[10], path[25];
printf("Things\nMore things\n");
printf("Even more things\n");
printf("\nChar: ");
scanf("\n%c",&opt);
printf("\nTask name: ");
scanf("%s",name);
printf("Name: %s\n", name);
printf("\nFolder name: ");
scanf("%s",path);
printf("Name: %s\n", name);
printf("Path: %s\n", path);
这是在“干净”模式下制造麻烦的代码。问题是,当数据大小大于10或25时,它将混合“名称”和“路径”,而不是剪切字符串。在某些情况下,它甚至将部分“路径”放在“名称”中。这是一种未定义的行为,还是我遗漏了什么?它只是将名称重载到路径,因为它们彼此相邻地占用内存空间。当您尝试在
Name
中写入超过10个字符,在Path
中写入超过25个字符时,会导致缓冲区溢出
在这种特殊情况下,name
和path
在堆栈上分配,path
在name
之后。但由于堆栈是自上而下的,如果您在路径中写入更多内容,则可以将名称
写入空格
阅读维基百科如果您不想有任何问题,请将字符串的scanf
替换为:
fgets(name, 10, stdin);
其中第二个参数是数组的大小。这样,即使您尝试写入更多字符,它们也会被忽略。如果您想将用户输入限制为精确的字符数,请尝试
scanf("%24s",path);
它应该可以防止字符数组的缓冲区过载。使用scanf时,应该指定要读取的最大大小,以避免缓冲区溢出:
scanf("%10s", name);
scanf不知道变量的大小(尤其是变量字符串)。它只是将字节放入内存空间,您必须自己检查是否存在溢出
由于数据结构对齐,没有SEGFULT。您需要告诉scanf
您的输入字符串可以占用多少字节。您还需要告诉scanf
放弃直到行尾的所有输入。由于提示不会以换行结束,因此应该刷新输出
printf("\nChar: ");
fflush(stdout);
scanf("\n%c%*[^\n] ",&opt);
printf("\nTask name: ");
fflush(stdout);
scanf(" %9[^\n]%*[^\n] ", name);
printf("\nFolder name: ");
fflush(stdout);
scanf(" %24[^\n]%*[^\n] ", path);
是的,正如您所怀疑的,在数组末尾写入是未定义的行为。scanf没有自动“阵列满时停止读取”。当它不知道数组的大小时,它怎么能这样做呢?有一些方法可以将格式更改为例如%10s
,以解决此问题,但规则是令人讨厌的。阅读您友好的scanf手册页!PS:换行符应该在printf字符串的末尾,而不是开头;否则,标准输出流可能不会被刷新,您将等待提示。(或添加fflush(stdout))。这与使用(*)scanf系列中的函数时有关溢出的其他问题非常相似,例如。此解决方案有效,但在按enter键显示输入结束时会出现奇怪的情况,因此我将应用Pablo Lemurr发布的解决方案,这就足够了。谢谢谢谢你的解决方案,虽然不完美,但对我来说已经足够了!