@romajke

Как реализовать считывание строк из файла в массив строк?

По ходу дела, я очень плохо понял тему указателей и работы с памятью, и теперь вот никак не могу сделать, казалось бы простейшую вещь.
Есть текстовый файл со словами, записанными по одному слову в строчку. Нужно считать каждую строку в массив arr[]. Пробовал и fscanf и fgetsе - не получается :(
Подскажите, что я не так делаю, и как правильно?
#include <stdio.h>
#define SIZE 45

int main()
{
    char *text = "example";
    FILE *fp = fopen(text, "r");
    if (fp == NULL)
    {
        printf("Could not open %s.\n", text);
        return 1;
    }

    //char word[SIZE+1];
    char *arr[26];

    int k=0;
    while(!feof(fp))
    {
        fscanf(fp,"%s",arr[k]);
        //fgets(word, SIZE, fp);
        //arr[k]=word;
        k++;
    }
   for(int i=0; i<3; i++)
   {
       if (arr[i])
        printf("%i ->%s\n", i+1,  arr[i]);
   }
    return 0;
}


Входные данные:
abc
bcd
cde
def
zet
  • Вопрос задан
  • 15450 просмотров
Решения вопроса 1
@res2001
Developer, ex-admin
На сколько я понял вы пытаетесь прочитать строку из файла и сохранить ее как элемент массива arr.
Но делаете это не правильно.
Ваша ошибка в том, что fscanf/fgets не выделяет память для хранения строки, она использует тот буфер, который вы ей предоставите. Но вы ничего не предоставляете.
Вам нужно для каждого элемента arr выделить память под строку:
arr[i] = (char*)malloc(sizeof(char) * BUFLEN);
где BUFLEN - некоторая целочисленная константа, обозначающая максимальную длину строки.
Тогда чтение из файла, как реализовано у вас пройдет.
В конце память выделенную с помощью malloc нужно освободить с помощью вызова free для каждого элемента массива arr.
И не забывайте обрабатывать ошибки выделения памяти и возвраты файловых операций.
fscanf со спецификатором формата "%s" считывает не строку, а слово - в строке может быть много слов. Для чтения строки используйте fgets, либо читайте посимвольно fgetc.
Когда заработает, потренируйтесь на файле, содержащем строку из более чем BUFLEN символов и попытайтесь найти корректный выход из этой ситуации.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
@lvv85
Используйте двумерный массив для строк:
char arr[26][SIZE];

И добавьте fclose(fp) после цикла while{...}.
Ответ написан
@sergio_nsk
fscanf замени на
size_t alloced = 0;
getline(&arr[k], &alloced, fp);


getline с сравнением с -1 можно поместить в while.
Ответ написан
dio4
@dio4
team leader, system engineer, master of sports
/* читаем из файла требуемое кол. строк ROWS или до конца файла EOF
 * (что наступит раньше), формируем строку по конечному символу '\n'
 * в файле, затем добавляем завершающий '\0' и полученную строку СИ 
 * записываем
 * в двумерный массив по 1-й строке в каждый элемент массива.
 * Затем массив выводим на консоль. Есть подсчет считанных строк.
 * См также ниже мой коммент
*/

/* file_in находится в каталоге программы и имеет вид:
I am a human 1
I am a 2 human`s 2
I am a 3 human 3
Nmjh## ___ 987 ht!
5555555555555555
66666666666666
77777777777777
8888888888888888
*/

#include <stdio.h>
#include <stdlib.h> /* prototype exit() */
#include <string.h>
#define ROWS 7
#define COLS 20
void file_open(void);
FILE * file_in;
char ch, arr_str[ROWS][COLS];
int j, i, count = 0;

int main(int agrc, char * argv[]){
  file_open();
  for(j = 0; j < ROWS; ++j){
    for(i = 0; (ch=getc(file_in)) != '\n' && (ch != EOF); ++i) {
      arr_str[j][i] = ch; // заполнение строки
    } //конец внутреннего for
    if(ch == EOF){
      puts("достигнут конец файла, выход.");
      fprintf(stdout, "count is: %i \n", count);
      break;
    } // конец if
    else{
      arr_str[j][i] = '\0'; 
      ++count;
    } // конец else
    
  } // конец внешнего for
  fclose(file_in);
/* вывод массива на консоль */
  fprintf(stdout, "Из файла считано %i строк, которые имеют вид:\n", count);
  puts(""); // пропуск строки
  for(j = 0; j < count; ++j){
    fprintf(stdout, "%s\n", arr_str[j]);
  }
  puts(""); // пропуск строки
  puts("Программа завершена.");
  exit(EXIT_SUCCESS);
}

void file_open(void){
  if( (file_in = fopen("file_in", "r")) == NULL){
    fprintf(stdout, "%s\n", "не могу отрыть файл для чтения");
    exit(EXIT_FAILURE);
  }
}

/*
Вывод на консоль:
Из файла считано 7 строк, которые имеют вид:

I am a human 1
I am a 2 human`s 2
I am a 3 human 3
Nmjh## ___ 987 ht!
5555555555555555
66666666666666
77777777777777

Программа завершена.
*/
Ответ написан
@mrobespierre
указатели сами по себе не очень сложно понять: грубо говоря - это переменная, значением которой является адрес в памяти, по которому лежит значение другой переменной (обычно анонимной, или безымянной, если угодно). строк в Си нет (но можно подключить например glib и наслаждаться). строкой в "ванильном" Си, без дополнительных библиотек, принято называть массив символов. массив в Си (с небольшими оговорками) - это указатель на первый элемент массива. выше уже написали, что если вы хотите считать строки файла в массив строк, то на самом деле вам нужен массив массивов (т.е. 2-мерный массив) символов. важной особенностью массивов в Си является необходимость указания размера ещё на этапе компиляции, т.е. мы сначала задаем размер массива (в данном случае он будет длиной строки), а потом заполняем его, попутно проверяя, не "переполнили" ли мы выделенное место. коллеги предлагают небольшие размеры массивов (26,7,20), я всегда выделяю 512 (2017 год на дворе), но считываю не более 500. удачи.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы