Функция для вставки текста строка за строкой из файла в массив строк, передаваемый указателем - PullRequest
1 голос
/ 01 июня 2019

Я пытаюсь создать функцию read_lines, которая принимает файл * fp, указатель на строки char ** и указатель на int num_lines.Функция должна вставлять каждую строку текста в строки и увеличивать число строк до того количества строк, которое есть в файле.

Возможно, это действительно просто, но я пытаюсь вставить текст уже несколько часов.

Вот как будет выглядеть main.c.Все, кроме read_lines, уже определено и работает.

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;
}

Это одна из моих попыток добавить строки, но я не смог понять это.

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);
    }

}

Буду признателен за любую помощь в решении этой проблемы, спасибо.

Ответы [ 3 ]

2 голосов
/ 01 июня 2019

Решение (без заголовков и проверки ошибок на удобочитаемость):

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;
}

Полное решение:

#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;
}

(Вы можете сохранить три строки, используя ..._ptr varsвместо того, чтобы устанавливать их в конце, но действительно ли это стоит затрат на читабельность?)

0 голосов
/ 01 июня 2019
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
}
0 голосов
/ 01 июня 2019

Я нахожу fgets сложным в использовании и большим количеством проблем, чем оно того стоит. Вот подход, основанный на fgetc и malloc:

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;
}

Я не проверял это, так что поправьте меня, если я сделал какие-либо ошибки. Кроме того, в реальном коде вы бы сделали здесь много ошибок, которые я пропустил.

...