Function to insert text line by line from a file i

2019-07-31 18:08发布

I'm trying to create a function read_lines that takes a file *fp, a pointer to char** lines, and pointer to int num_lines. The function should insert each line of text into lines, and increase num_lines to however many lines the file has.

Its probably really simple but I've been trying to insert the text for several hours now.

This is what main.c would look like. Everything but read_lines is already defined and working.

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

    char** lines = NULL;
    int num_lines = 0;
    FILE* fp = validate_input(argc, argv);
    read_lines(fp, &lines, &num_lines);
    print_lines(lines, num_lines);
    free_lines(lines, num_lines);
    fclose(fp);

    return 0;
}

This is one of my attempts at trying to append lines, but I couldn't figure it out.

read_lines.c

void read_lines(FILE *fp, char ***lines, int *num_lines) {
    int i;
    int N = 0;
    char s[200];
    for (i=0; i<3; i++)
    {
        while(fgets(s, 200, fp)!=NULL){N++;}
        char strings[50][200];

        rewind(fp);
        fgets(s, 200, fp);
        strcpy(lines[i],s);
    }

}

I'd appreciate any help at solving this, thanks.

标签: c fgets getline
3条回答
我欲成王,谁敢阻挡
2楼-- · 2019-07-31 18:39

I find fgets hard to use and more trouble than it's worth. Here is a fgetc and malloc-based approach:

void read_lines(FILE *fp, char ***lines, int *num_lines) {
    int c;

    size_t line = 0;
    size_t pos  = 0;
    size_t len  = 64;
    *lines = malloc(1 * sizeof(char*));
    (*lines)[0] = malloc(len);
    while ((c = fgetc(fp)) != EOF) {
        if (c == '\n') {
             (*lines)[line][pos] = '\0';
             line++;
             pos = 0;
             len = 64;
             *lines = realloc(*lines, (line+1) * sizeof(char*));
        } else {
            (*lines)[line][pos] = c;
        }
        pos++;
        if (pos >= len) {
            len *= 2;
            (*lines)[line] = realloc((*lines)[line], len);
        }
    }
    *num_lines = line+1;
}

I haven't checked this, so correct me if I made any mistakes. Also, in real code you would do lots of error checking here that I have omitted.

查看更多
姐就是有狂的资本
3楼-- · 2019-07-31 18:52

A solution (without headers and error checking for readability):

void read_lines(FILE *stream, char ***lines_ptr, size_t *num_lines_ptr) {
   char **lines = NULL;
   size_t num_lines = 0;
   char *line = NULL;
   size_t len = 0;
   ssize_t nread;
   while ((nread = getline(&line, &len, stream)) != -1) {
      lines = lines == NULL
         ? malloc(sizeof(char*))
         : realloc(lines, (num_lines+1)*sizeof(char*));

      lines[num_lines] = malloc(nread+1);
      memcpy(lines[num_lines], line);
      ++num_lines;
   }

   free(line);
   *lines_ptr = lines;
   *num_lines_ptr = num_lines;
}

The full solution:

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

// lines_ptr:     Output. Initial value ignored. To be freed by caller on success.
// num_lines_ptr: Output. Initial value ignored.
// Returns:       0 on error (errno set). 1 on success.
int read_lines(FILE *stream, char ***lines_ptr, size_t *num_lines_ptr) {
   char ***lines = NULL;
   size_t num_lines = 0;
   char *line = NULL;
   size_t len = 0;
   ssize_t nread;
   while ((nread = getline(&line, &len, stream)) != -1) {
      char **new_lines = lines == NULL
         ? malloc(sizeof(char*))
         : realloc(lines, (num_lines+1)*sizeof(char*));
      if (new_lines == NULL)
         goto error;

      lines = new_lines;

      lines[num_lines] = malloc(nread+1);
      if (lines[num_lines] == NULL)
         goto error;

      memcpy(lines[num_lines], line);
      ++num_lines;
   }

   if (ferror(stream))
      goto error;

   free(line);
   *lines_ptr = lines;
   *num_lines_ptr = num_lines;
   return 1;

error:
   for (size_t i=num_lines; i--; )
      free(lines[i]);

   free(lines);
   free(line);
   *lines_ptr = NULL;
   *num_lines_ptr = 0;
   return 0;
}

(You could save three lines by using the ..._ptr vars instead of setting them at the end, but is that really worth the readability cost?)

查看更多
劫难
4楼-- · 2019-07-31 19:02
assuming you have allocated enough memory to lines, following should work
if not you have to malloc/calloc() for lines[i] before doing strcpy() in every 
iteration of the loop.


void read_lines(FILE *fp, char ***lines, int *num_lines) {
       int N = 0;
       char s[200];
       while(fgets(s, 200, fp)!=NULL){
             N++;
             strcpy((*lines)[N],s);
       }
       *num_lines = N; // update pointer with value of N which is number of lines in file
}
查看更多
登录 后发表回答