【问题标题】:Reading each line of file into array将文件的每一行读入数组
【发布时间】:2013-10-10 23:49:22
【问题描述】:

我正在读取一个文件,并希望将每一行放入一个数组中的字符串中。文件的长度是任意的,每行的长度是任意的(尽管假设它会少于 100 个字符)。

这就是我所拥有的,但它没有编译。本质上这是一个字符数组的数组,对吧?所以不应该是char** words = (**char)malloc(sizeof(*char));吗?

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

int main(){


 int BUFSIZE = 32767;//max number of lines to read
 char** words = (**char)malloc(sizeof(*char));//gives error: expected expression before 'char'
 FILE *fp = fopen("coll.txt", "r");
 if (fp == 0){
        fprintf(stderr, "Error opening file");
        exit(1);
 }

int i = 0;
words[i] = malloc(BUFSIZE);
while(fscanf(fp, "%100s", words[i]) == 1)//no line will be longer than 100
{
        i++;
        words[i] = realloc(words, sizeof(char*)*i);
 }

 int j;
 for(j = 0; j < i; j++)
    printf("%s\n", words);

 return 0;
}

注意:我已阅读“Reading from a file and storing in array”,但它没有回答我的问题。

【问题讨论】:

  • 它应该是 char*... 您正在尝试查找字符指针的大小...
  • 请注意,%100s 将 (a) 跳过前导空白并在非空白字符后的空白处停止读取,并且 (b) 将使大小为 100 的缓冲区溢出一个字节,这可能很重要。您必须在转换规范中指定比数组大小小一。

标签: c arrays string file-io


【解决方案1】:

您的程序存在一些问题。 realloc() 语句未正确使用。我也更喜欢 fgets() 来获得一条线。这是我的解决方案。这也使用 realloc() 来增加缓冲区行的分配,因此您不必提前知道行数,也不必两次读取文件(这样更快)。当您不知道必须提前分配多少内存时,这是一种常用的技术。

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

int main(void)

    {
    int lines_allocated = 128;
    int max_line_len = 100;

    /* Allocate lines of text */
    char **words = (char **)malloc(sizeof(char*)*lines_allocated);
    if (words==NULL)
        {
        fprintf(stderr,"Out of memory (1).\n");
        exit(1);
        }

    FILE *fp = fopen("coll.txt", "r");
    if (fp == NULL)
        {
        fprintf(stderr,"Error opening file.\n");
        exit(2);
        }

    int i;
    for (i=0;1;i++)
        {
        int j;

        /* Have we gone over our line allocation? */
        if (i >= lines_allocated)
            {
            int new_size;

            /* Double our allocation and re-allocate */
            new_size = lines_allocated*2;
            words = (char **)realloc(words,sizeof(char*)*new_size);
            if (words==NULL)
                {
                fprintf(stderr,"Out of memory.\n");
                exit(3);
                }
            lines_allocated = new_size;
            }
        /* Allocate space for the next line */
        words[i] = malloc(max_line_len);
        if (words[i]==NULL)
            {
            fprintf(stderr,"Out of memory (3).\n");
            exit(4);
            }
        if (fgets(words[i],max_line_len-1,fp)==NULL)
            break;

        /* Get rid of CR or LF at end of line */
        for (j=strlen(words[i])-1;j>=0 && (words[i][j]=='\n' || words[i][j]=='\r');j--)
            ;
        words[i][j+1]='\0';
        }
    /* Close file */
    fclose(fp);

    int j;
    for(j = 0; j < i; j++)
        printf("%s\n", words[j]);

    /* Good practice to free memory */
    for (;i>=0;i--)
        free(words[i]);
    free(words);
    return 0;
    }

【讨论】:

  • +1。我强烈建议将for 循环体的分号单独放在一行上。当在右括号后附加到同一行时,它很容易被误认为是拼写错误,或者被忽略。名义上,您可以在一行中有多个 '\r' 字符;它可能很重要(但更可能不会)。
  • @JonathanLeffler -- 我实施了你的建议。谢谢。
  • @willus 你是如何决定 int lines_allocated 的值 128 的?
  • @Celeritas -- 好问题。有点随意。你想选择一个不是那么大的数字,你最初会过度分配内存,但又不会小到导致大量的 realloc 调用。你只是分配一个指针数组,所以你可以从一个更大的值开始。也可以调整系数 2 乘数。我见过1.5的使用。这部分取决于您认为您的典型案例也会是什么。如果你真的想要,你可以研究不同情况下的内存使用和运行时间以优化值,但性能变化可能很小。
  • 不错的答案!从行尾删除 \n 和/或 \r 的 for 循环将一个字符删除到多个字符,将 \0 放在字符串的最后一个不是换行符的字符处(从而截断最后一个字符) .您可能应该将words[i][j] 更改为words[i][j+1]。另外,用fclose()关闭打开的文件也是一个好习惯。
【解决方案2】:

你应该换行:

char** words = (**char)malloc(sizeof(*char));

进入这个:

char** words=(char **)malloc(sizeof(char *)*Max_Lines);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-13
    • 2012-09-13
    • 2013-07-26
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多