在C中检测txt文件的EOF

时间:2017-09-16 16:34:17

标签: c multidimensional-array io iteration scanf

我写了这段代码,它读取我文本的每个字符并将其放入我的char数组中。我的问题是没有检测到文件的结尾,因此每次最后一个char之前,fscanf()在文本结束后返回,直到我的数组被填满。我怎么能防止这种情况?我在C编程。

我的代码:

int main() {
    char array[50][50];
    char buff;
    FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r");

    for (int i = 0; i < 50; i++) {
        for (int k = 0; k < 50; k++) {
            fscanf(cola, "%c", &buff);
            array[i][k] = buff;
        }
    }

    fclose(cola);

    for (int i = 0; i < 50; i++) {
        for (int k = 0; k < 50; k++) {
            printf("%c", array[i][k]);
        }
    }
    return 0;
}

感谢您的帮助。

Here is a Screenshot of my Code

3 个答案:

答案 0 :(得分:2)

fscanf()返回成功转化的次数。您应该测试返回值并特别处理换行符:

#include <stdio.h>

int main(void) {
    char array[50][50];
    char buff;
    FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r");

    if (cola == NULL) {
        return 1;
    }
    for (int i = 0; i < 50; i++) {
        for (int k = 0; k < 50; k++) {
            if (fscanf(cola, "%c", &buff) != 1 || buff == '\n') {
                array[i][k] = '\0';
                break;
            }
            array[i][k] = buff;
        }
    }
    fclose(cola);

    for (int i = 0; i < 50; i++) {
        for (int k = 0; k < 50 && array[i][k] != '\0'; k++) {
            printf("%c", array[i][k]);
        }
        printf("\n");
    }
    return 0;
}

如果您使用getc()而不是fscanf()从文件中读取字节,则可以简化代码:

#include <stdio.h>

int main(void) {
    char array[50][51];
    int c, i, k, n;
    FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r");

    if (cola == NULL) {
        return 1;
    }
    for (n = 0; n < 50; n++) {
        for (k = 0; k < 50; k++) {
            if ((c = getc(cola)) == EOF || c == '\n') {
                break;
            }
            array[n][k] = c;
        }
        array[n][k] = '\0';
        if (c == EOF && k == 0)
            break;
    }
    fclose(cola);

    for (i = 0; i < n; i++) {
        puts(array[i]);
    }
    return 0;
}

答案 1 :(得分:1)

替换:

for (int i = 0; i < 50; i++) {
    for (int k = 0; k < 50; k++) {
        fscanf(cola, "%c", &buff);
        array[i][k] = buff;
    }
}

使用:

for (int i = 0; i < 50; i++) {
    for (int k = 0; k < 50; k++) {
        int c = getc(cola);
        if (c == EOF)
            break;
        array[i][k] = c;
    }
}

由于buff未使用,因此请勿定义它。请注意,getc()的返回类型为int,而不仅仅是char。始终检查I / O功能是否成功。在原始代码中,您甚至不检查I / O操作是否成功,这使得无法检测EOF。

请注意,此代码会做出许多可能或可能不合理的假设。例如,假设文件中的每一行由49个字符加一个换行符组成;您还假设您永远不需要将信息打印为“字符串”(您现有的代码不会;它会按字符打印,因此它是'安全的')。

您可能希望将输入描述为:

  • 最多读取50行,最多49个字符,每行添加换行符,将结果存储在变量array中,每行都是以空字符结尾的字符串。

这对常见问题(短线,长线,线不够)更具弹性。代码可能是:

enum { LINE_LEN = 50, NUM_LINES = 50 };
char array[NUM_LINES][LINE_LEN];
int i;
for (i = 0; i < LINE_LEN; i++)
{
    int c;
    int k;
    for (k = 0; k < LINE_LEN; k++)
    {
        c = getc(cola);
        if (c == EOF || c == '\n')
            break;
        if (k == LINE_LEN - 1)
        {
            /* Too long - gobble excess */
            while ((c = getc(cola)) != EOF && c != '\n')
                ;
            break;
        }
        array[i][k] = c;
    }
    array[i][k] = '\0';
    if (c == EOF)
        break;
}
int num_lines = i;   // You have num_lines lines of data in your array

我在https://www.ascii-code.com/ascii-art/logos/coca-cola.php找到了一个版本的可口可乐™ASCII艺术图像,它看起来与您的图像相似,但还有许多其他来源和变体:

         __                              ___   __        .ama     ,
      ,d888a                          ,d88888888888ba.  ,88"I)   d
     a88']8i                         a88".8"8)   `"8888:88  " _a8'
   .d8P' PP                        .d8P'.8  d)      "8:88:baad8P'
  ,d8P' ,ama,   .aa,  .ama.g ,mmm  d8P' 8  .8'        88):888P'
 ,d88' d8[ "8..a8"88 ,8I"88[ I88' d88   ]IaI"        d8[         
 a88' dP "bm8mP8'(8'.8I  8[      d88'    `"         .88          
,88I ]8'  .d'.8     88' ,8' I[  ,88P ,ama    ,ama,  d8[  .ama.g
[88' I8, .d' ]8,  ,88B ,d8 aI   (88',88"8)  d8[ "8. 88 ,8I"88[
]88  `888P'  `8888" "88P"8m"    I88 88[ 8[ dP "bm8m88[.8I  8[
]88,          _,,aaaaaa,_       I88 8"  8 ]P'  .d' 88 88' ,8' I[
`888a,.  ,aadd88888888888bma.   )88,  ,]I I8, .d' )88a8B ,d8 aI
  "888888PP"'        `8""""""8   "888PP'  `888P'  `88P"88P"8m"

此文件的最长行是67个字符加上换行符的第一行;最短的是61个字符加上换行符。该文件总共只有13行和845个字符(LF行结尾)。因此,您的程序无法处理此特定数据文件。它会查找2,500个字符,但不会获得它们。

我的完整测试代码被装配为从标准输入读取,而不是固定文件名。

#include <stdio.h>

int main(void)
{
    FILE *cola = stdin;

    enum { LINE_LEN = 80, NUM_LINES = 50 };
    char array[NUM_LINES][LINE_LEN];
    int i;      // Need value of i after loop
    for (i = 0; i < NUM_LINES; i++)
    {
        int c;  // Need value of c after loop
        int k;
        for (k = 0; k < LINE_LEN; k++)
        {
            c = getc(cola);
            if (c == EOF || c == '\n')
                break;
            if (k == LINE_LEN - 1)
            {
                /* Too long - gobble excess */
                while ((c = getc(cola)) != EOF && c != '\n')
                    ;
                break;
            }
            array[i][k] = c;
        }
        array[i][k] = '\0';
        if (c == EOF)
            break;
    }
    int num_lines = i;   // You have num_lines lines of data in your array

    for (i = 0; i < num_lines; i++)
        puts(array[i]);

    return 0;
}

我在显示的数据文件上测试了它,最后一行是空行,并且在空白行后面有几行包含超过79个字符的行。它正确处理了所有这些特殊情况。请注意,处理用户输入很难;处理反向用户输入更难。代码不那么紧凑。您可以更改规则,然后更改代码以匹配。我不确定这是编写代码的最简单方法;然而,它确实有效。有一个函数来处理内部输入循环可能更好;外部循环可以测试该函数的返回值。这将减少特殊情况处理。

#include <assert.h>
#include <limits.h>
#include <stdio.h>

static int read_line(FILE *fp, size_t buflen, char *buffer)
{
    assert(buflen < INT_MAX);
    int c;      // Need value of c after loop
    size_t k;   // Need value of k after loop
    for (k = 0; k < buflen; k++)
    {
        if ((c = getc(fp)) == EOF || c == '\n')
            break;
        if (k == buflen - 1)
        {
            /* Too long - gobble excess */
            while ((c = getc(fp)) != EOF && c != '\n')
                ;
            break;
        }
        buffer[k] = c;
    }
    buffer[k] = '\0';
    return (k == 0 && c == EOF) ? EOF : (int)k;
}

int main(void)
{
    enum { LINE_LEN = 80, NUM_LINES = 50 };
    char array[NUM_LINES][LINE_LEN];
    int i;
    for (i = 0; i < NUM_LINES; i++)
    {
        if (read_line(stdin, LINE_LEN, array[i]) == EOF)
            break;
    }
    int num_lines = i;

    for (i = 0; i < num_lines; i++)
        puts(array[i]);

    return 0;
}

这将从与先前版本相同的输入产生相同的输出。

答案 2 :(得分:-1)

int main() {
//char array[50][50];
char buff;
int t;
FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r");

if (cola == NULL)
{
    printf("Cannot open file \n");
    exit(0);
}
while (1) {
    t = fgetc(cola);
    if (t == EOF)
        break;
    buff = t;
    printf("%c", buff);
}


fclose(cola);

return 0;
}