如何使用scanf读取文件中的每个单词。

时间:2018-03-18 04:39:10

标签: c scanf

在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; }
    }
}

2 个答案:

答案 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}}到istokenword然后将令牌写入输出文件(我使用&#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解析器,它可以完成所有工作。

FLEX

  

这是一个程序,它将多个空格和制表符压缩为一个空格,并丢弃在一行末尾找到的空格:

%%
[ \t]+        putchar( ' ' );
[ \t]+$       /* ignore this token */

您可以在http://alumni.cs.ucr.edu/~lgao/teaching/flex.html找到更多信息。