|
Вопрос # 5 197/ вопрос открыт / |
|
Здравствуйте, уважаемые эксперты!
Как на Си (именно на Си :) ) правильно считать значения из файла в массив (количество элементов заранее не известно)?
Мой код в приложении, вываливается с ошибкой EXC_BAD_ACCESS в строке fscanf(...);
Заранее, спасибо.
Приложение: Переключить в обычный режим- // IDE: NetBeans 7.0 Beta 2
- // MacOS 10.5.8
-
- #include <stdio.h>
- #include <stdlib.h>
-
- int main(void) {
- FILE *file;
- file = fopen("some.txt", "r");
- int *Arr = (int*)malloc(2*sizeof(int));
- int Len = 0;
-
- while (!feof(file)) {
- fscanf(file, "%d ", Arr[Len]);
- Len++;
- Arr = realloc(Arr, (Len+1)*sizeof(int));
- }
- fclose(file);
-
- int i;
- for (i = 0; i < Len; i++) {
- printf("Arr[%d] = %d", i, Arr[i]);
- }
- return 0;
- }
Примечание #1 (14 апреля 2011, 22:02): Это int *Arr = (int*)malloc(2*sizeof(int));
заменить на это int *Arr = (int*)malloc(sizeof(int));
двойка там так, остаток эксперементов :)
 |
Вопрос задал: 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 (статус: 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 (статус: 2-ой класс), 15 апреля 2011, 10:35 [#3]:
Спасибо, разобрался
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|