编程非常新。我正在尝试创建一个txt文件,要求用户输入文件名,然后输入该文件的文本。起初,我得到了一个关于null的错误,所以我放了一个if语句,代码似乎无法打开具有该名称的文件。试图做一些研究,最终做出了一些改变,但仍然导致了同样的错误。
include <stdio.h>;
include <stdlib.h>;
int main()
{
char *fileName[100];
char inputText[100];
printf("What is the .txt file name? n");
scanf_s("%123s", &fileName);
strcat(fileName, ".txt");
FILE *textFile;
textFile = fopen_s(&textFile, fileName, "w");
if (textFile != 0)
{
printf("Cannot get file");
return -1;
}
printf("What should be written in the text file? n");
scanf_s("%123s", &inputText);
fprintf(textFile, "%s", inputText);
fclose(textFile);
return 0;
}
在学习C时,你能做的最重要的事情就是放慢速度有很多东西要学,你必须一步一个脚印。猜测、编译、查看是否有任何变化、更改其他内容和(重复)都没有用查一下
也就是说,您对stdin
/stdout
的基本输入/输出以及为写入而打开的文件感兴趣。目前尚不清楚您是使用scanf_s
还是使用非_s
版本的窗口,因为它们在下面是混合和匹配的。无论如何,主要的区别将是所需的参数。
在C中,声明数组以容纳文件名,并声明输入文本以容纳100
字符。使用字符串时,每个字符串都需要在末尾有一个nul终止字符(' '
…或仅0
,数字相同)。这意味着您可以在filename
或inputtext
中存储最多个99
字符+1
nul终止字符(附带说明:C通常避免使用大小写混合的变量名,而使用所有小写,但这取决于您)
为了防止写入超过filename
或inputtext
的末尾,您需要确保限制尝试存储的字符数。您可以使用格式说明符的字段宽度选项来执行此操作。例如
scanf ("%99s", inputtext);
或适用于windows_s
版本:
scanf_s ("%99s", inputtext, 100u);
但是,使用"%99s"
的格式说明符不允许输入包含空白,因为%s
格式说明符将读取到第一个空格或换行。其次,在按下[Enter]生成的用户输入结束时,它不会读取(或无论如何都不会处理)'n'
。如果您的下一个输入是字符输入,这将导致问题,因为scanf
将愉快地接受'n'
作为下一个要读取的字符。现在%s
将跳过前导空白('n'
是空白)应该不会出现问题,但这是在形成像scanf
格式字符串这样简单的东西时必须经过的思考过程。
养成每次计算输入流中所有字符的习惯。这样你就不会因为一些无法解释的错误而措手不及。
为了允许输入包含空白,可以为scanf
使用字符类格式说明符。例如,您可以使用"%99[^n]"
作为格式字符串。然而,字符类不会自动忽略前导空格,但您可以通过在%
开始格式说明符(例如" %99[^n]"
)之前留下space
来提供这种灵活性。这很重要。(这也是为什么fgets
或POSIXgetline
通常比scanf
更适合处理用户输入的原因
现在,您如何处理留在输入缓冲区中的'n'
(例如这里的stdin
)?除了保留space
之外,还可以在格式字符串中使用赋值抑制运算符。" %99[^n]%*c"
%*c
是读取字符%c
的格式说明符,但通过包含'*'
(赋值抑制运算符),您可以告诉scanf
读取并丢弃该字符。
在接受用户输入时,仅仅提供正确的格式说明符是不够的。您必须验证您实际收到了您期望的输入。对于任何输入例程,这至少意味着检查scanf
(或fgets
或getline
等)的返回。对于scanf
,返回是">匹配计数",这是根据格式字符串执行的成功转换数。例如CCD_ 43(或CCD_ 44)构成对单个转换的请求。(与赋值抑制运算符相关的任何转换都不包括在匹配计数中)因此,您的预期返回是格式字符串中的转换次数。综合起来,您可以使用处理您的inputtext
printf ("What should be written in the text file? "); /* prompt */
/* validate user input -- limit to 99 chars (+1 for nul char) */
if (scanf (" %99[^n]%*c", inputtext) != 1) {
fprintf (stderr, "error: invalid input (inputtext).n");
return 1;
}
同样的事情对filename
也适用吗?答案:不为什么?您计划在用户输入后将".txt"
附加到filename
,对吗?".txt"
中有多少个字符?答:4
(组合字符串只有1
nul终止字符)。那么,您必须将filename
限制为什么呢?" %95[^n]%*c"
要进行文件I/O,您有几种选择。到目前为止,fstream缓冲I/O函数是最常见的基本文本I/O函数。为了读取或写入文件,必须首先打开FILE
流。您可以通过声明FILE *pointer
,然后调用fopen
,然后检查返回值(pointer
的值)来验证文件是否已成功打开。相同的规则、格式说明符等适用于读取/写入文件(在磁盘上),就像它们适用于写入stdin
或stdout
一样,因为从C的角度来看,所有这些都只是文件。
考虑到这一点,你可以做类似于以下的事情:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXC = 100 };
int main (void) {
/* declare and initialize variables */
char filename[MAXC] = "", inputtext[MAXC] = "";
FILE *fp = NULL;
printf ("What is the .txt file name? "); /* prompt */
/* validate user input -- limit to 95 chars */
if (scanf (" %95[^n]%*c", filename) != 1) {
fprintf (stderr, "error: invalid input (filename).n");
return 1;
}
strcat (filename, ".txt"); /* +4 chars = 99 chars */
/* open file/validate file open for reading */
if (!(fp = fopen (filename, "w"))) {
fprintf (stderr, "error: file open failed '%s'.n", filename);
return 1;
}
printf ("What should be written in the text file? "); /* prompt */
/* validate user input -- limit to 99 chars (+1 for nul char) */
if (scanf (" %99[^n]%*c", inputtext) != 1) {
fprintf (stderr, "error: invalid input (inputtext).n");
return 1;
}
/* output status to stdout & inputtext to fp */
printf ("nwriting to '%s'n%sn", filename, inputtext);
fprintf (fp, "%sn", inputtext);
if (fclose (fp)) /* close file - validate stream close */
fprintf (stderr, "error: on file stream close.n");
return 0;
}
注意:在将写入文件后,检查fclose
的返回非常重要,以确保在写入过程中不会发生流错误。(对于关闭你从中阅读的流,不存在这种担忧)
示例使用/输出
$ ./bin/inputtext
What is the .txt file name? dat/inputtext
What should be written in the text file? A quick brown fox jumps over the lazy dog.
writing to 'dat/inputtext.txt'
A quick brown fox jumps over the lazy dog.
检查文件内容:
$ cat dat/inputtext.txt
A quick brown fox jumps over the lazy dog.
仔细查看代码,如果您对代码中的任何字符有任何问题,请告诉我。每个人在开始时都需要一些帮助,我能传达的最重要的事情是放慢速度,理解你编码的每一个字符,阅读并理解你的编译器警告(修复每一个警告),如果你不确定自己在做什么,就查一下。无论是Linux/Unix上的man function
,还是在MSDN上搜索窗口(例如scanf_s,…)。它们都会非常清楚地告诉你每个函数的每个参数都有什么类型和要求(还有很多例子)。
祝你的编码好运。
根据MSDN文档,fopen_s的参数形式为FILE**,而不是FILE*。它还返回一个错误代码,而不是文件句柄,该句柄不是函数的返回值。因此,您在这段代码中所做的是用一些不相关的整数覆盖您的文件句柄。如果您将错误代码存储在其他变量中,则应该可以解决该问题。
有关fopen_s的更多信息,请访问此处:https://msdn.microsoft.com/en-us/library/z5hh6ee9.aspx