在c代码中。我有一个输入文件(名为in),格式为mad-lib,“我真的<形容词>眼睛”(<>中没有空格)我想编写一个使用scanf的bool函数如果单词以'<'开头,则读取每个单词并返回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; }
}
}
答案 0 :(得分:5)
在来电者中,word
必须足够大,以容纳文字中最大的字词(+ 3个字符,2个<,>
和 nul-termanting 字符。您应该将word
的最大长度作为参数传递给istoken
,但由于您使用的是scanf
,因此您必须将字段宽度修改器硬编码为保护你的数组边界。(这是建议fgets
优于scanf
的原因之一 - 但你必须使用scanf
)。不要在{{1}的缓冲区大小上吝啬调用者中的以下内容在调用者中应该足够了(可能是word
):
main()
无需#define MAXC 1024
...
char word[MAXC] = "";
或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 */
}
时通过指针参数返回word
中的令牌,这似乎是您代码的一个尴尬因素 - 但它是此外,如果令牌超过bool
个字符,包括 nul-terminatedating 字符 - 您将在函数返回时1024
中没有完整的令牌。
仔细看看,如果您有其他问题,请告诉我。
阅读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;
}
最后注意:正如您在下面的评论中提出的那样,您可以在$ echo "my dog has <too> many fleas." | ./bin/scanftoken
found token: '<too>'
内输出令牌,例如
intoken
这通常是你想要避免的事情。在程序设计中,您希望(作为目标)将您的实现(您的程序执行,计算等)与输入/输出分开。这使得您的代码在被多个想要输出bool istoken(char word[]) {
while (scanf("%100s", word) == 1) {
if (word[0] == '<') {
printf("the token is: %s\n", word);
return true;
}
}
return false;
}
虽然有点不常见,但是如果调用者然后使用该返回来确定如何处理printf("the token is: %s\n", word);
中的令牌,那么找到令牌并返回istoken
的{{1}}函数会更有意义。 。如果您要在true/false
内打印它,如果找到一个令牌,然后对调用者的返回不做任何操作,那么为什么还要将其声明为word
- 您可能也只是如果您没有使用退货,请将其声明为intoken
。
就像我说的那样(一个目标)。只要它是有效代码,您可以按照自己喜欢的方式对代码进行分解。在bool
中使用void
对于临时调试目的也是完全有效的。 (事实上,这是您最有用的调试工具之一,只需在程序的逻辑路径中添加临时printf
语句,以找出您的代码在何处按预期工作以及&#34;训练落在何处这是赛道&#34;可以这么说。
文件I / O示例
好的,我们终于遇到istoken
问题printf
了。因为,正如我现在所理解的,您将文本放在一个文件中(我已使用'Z'
作为输入),并且您希望在'XY'
中读取输入文件并返回"myfile.txt"
和{{ 1}}到istoken
和word
然后将令牌写入输出文件(我使用&#34; tokenfile.txt&#34;之前输出文件),然后你需要做什么使用true/false
中的main()
打开您的输入文件和输出文件,类似于以下内容:
true
(我没有那么有创意,我只使用fopen
作为输入文件指针,main()
作为输出文件指针)
每当您打开文件之前尝试读取或写入文件时,您必须验证该文件实际上是打开以进行读取或写入(例如{ {1}}成功了)。例如:
FILE *ifp = fopen ("myfile.txt", "r"), /* infile pointer */
*ofp = fopen ("tokenfile.txt", "w"); /* outfile pointer */
现在打开这两个文件,您可以拨打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;
}
参数与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 */
}
最后,您必须istoken
您打开的文件。 但写的文件存在扭曲。您应验证 stdout
以确保ofp
上未发生可能未被捕获的流错误。 e.g。
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
示例输入文件
fclose
示例使用/输出
ofp
我可以给你学习C的最好建议就是减速。有很多东西需要学习,事实上已经有30年的时间了,我几乎没有触及表面(这一点,他们不断修改标准)。一步一步吧。为您使用的每个函数循环 fclose (ifp); /* close infile pointer */
if (fclose(ofp) == EOF) /* validate "close-after-write" */
perror ("stream error on outfile stream close");
,找出正确的参数是什么,最重要的是它返回的内容以及错误报告的形式(例如它是否设置#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;
}
以便您可以使用{ {1}}报告错误或您是否需要使用$ cat myfile.txt
my dog has <too> many fleas.
?
始终启用编译器警告并阅读并理解警告,在没有警告的情况下编译之前不接受代码。只需听一下编译器告诉你的内容,你就可以学到很多C语言。如果一切都失败了......和鸭子说话。 How to debug small programs,实际上,它有助于$ ./bin/scanftoken
found token: '<too>'
$ cat tokenfile.txt
<too>
答案 1 :(得分:0)
如果你介意使用一些强大的词法分析器,我建议你使用flex
来帮助你进行标记化。
正如您所看到的,Flex允许您编写令牌模式并生成一个C
解析器,它可以完成所有工作。
这是一个程序,它将多个空格和制表符压缩为一个空格,并丢弃在一行末尾找到的空格:
%%
[ \t]+ putchar( ' ' );
[ \t]+$ /* ignore this token */
您可以在http://alumni.cs.ucr.edu/~lgao/teaching/flex.html找到更多信息。