在c代码中.我有一个输入文件(称为in),格式为mad-lib,"我真的有<形容词>眼睛"(<>中没有空格)我想写一个bool函数,使用scanf来读取每个单词并返回true如果单词以'<'开头(也称为标记)我该怎么做呢?是的,我必须使用scanf.这是我现在所拥有的,但我不认为这是完全正确的,所以另一个问题是,我怎么知道我的功能是否正常工作.
/* istoken = returns true if word is a token */
bool istoken(char word[]) {
char first;
int firstindex;
while (1) {
scanf("%s", word);
first = word[MAX_LEN];
firstindex = (int)strlen(word);
if (first == '<') {
printf("The token is: %s\n", first);
return true; }
else {
return false; }
}
}
Run Code Online (Sandbox Code Playgroud)
在调用者中,word必须足够大,以容纳文本中最大的单词(+ 3个字符,2个<,>和nul-termanting字符.您应该将最大长度word作为参数传递给istoken,但是因为你正在使用scanf,你必须硬编码字段宽度修饰符以保护你的数组边界.(这是fgets建议的原因之一scanf- 但你必须使用scanf).不要word在调用者中使用缓冲区大小.如下所示应该足够了来电者(可能main()适合你):
#define MAXC 1024
...
char word[MAXC] = "";
Run Code Online (Sandbox Code Playgroud)
没有必要first或firstindex.要检查字符串中的第一个字符,您需要做的就是取消引用指针.有了这个,它只是一个问题:
/* istoken = returns true if word is a token */
bool istoken (char *word) {
while (scanf("%1023s", word) == 1) /* did a valid read take place? */
if (*word == '<') /* is 1st char '<' ? */
return true; /* return true */
return false; /* out of words, return false */
}
Run Code Online (Sandbox Code Playgroud)
(注意:简单地在返回时word通过指针参数返回令牌bool,似乎是你的代码的一个尴尬因素 - 但它是可行的.另外,如果令牌超过1024字符,包括nul-terminationing字符 - 你将word在函数返回时没有完整的标记)
仔细看看,如果您有其他问题,请告诉我.
一个简短的例子阅读 stdin
#include <stdio.h>
#include <stdbool.h>
#define MAXC 1024
/* istoken = returns true if word is a token */
bool istoken (char *word) {
while (scanf("%1023s", word) == 1) /* did a valid read take place? */
if (*word == '<') /* is 1st char '<' ? */
return true; /* return true */
return false; /* out of words, return false */
}
int main (void) {
char word[MAXC] = "";
if (istoken (word))
printf ("found token: '%s'\n", word);
else
fprintf (stderr, "error: no token found.\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
示例使用/输出
$ echo "my dog has <too> many fleas." | ./bin/scanftoken
found token: '<too>'
Run Code Online (Sandbox Code Playgroud)
最后一点:正如您在下面的评论中提出的那样,您可以从内部输出令牌intoken,例如
bool istoken(char word[]) {
while (scanf("%100s", word) == 1) {
if (word[0] == '<') {
printf("the token is: %s\n", word);
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
这通常是你想要避免的.在您的程序设计中,您希望(作为目标)将您的实现(您的程序执行,计算等)与输入/输出分开.这使得您的代码在被多个想要输出的函数调用时可用printf("the token is: %s\n", word);
虽然有点不常见,但是如果调用者然后使用该返回来确定如何处理istoken令牌,那么定位令牌并返回的函数true/false会更有意义word.如果你只是要在内部打印它,intoken如果找到一个令牌,然后对调用者的返回什么都不做,那么为什么要将它声明为bool无论如何 - 你也可以将它声明为void好像你没有使用返回.
就像我说的那样(目标).只要它是有效代码,您可以按照自己喜欢的方式对代码进行分解.使用的printf范围内istoken是完全有效的临时调试的目的也是如此.(事实上,这是你最有用的调试工具之一,只需printf在程序中的整个逻辑路径中添加临时语句,以找出代码在哪里工作,以及"火车掉落轨道"所以说话.
文件I/O示例
好的,我们终于解决'Z'了这个'XY'问题.因为,我现在明白了,你有一个文件你的文字(我用"myfile.txt"的输入),你想读你inputfile中的istoken并返回word,并true/false以main()如果true然后写令牌到输出文件(我用"tokenfile. TXT"我的输出文件之前),那么你需要做的是开放的两个输入文件,并使用输出文件fopen中main()类似以下内容:
FILE *ifp = fopen ("myfile.txt", "r"), /* infile pointer */
*ofp = fopen ("tokenfile.txt", "w"); /* outfile pointer */
Run Code Online (Sandbox Code Playgroud)
(我没那么有创意,我只用ifp了输入文件指针和ofp对输出文件指针)
无论何时打开文件,在尝试读取或写入文件之前,都必须验证文件实际上是否已打开以进行读取或写入(例如,fopen成功).例如:
if (ifp == NULL) { /* validate input open for reading */
perror ("fopen-myfile.txt");
return 1;
}
if (ofp == NULL) { /* validate output open for writing */
perror ("fopen-tokenfile.txt");
return 1;
}
Run Code Online (Sandbox Code Playgroud)
现在打开两个文件,您可以调用istoken和读取ifp.但是,这需要修改istoken以使用FILE *参数fscanf而不是使用scanf.例如:
/* istoken = returns true if word is a token */
bool istoken (FILE *ifp, char *word) {
while (fscanf(ifp, "%1023s", word) == 1) /* valid read take place? */
if (*word == '<') /* is 1st char '<' ? */
return true; /* return true */
return false; /* out of words */
}
Run Code Online (Sandbox Code Playgroud)
返回后istoken,您可以写入以stdout让用户知道是否找到了令牌,并且还写入了ofp输出文件中的存储令牌,例如.
if (istoken (ifp, word)) { /* call istoken passing open ifp */
printf ("found token: '%s'\n", word); /* output token */
fprintf (ofp, "%s\n", word); /* write token to outfile */
}
else
fprintf (stderr, "error: no token found.\n");
Run Code Online (Sandbox Code Playgroud)
最后,您必须fclose打开已打开的文件.但是你写的文件有一个转折点.你应该确认的fclose,以确保一个流的错误并没有出现在ofp可能没有被抓到,否则.例如
fclose (ifp); /* close infile pointer */
if (fclose(ofp) == EOF) /* validate "close-after-write" */
perror ("stream error on outfile stream close");
Run Code Online (Sandbox Code Playgroud)
完全放在一起,您可以执行以下操作:
#include <stdio.h>
#include <stdbool.h>
#define MAXC 1024
/* istoken = returns true if word is a token */
bool istoken (FILE *ifp, char *word) {
while (fscanf(ifp, "%1023s", word) == 1) /* valid read take place? */
if (*word == '<') /* is 1st char '<' ? */
return true; /* return true */
return false; /* out of words */
}
int main (void) {
char word[MAXC] = "";
FILE *ifp = fopen ("myfile.txt", "r"), /* infile pointer */
*ofp = fopen ("tokenfile.txt", "w"); /* outfile pointer */
if (ifp == NULL) { /* validate input open for reading */
perror ("fopen-myfile.txt");
return 1;
}
if (ofp == NULL) { /* validate output open for writing */
perror ("fopen-tokenfile.txt");
return 1;
}
if (istoken (ifp, word)) { /* call istoken passing open ifp */
printf ("found token: '%s'\n", word); /* output token */
fprintf (ofp, "%s\n", word); /* write token to outfile */
}
else
fprintf (stderr, "error: no token found.\n");
fclose (ifp); /* close infile pointer */
if (fclose(ofp) == EOF) /* validate "close-after-write" */
perror ("stream error on outfile stream close");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
示例输入文件
$ cat myfile.txt
my dog has <too> many fleas.
Run Code Online (Sandbox Code Playgroud)
示例使用/输出
$ ./bin/scanftoken
found token: '<too>'
$ cat tokenfile.txt
<too>
Run Code Online (Sandbox Code Playgroud)
我可以给你学习C的最好建议就是放慢速度.有很多东西需要学习,事实上已经有30年的时间了,我几乎没有触及表面(这一点,他们不断修改标准).一步一步吧.man page为你使用的每个函数循环,找出正确的参数是什么,最重要的是它返回什么,以及错误报告的形式是什么(例如它是否设置,errno以便你可以perror用来报告错误或者你需要使用fprintf (stderr, ....)?
始终启用编译器警告并阅读并理解警告,并且在没有警告的情况下编译之前不要接受代码.只需听一下编译器告诉你的内容,你就可以学到很多C语言.如果一切都失败了......和鸭子说话.如何调试小程序,真的,它有所帮助:)