Function to insert text line by line from a file into string array passed by pointer

喜夏-厌秋 提交于 2019-12-24 10:10:01

问题


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.


回答1:


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?)




回答2:


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:


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
}


来源:https://stackoverflow.com/questions/56404325/function-to-insert-text-line-by-line-from-a-file-into-string-array-passed-by-poi

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!