当我从 C 中的文件中读取单词时出现 while 循环问题

Problem with while loop when I read words from a file in C

我正在尝试创建一个程序:

  1. 从文件中找到最大长度的单词
  2. 创建一个动态分配的二维数组
  3. 将文件中的单词存储到数组

https://gist.github.com/up1047388/363854cbe703a6f297ebb644c50d307f(整个程序)

文件:https://gist.github.com/up1047388/758574c484d916c4aeba106f293f185a

问题出在这个循环中(我使用printf作为找到问题的提示,但程序没有打印出问题内部的任何内容):

我正在尝试在循环中执行以下操作:

  1. 将包含文件每一行的字符传递到一个字符串中
  2. 当程序从文件中读取'\n'时存储单词 它存储在字符串中到数组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    FILE *fp;

    fp = fopen("C:\Users\Docs\lol.txt", "r");

    if (fp == NULL)
    {
        printf("the file is empty");
        exit(8);
    }

    int length[4];
    int ch1;
    int counter1 = 0, i = 0;

    while ((ch1 = getc(fp)) != EOF)
    {
        if (ch1 == '\n')
        {
            length[i] = counter1;
            i++;
            counter1 = 0;
            continue;
        }
        counter1++;
    }
    length[i] = counter1;

    fseek(fp, 0, SEEK_SET);

    int thelongest = length[0];

    for (i = 0; i < counter; i++)
    {
        if (length[i] >= thelongest)
        {
            thelongest = length[i];
        }
    }

    printf("\n the longest number is %d", thelongest);

    char **arr;

    **arr = (char **)malloc(sizeof(char *) * 4);

    int j = 0 i = 0;
    char str[thelongest];
    int ch2;
    while ((ch2 = getc(fp)) != EOF)
    { // printf("fvfdvdfvd");
        if (ch2 == '\n')
        {
            arr[j] = (char *)malloc(thelongest * sizeof(char));
            strcpy(arr[j], str);
            // printf("\n%c",str[i]);
            j++;
            continue;
        }
        str[i] = ch2;
        i++;
    }
    str[i] = ch2;
    strcpy(arr[j], str);

    return 0;
}

getc 的 return 值是 int 而不是 char。如果您使用 char(就像您使用的那样),那么 EOF 测试将永远无法运行,因此您将永远循环。

https://linux.die.net/man/3/getc

你需要

int ch1; <<<<====
int counter1 = 0, i = 0;

while ((ch1 = getc(fp)) != EOF)
{

另外 counter 未在任何地方声明

这一行错得很厉害

**arr = (char**)malloc(sizeof(char*) * counter);

你是说

arr = (char**)malloc(sizeof(char*) * counter);

此行缺少一个“,”

int j = 0 i = 0;

但是你之前已经声明了一个 i

在你的阅读循环中你永远不会 0 终止 'str'

正在阅读逻辑。

您似乎拿不定主意,counter1 是文件中的行数还是当前行的长度。在第一个读取循环中,它肯定是行长度。

但是你用它来遍历数组'length'。其大小为行数。实际上不是,它的大小为 4 - 这也是错误的。

如果你有 'numberOfLines' 和 'currentLineLength'

,你的生活会更轻松

对于初学者而不是这些声明

char ch1;

char ch2;

你应该使用

int ch1;

int ch2;

否则,如果类型 char 的行为与类型 unsigned char 相同,程序将无法正常运行。

在此声明中重新声明了变量 i。

int j = 0 i = 0;

之前在此声明中声明过

int counter1 = 0, i = 0;

所以编译器会报错。

还有一个错字

 for (i = 0; i < counter; i++)

未声明变量counter

如果文件的最后一行也以换行符 '\n' 结尾,那么

之后的语句
while( (ch1 = getc(fp))!= EOF )
{
    if (ch1 == '\n')
    {
    length[i]=counter1;
    i++;
    counter1=0;
    continue;
    }
    counter1++;
}
length[i]=counter1;

可以调用未定义的行为,因为访问数组之外​​的内存 length

这条语句中的左操作数

**arr = (char **)malloc(sizeof(char *) * counter);

具有类型 char。看来你的意思是

arr = (char **)malloc(sizeof(char *) * counter);

您需要将此数组的大小加 1 以保留 space 作为终止零字符 '[=32=]'

char str[thelongest + 1];

对于这个内存分配同样有效

arr[j] = (char *)malloc( ( thelongest + 1 ) * sizeof(char));

在这个 if 语句中

    if (ch2 == '\n')
    {
        arr[j] = (char *)malloc(thelongest * sizeof(char));
        strcpy(arr[j], str);
        // printf("\n%c",str[i]);
        j++;
        continue;
    }

您忘记附加终止零字符

str[i] = '[=23=]';

并将 i 设置为 0

在循环后再次出现这些语句

str[i] = ch2;
strcpy(arr[j], str);

如果文件中的最后一个单词以换行符结束 '\n',则可以调用未定义的行为 '\n'

此外,由于循环的条件,循环后 ch2 的值等于 -1(如果 char 类型的行为与 signed char 类型相同)

while ((ch2 = getc(fp)) != EOF)

所以这个作业

str[i] = ch2;

没有意义。

存在多个问题:

  • 如果 fopen 失败,则诊断消息不正确

  • 如果文件超过 4 行,你有未定义的行为

  • **arr = (char **)malloc(sizeof(char *) * 4);不正确!你应该写:

     arr = malloc(sizeof(*aff) * count);
    
  • char str[thelongest]; 的长度不足以存储长度为 thelongest 的字符串:空终止符需要一个额外的字节。

  • arr[j] = (char *)malloc(thelongest * sizeof(char)); 对于最长的行来说太短,对于其他行来说太大了。您应该使用 strdup() 或分配 i + 1 字节。

  • 您必须在 s[i] 处设置一个空字节才能使用 strcpy(arr[j], str);

  • 你在将单词存储到数组后将 i 重置为 0

  • str[i] = ch2; 最终循环后不正确:ch2 的值为 EOF,这不是一个字符。如果 i != 0.

    ,您应该设置 str[i] = '[=26=]' 并复制最后一行

这是修改后的版本:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    const char *filename = "C:\Users\Docs\lol.txt";
    FILE *fp = fopen(, "r");
    if (fp == NULL) {
        fprintf(stderr, "cannot open file %s: %s\n", filename, strerror(errno));
        exit(8);
    }

    // compute the number of lines and the maximum length
    int len = 0, longest = 0, count = 0;
    for (;;) {
        int c = getc(fp);
        if (c == EOF || c == '\n') {
            if (longest < len)
                longest = len;
            if (len > 0)
                count++;
            len = 0;
            if (c == EOF)
                break;
        } else {
            len++;
        }
    }

    printf("the longest line has %d bytes\n", longest);
    printf("%d non empty lines\n", count);

    // allocate the array with an extra entry for a NULL terminator
    char **arr = calloc(sizeof(**arr), count + 1);
    if (arr == NULL) {
        fprintf(stderr, "cannot allocate memory\n");
        fclose(fp);
        return 1;
    }

    // read the file contents
    char str[thelongest + 1];
    int i = 0, j = 0;
    rewind(fp);
    for (;;) {
        int c = getc(fp);
        if (c == '\n' || c == EOF) {
            // store a new word
            if (j != 0) {
                str[j] = '[=11=]';
                arr[i++] = strdup(str);
                j = 0;
            }
            if (c == EOF)
                break;
        } else {
            str[j++] = c;
        }
    }
    arr[i] = NULL;
    fclose(fp);

    // do something with the array
    [...]
    // free the array
    for (i = 0; i < count; i++)
        free(arr[i]);
    free(arr);
    return 0;
}