Вернуть массив чисел, прочитанных из файла - PullRequest
0 голосов
/ 30 апреля 2019

У меня есть задание, в котором мне нужно написать функцию, которая читает числа из файла в массив и возвращает этот массив (указатель на первый элемент).Я написал функцию, которая читает из файла в массив, но не знаю, как ее вернуть.

void to_array(FILE* file, int bufsize){
char arr[bufsize][100];
fseek(file, 0, SEEK_SET);
int i = 0;
while(!feof(file)){
    fscanf(file, "%s", arr[i]);
    i++;
}

Буду признателен за любые идеи.

Ответы [ 3 ]

2 голосов
/ 01 мая 2019

в

void to_array(FILE* file, int bufsize){
  char arr[bufsize][100];
  ...
}

ваш массив локальный, если вы вернете его адрес, он не сможет его использовать

Один способ выделить его в голове с помощью malloc , другой - получить этот массив в качестве аргумента для его заполнения. Обратите внимание, что он не может быть статичным без постоянного размера

Не использовать feof проверить результат fscanf

Вы читаете числа, поэтому массив должен быть массивом чисел, давайте рассмотрим int

Пример, где функция получает дескриптор файла и указатель на переменную, которая будет содержать количество элементов, помещенных в массив, функция возвращает массив, выделенный в куче, как вы хотели

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

int * to_array(FILE * fp, size_t * sz)
{
  int * a = malloc(0); /* initially empty */
  int v;

  *sz = 0; /* initially no element */

  while (fscanf(fp, "%d", &v) == 1) {
    a = realloc(a, (++*sz)*sizeof(int)); /* add an entry */
    a[*sz - 1] = v; /* set entry */
  }

  return a;
}

int main()
{
  size_t sz;
  int * a = to_array(stdin, &sz);

  /* check */
  for (size_t i = 0; i != sz; ++i)
    printf("%d\n", a[i]);

  /* free used memory */
  free(a);

  return 0;
}

Компиляция и исполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall a.c
pi@raspberrypi:/tmp $ echo 11 22 33 | ./a.out
11
22
33
pi@raspberrypi:/tmp $

Исполнение под valgrind :

pi@raspberrypi:/tmp $ echo 11 22 33 | valgrind ./a.out
==10080== Memcheck, a memory error detector
==10080== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10080== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10080== Command: ./a.out
==10080== 
11
22
33
==10080== 
==10080== HEAP SUMMARY:
==10080==     in use at exit: 0 bytes in 0 blocks
==10080==   total heap usage: 6 allocs, 6 frees, 5,144 bytes allocated
==10080== 
==10080== All heap blocks were freed -- no leaks are possible
==10080== 
==10080== For counts of detected and suppressed errors, rerun with: -v
==10080== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

Функция выделяет дополнительную запись каждый раз, можно делать с помощью блока заданного количества записей, чтобы не приходилось делать это каждый раз при добавлении записи.

0 голосов
/ 01 мая 2019

Если вы решите использовать массив с автоматической продолжительностью хранения , вы должны объявить массив в вызывающей функции и передать указатель на массив в вашу функцию.Затем вы можете заполнить массив в функции.Однако вы также должны предоставить способ вернуть количество прочитанных строк.Ваш выбор типа void для вашей функции усложняет это (немного), так как вы обычно выбираете значимый тип возврата, такой как size_t, позволяющий вам возвращать количество прочитанных строк.Несмотря на это, вы можете передать указатель на значение size_t и обновить значение по этому адресу в вашей функции, тем самым сделав количество строк доступным обратно в вызывающую функцию.

Несколько замечаний:

/* if you need a constant, #define one (or more) */
#define STRSZ  32       /* maximum string stize in array */
#define NSTR  100       /* maximum number of strings in array */

( не экономить на размере буфера ) Самое длинное слово в словаре без ограничений (не медицинское) - 29 символов, а самое длинное 64-разрядное число - 20 символов (включаязнак), поэтому для обычного использования будет достаточно размера буфера 30, 32 будет учитывать любой конечный знак препинания.(если пробел не учитывает количество строк, которые нужно прочитать, удвойте число STRSZ до 64). При необходимости настройте количество строк и максимальное количество символов в каждой.

Ваша функция можетзатем записать, чтобы взять указатель на массив символов [32] , например,

 void to_array (char (*arr)[STRSZ], FILE *fp, size_t *nstr)
{
    *nstr = 0;  /* initialize number of strings to zero */

    /* protect array bounds while reading each string from file */
    while (*nstr < NSTR && fscanf (fp, "%31s" , arr[*nstr]) != EOF)
        (*nstr)++;  /* increment number of strings */
}

( примечание: использование поля width , модификатор "%31s" для защиты границ каждой строки при чтении из файла и использование *nstr < NSTR для защиты границ массива для числа строк, считанных из файла)

Inmain(), вы можете просто объявить 2D-массив с автоматической продолжительностью хранения и переменной для отслеживания количества заполненных строк, например,

    char arr[NSTR][STRSZ] = {{0}};  /* array to hold strings (max 31 char) */
    size_t n = 0;                   /* number of strings read */

Теперь вы можете вызвать ваш to_array() функционирует следующим образом:

    to_array (arr, fp, &n);     /* read strings from file, n holds number */

Помещая вместе с надлежащей проверкой того, что ваш файл открыт для чтения перед вашим вызовом to_array(), вы можете сделать:

#include <stdio.h>

/* if you need a constant, #define one (or more) */
#define STRSZ  32       /* maximum string size */
#define NSTR  100       /* maximum number of strings in array */

void to_array (char (*arr)[STRSZ], FILE *fp, size_t *nstr)
{
    *nstr = 0;  /* initialize number of strings to zero */

    /* protect array bounds while reading each string from file */
    while (*nstr < NSTR && fscanf (fp, "%31s" , arr[*nstr]) != EOF)
        (*nstr)++;  /* increment number of strings */
}

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

    char arr[NSTR][STRSZ] = {{0}};  /* array to hold strings (max 31 char) */
    size_t n = 0;                   /* number of strings read */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    to_array (arr, fp, &n);     /* read strings from file, n holds number */

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (size_t i = 0; i < n; i++)  /* output each string in arr */
        printf ("arr[%2zu] : '%s'\n", i, arr[i]);
}

Пример входного файла

$ cat ../dat/10int_nl.txt
8572
-2213
6434
16330
3034
12346
4855
16985
11250
1495

ПримерИспользование / Вывод

$ ./bin/fscanffile ../dat/10int_nl.txt
arr[ 0] : '8572'
arr[ 1] : '-2213'
arr[ 2] : '6434'
arr[ 3] : '16330'
arr[ 4] : '3034'
arr[ 5] : '12346'
arr[ 6] : '4855'
arr[ 7] : '16985'
arr[ 8] : '11250'
arr[ 9] : '1495'

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.Попробуйте использовать fgets(), если вам нужно прочитать строку за раз.

0 голосов
/ 01 мая 2019

Обязательно наберите #include <stdio.h> при использовании.

Обычно прерогатива пользователя, где он хочет указатель файла, то есть вам не нужно fseek.

Нужно принять размер буфера, а также буфер, или можно использовать динамический realloc (более сложные сообщения об ошибках и free.)

Используйте возвращаемые значения, чтобы решить, продолжать ли, а не feof. Я думаю, что вы выбрали правильную функцию чтения ввода с fscanf; обязательно прочитайте документацию . В частности, %s почти наверняка не то, что вы хотите; возможно %d?

while риск переполнения буфера; если у вас есть буфер фиксированного размера, что-то вроде этого:

size_t i;
for(i = 0; i < bufsize && scanf("%d", buf + i) == 1; i++);

Может произойти несколько вещей, в том числе:

  • Ошибка потока (файла). Используйте ferror для проверки.
  • Вы не достигли конца файла, это подходит для проверки с feof; если i == bufsize в программе больше нет места для номера; в противном случае это неверный номер. Эти условия неудобны для обработки, но я предлагаю errno .
  • Успех.

Возможно, кто-то хочет вернуть логическое значение для успеха?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...