在我的 'writing a file' 程序中找不到错误
Can't find the bug in my 'writing a file' program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char file_name[100];
char insert[100];
printf("Enter the file name:");
scanf("%s", file_name);
FILE *f = fopen((strcat(file_name, ".txt")), "a");
printf("Insert:");
scanf ("%[^\n]%*s", insert);
fprintf(f, "%s", insert);
}
上述代码应该write/insert 数据到文件,但是,程序在打印'Insert:' 后立即终止。我在这里似乎找不到问题。
问题出在你的第一个 scanf
上。马车 return 没有被处理,这意味着下一个 scanf
在被调用后立即处理它,因为它仍在缓冲区中。
也许试试,scanf("%s\n", filename);
scanf
:
scanf("%s", file_name);
不会消耗您输入文件名后按的换行符。它保留在标准输入流中(stdin
)。 scanf
:
scanf ("%[^\n]%*s", insert);
扫描所有内容直到一个换行符,然后扫描并丢弃一个字符串。如果下一个字符是 \n
,%[^\n]
将失败。所以,scanf
,在你的例子中失败了,returns 因为下一个字符是 \n
。 insert
仍未初始化并包含垃圾。
fprintf(f, "%s", insert);
将垃圾写入f
。
如何解决这个问题?解决问题的两种方法:
- 在第一个
scanf
之后使用 getchar();
来去除第一个 scanf
留下的换行符。
使用
scanf (" %[^\n]%*s", insert);
而不是
scanf ("%[^\n]%*s", insert);
%[^\n]
之前的space扫描并丢弃所有whitespace characters(如\n
、space等),如果有的话,直到第一个非白色 space 字符,如下面 C11 标准的引用所示:
7.21.6.2 The fscanf function
[...]
- A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails
我更喜欢第二种解决方案,因为它可以处理 任何 个白色space 字符。
这两种解决方案都有效,但是您会遇到另一个问题。在您为第二个 scanf
提供数据后,您的程序不会停止扫描!解决这个问题很容易。只需从第二个 scanf
. 中删除 %*s
想知道为什么吗?引用C11标准,
7.21.6.2 The fscanf function
[...]
- The conversion specifiers and their meanings are:
[...]
s Matches a sequence of non-white-space characters. 286
[...]
因此,%s
将跳过前导白色space 字符,并在遇到白色space 字符时停止扫描,或者如果存在长度字段,则会停止扫描,直到指定的长度或 直到白色space 字符,以先出现者为准。粗体部分解释了它。
为了提高安全性,限制 scanf
读取 insert
和 file_name
的字符数,这样就可以避免 buffer overflows。此外,检查 scanf
和 fopen
的 return 值以查看它们是否成功。 scanf
s,在你的情况下,returns 1 如果成功。如果不是 1,则发生错误。 fopen
、returns NULL
失败。如果不是NULL
,fopen
就成功了。
最终计划:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char file_name[100];
char insert[100];
printf("Enter the file name:");
if(scanf("%94s", file_name) != 1) //Scans a maximum of 94 chars,+1 for [=15=] at the end,+4 for ".txt"
{
printf("scanf failed\n");
exit(-1); //Exit the program with a negative return value
}
strcat(file_name, ".txt"); //Improves readability,do one thing in one line
FILE *f = fopen(filename, "a");
if(f == NULL) //if fopen failed to open the filename,
{
printf("fopen failed\n");
exit(-1);
}
printf("Insert:");
if(scanf (" %99[^\n]", insert) != 1) // Note the space before %[^\n],99 scans a maximum of 99 chars,+1 for the [=15=] at the end
{
printf("scanf failed\n");
fclose(f); //Free resources before exiting
exit(-1);
}
fprintf(f, "%s", insert);
fclose(f); //Close the file after use
}
如果要丢弃第二个 scanf
留下的换行符,请使用
scanf (" %99[^\n]%*c", insert)
而不是
scanf (" %99[^\n]", insert)
虽然在这个程序中没有什么区别。
如果您想知道为什么我要引用“7.21.6.2 fscanf 函数”一章的话,那是因为 fscanf
与 scanf
完全相同它的第一个参数是 stdin
。再次引用 C11 标准,
7.21.6.4 The scanf function
[...]
- The
scanf
function is equivalent to fscanf
with the argument stdin
interposed before the arguments to scanf
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char file_name[100];
char insert[100];
printf("Enter the file name:");
scanf("%s", file_name);
FILE *f = fopen((strcat(file_name, ".txt")), "a");
printf("Insert:");
scanf ("%[^\n]%*s", insert);
fprintf(f, "%s", insert);
}
上述代码应该write/insert 数据到文件,但是,程序在打印'Insert:' 后立即终止。我在这里似乎找不到问题。
问题出在你的第一个 scanf
上。马车 return 没有被处理,这意味着下一个 scanf
在被调用后立即处理它,因为它仍在缓冲区中。
也许试试,scanf("%s\n", filename);
scanf
:
scanf("%s", file_name);
不会消耗您输入文件名后按的换行符。它保留在标准输入流中(stdin
)。 scanf
:
scanf ("%[^\n]%*s", insert);
扫描所有内容直到一个换行符,然后扫描并丢弃一个字符串。如果下一个字符是 \n
,%[^\n]
将失败。所以,scanf
,在你的例子中失败了,returns 因为下一个字符是 \n
。 insert
仍未初始化并包含垃圾。
fprintf(f, "%s", insert);
将垃圾写入f
。
如何解决这个问题?解决问题的两种方法:
- 在第一个
scanf
之后使用getchar();
来去除第一个scanf
留下的换行符。 使用
scanf (" %[^\n]%*s", insert);
而不是
scanf ("%[^\n]%*s", insert);
%[^\n]
之前的space扫描并丢弃所有whitespace characters(如\n
、space等),如果有的话,直到第一个非白色 space 字符,如下面 C11 标准的引用所示:7.21.6.2 The fscanf function
[...]
- A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails
我更喜欢第二种解决方案,因为它可以处理 任何 个白色space 字符。
这两种解决方案都有效,但是您会遇到另一个问题。在您为第二个
scanf
提供数据后,您的程序不会停止扫描!解决这个问题很容易。只需从第二个 scanf
. 中删除 %*s
想知道为什么吗?引用C11标准,
7.21.6.2 The fscanf function
[...]
- The conversion specifiers and their meanings are:
[...]
s Matches a sequence of non-white-space characters. 286
[...]
因此,%s
将跳过前导白色space 字符,并在遇到白色space 字符时停止扫描,或者如果存在长度字段,则会停止扫描,直到指定的长度或 直到白色space 字符,以先出现者为准。粗体部分解释了它。
为了提高安全性,限制
scanf
读取 insert
和 file_name
的字符数,这样就可以避免 buffer overflows。此外,检查 scanf
和 fopen
的 return 值以查看它们是否成功。 scanf
s,在你的情况下,returns 1 如果成功。如果不是 1,则发生错误。 fopen
、returns NULL
失败。如果不是NULL
,fopen
就成功了。
最终计划:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char file_name[100];
char insert[100];
printf("Enter the file name:");
if(scanf("%94s", file_name) != 1) //Scans a maximum of 94 chars,+1 for [=15=] at the end,+4 for ".txt"
{
printf("scanf failed\n");
exit(-1); //Exit the program with a negative return value
}
strcat(file_name, ".txt"); //Improves readability,do one thing in one line
FILE *f = fopen(filename, "a");
if(f == NULL) //if fopen failed to open the filename,
{
printf("fopen failed\n");
exit(-1);
}
printf("Insert:");
if(scanf (" %99[^\n]", insert) != 1) // Note the space before %[^\n],99 scans a maximum of 99 chars,+1 for the [=15=] at the end
{
printf("scanf failed\n");
fclose(f); //Free resources before exiting
exit(-1);
}
fprintf(f, "%s", insert);
fclose(f); //Close the file after use
}
如果要丢弃第二个
scanf
留下的换行符,请使用
scanf (" %99[^\n]%*c", insert)
而不是
scanf (" %99[^\n]", insert)
虽然在这个程序中没有什么区别。
如果您想知道为什么我要引用“7.21.6.2 fscanf 函数”一章的话,那是因为
fscanf
与 scanf
完全相同它的第一个参数是 stdin
。再次引用 C11 标准,
7.21.6.4 The scanf function
[...]
- The
scanf
function is equivalent tofscanf
with the argumentstdin
interposed before the arguments toscanf
.