Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 5 197

Раздел: C++
/ вопрос открыт /

Здравствуйте, уважаемые эксперты!
Как на Си (именно на Си :) ) правильно считать значения из файла в массив (количество элементов заранее не известно)?
Мой код в приложении, вываливается с ошибкой EXC_BAD_ACCESS в строке fscanf(...);
Заранее, спасибо.

Приложение:
  1. // IDE: NetBeans 7.0 Beta 2
  2. // MacOS 10.5.8
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6.  
  7. int main(void) {
  8. FILE *file;
  9. file = fopen("some.txt", "r");
  10. int *Arr = (int*)malloc(2*sizeof(int));
  11. int Len = 0;
  12.  
  13. while (!feof(file)) {
  14. fscanf(file, "%d ", Arr[Len]);
  15. Len++;
  16. Arr = realloc(Arr, (Len+1)*sizeof(int));
  17. }
  18. fclose(file);
  19.  
  20. int i;
  21. for (i = 0; i < Len; i++) {
  22. printf("Arr[%d] = %d", i, Arr[i]);
  23. }
  24. return 0;
  25. }


Примечание #1 (14 апреля 2011, 22:02):
Это int *Arr = (int*)malloc(2*sizeof(int));
заменить на это int *Arr = (int*)malloc(sizeof(int));
двойка там так, остаток эксперементов :)

IlluminatI Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: IlluminatI (статус: 2-ой класс)
Вопрос отправлен: 14 апреля 2011, 21:59
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: Вадим К

Здравствуйте, IlluminatI!
Нужно знать, что fscanf требует адреса переменной, а не значения. после этого все стает на свои места. То есть, нужно просто добавить & в строку с fscanf

fscanf(file, "%d", &Arr[Len]);
Но у этого кода есть ещё один недостаток - он выделяет на один элемент больше, чем нужно и забывает освободить память в конце. Поэтому программа должна выглядеть как минимум так
#include <stdio.h>
#include <stdlib.h>
 
int main(void) {
    FILE *file;
    file = fopen("some.txt", "r");
    int *Arr = NULL;
    int Len = 0;
 
    while (!feof(file)) {
       Len++;
       Arr = realloc(Arr, Len*sizeof(int));
       fscanf(file, "%d", &Arr[Len-1]);
    }
    fclose(file);
 
    int i;
    for (i = 0; i < Len - 1; i++) {
        printf("Arr[%d] = %d\n", i, Arr[i]);
    }
    free(Arr);
    return 0;
}

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 14 апреля 2011, 22:24
Оценка за ответ: 5

Комментарий к оценке: спасибо)

Мини-форум вопроса

Всего сообщений: 3; последнее сообщение — 15 апреля 2011, 10:35; участников в обсуждении: 2.
IlluminatI

IlluminatI (статус: 2-ой класс), 15 апреля 2011, 00:48 [#1]:

У меня еще вопрос.
Вот инициализация массивов:
float* InpSignal = {NULL};
float* OutSignal = {NULL};
float* TimeArray = {NULL};
Вот функция считывания из файла:
float* ReadFromFile(char *FileName) {
   FILE *file;
   float *Array;
   file = fopen(FileName, "r");
   if (file == NULL)
       return 0;
 
   int Len = 0;
   while (!feof(file)) {
       Len++;
       Array = realloc(Array, Len*sizeof(float));
       fscanf(file, "%f", &Array[Len-1]);
   }
   fclose(file);
   printf("Done.\n");
 
   return Array;
}
А вот вызов:
InpSignal = ReadFromFile("InputSignal.txt");
OutSignal = ReadFromFile("OutputSignal.txt");      
TimeArray = ReadFromFile("TimeList.txt");

После всего этого, все три указателя ссылаются на один и тот же адресс, и значения получаются одни и те же, почему так? И как это можно исправить?
Вадим К

Вадим К (статус: Академик), 15 апреля 2011, 10:15 [#2]:

если это новый вопрос - то нужно и создавать новый вопрос:)
ответ такой - это побочный эффект. И если немного программу поменять, он может пропасть или сильно видоизменится.
Итак, первое правило любого программиста на С/С++ - все локальный переменные НУЖНО инициализировать перед использованием. Иначе там МУСОР! Но на практике там оказывается не совсем мусор и значением можно угадать с большой вероятностью.
Посмотрим на приведенный код. Три раза подряд вызывается одна и та же функция. Поэтому оказывается, что локальные переменные, которые размещаются в стеке, оказываются в тех же местах.
По какой то случайности в первый раз Arr содержало 0 и realloc в этом случае отработал как обычный malloc.
В следующий вызов функции Arr будет содержать тот же адрес! Так как памяти на том месте ещё достаточно с большой вероятностью, то и размещать новый массив будет там же...

Как же это исправить? нужно внимательнее посмотреть на тот код, который я дал в ответе и найти одну принципиальную разницу:)
Галочка "подтверждения прочтения" - вселенское зло.
IlluminatI

IlluminatI (статус: 2-ой класс), 15 апреля 2011, 10:35 [#3]:

Спасибо, разобрался :)

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:34
Выполнено за 0.04 сек.