从文件

时间:2016-05-06 23:18:31

标签: c

我在查明如何使用循环从具有数字的文件中读取名称时遇到了问题。例如

科比·布莱恩特81 62 60

我知道如何将每个字符串和数字单独扫描到一个变量中,但我很难理解如何更简单。

while ((chh = fgetc(input)) != EOF)
{
    printf("%c", chh);
}

这读取每行直到EOF,但我不知道如何让它停在神户bryant。我可以采用的一种方法是在循环中创建一个c字符串,使其停止一些方式并将其设置为等于变量。

旁注:如果科比布莱恩特身上还有2个其他球员的名字怎么样,怎么会接近?

谢谢!

1 个答案:

答案 0 :(得分:1)

在您担心阅读包含姓名的多行之前,请先正确阅读一行。使用面向字符的输入时,您有两种填充阵列的基本方法。 (1)使用数组索引并在读取每个有效字符时,在当前索引处添加到数组中;或者(2)使用指向数组的指针,并在每个有效字符添加到数组时递增指针。

在读取/存储每个字符时,至少有两个条件可以验证:(1)您没有尝试在数组末尾之外写入(为 nul-terminatedating 字符留出空间,(2)您终止了EOF上的阅读。

其余的只是冷逻辑(1)何时停止向数组添加字符和(2)应放置 nul-terminatedating 字符的位置。通过这样的学习练习,最简单的方法是拿出一支铅笔和一张纸,写下一个示例线,然后逐步浏览每个角色,随时编写条件。我不是在开玩笑,在纸上写出类似下面的内容并按照逻辑进行操作:

|K|o|b|e| |B|r|y|a|n|t| |8|1| |6|2| |6|0|\n|

当你阅读每个角色时,确定需要什么逻辑来确定是否存储角色,是否继续阅读,或者是否读取/丢弃该行中的所有剩余字符(从遇到第一个无效时开始)字符)。您还必须确定在阅读多行时如何处理'\n'

使用数组索引的示例是:

enum { MAXL = 64 }; /* constant for max name length */
...
    char name[MAXL] = ""; /* char array to hold name   */
    int c = 0, idx = 0;   /* var for char & array index */

    while (idx + 2 < MAXL &&  /* for each char in line */
           ((c = fgetc (fp)) != '\n' && c != EOF))
    {   /* if valid char */
        if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
            || c == '.' || c == ' ') {
            name[idx++] = c; /* write char to name, advance */
        }
        else { /* if not valid char - read to '\n' or EOF */
            while ((c = fgetc (fp)) != '\n' && c != EOF) {}
            break;
        }
    }
    if (idx) { /* if name contains chars - check last char */
        if (name[idx-1] == '.' || name[idx-1] == ' ')
            name[--idx] = 0;  /* if not letter, overwrite prior */
        else 
            name[idx] = 0;    /* nul-terminate at current idx  */
        printf (" name: '%s'\n", name);
    }

使用指针和结束指针的相同逻辑体是:

    char name[MAXL] = ""; /* char array to hold name   */
    char *p, *ep;         /* current pointer & end pointer */
    int c = 0;            /* var for current character */
    p = ep = name;        /* initialize both to name   */

    while (p + 2 < name + MAXL &&  /* for each char in line */
           ((c = fgetc (fp)) != '\n' && c != EOF))
    {   /* if valid char */
        if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
            || c == '.' || c == ' ') {
            ep = p;     /* set end ptr to current positon */
            *p++ = c;   /* write char to current, advance */
        }
        else { /* if not valid char - read to '\n' or EOF */
            while ((c = fgetc (fp)) != '\n' && c != EOF) {}
            break;
        }
    }
    if (p > name) { /* if name contains chars */
        if (*ep == '.' || *ep == ' ')
            *ep = 0;    /* nul-terminate prior */
        else
            *p = 0;     /* nul-terminate current */
        printf (" name: %s\n", name);
    }

要读取多个名称,您只需要在连续循环中包装用于读取每一行的代码,并检查最后是否c == EOF。 e.g。

for (;;) {  /* loop continually over each line in file */
...
    if (c == EOF)   /* if EOF, break */
        break;
}

将所有部分放在一起的简短示例(使用指针而不是索引)可能类似于:

#include <stdio.h>

enum { MAXL = 64 }; /* constant for max name length */

int main (int argc, char **argv) {

    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    for (;;) {  /* loop continually over each line in file */
        char name[MAXL] = ""; /* char array to hold name   */
        char *p, *ep;         /* current pointer & end pointer */
        int c = 0;            /* var for current character */
        p = ep = name;        /* initialize both to name   */

        while (p + 2 < name + MAXL &&  /* for each char in line */
            ((c = fgetc (fp)) != '\n' && c != EOF))
        {   /* if valid char */
            if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
                || c == '.' || c == ' ') {
                ep = p;     /* set end ptr to current positon */
                *p++ = c;   /* write char to current, advance */
            }
            else { /* if not valid char - read to '\n' or EOF */
                while ((c = fgetc (fp)) != '\n' && c != EOF) {}
                break;
            }
        }
        if (p > name) { /* if name contains chars */
            if (*ep == '.' || *ep == ' ')
                *ep = 0;    /* nul-terminate prior */
            else
                *p = 0;     /* nul-terminate current */
            printf (" name: %s\n", name);
        }
        if (c == EOF)   /* if EOF, break */
            break;
    }

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

示例输入

$ cat dat/namesnums.txt
Kobe Bryant 81 62 60
John Doe 21 34
Alfred C. Jones 882

示例使用/输出

$ ./bin/fgetcname <dat/namesnums.txt
 name: Kobe Bryant
 name: John Doe
 name: Alfred C. Jones

注意:代码还说明了名称后面没有数字的行)

查看示例。真的没有捷径。使用面向字符的输入时,您必须考虑到每个预期的字符。 (为了使您的代码更加健壮,您应该考虑每个未预料到的角色,但这将留待另一天)。如果您有疑问,请告诉我。