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

Sta*_*lis 0 c scanf

在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)

Dav*_*ica 5

在调用者中,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)

没有必要firstfirstindex.要检查字符串中的第一个字符,您需要做的就是取消引用指针.有了这个,它只是一个问题:

/* 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/falsemain()如果true然后写令牌到输出文件(我用"tokenfile. TXT"我的输出文件之前),那么你需要做的是开放的两个输入文件,并使用输出文件fopenmain()类似以下内容:

    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语言.如果一切都失败了......和鸭子说话.如何调试小程序,真的,它有所帮助:)