Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 03.06.2015, 00:34   #1
Pug_from_Mordor
Пользователь
 
Аватар для Pug_from_Mordor
 
Регистрация: 09.11.2014
Сообщений: 40
Вопрос Не работает чтение из файла.

Пишу однофайловую базу данных на СИ по теме "Видеокарты". Все записи в базе данных реализую в динамическом массиве структур, то есть 1 запись=1 структура. Написал всю базу данных, осталось сделать только чтение из файла и сохранение в файл. То есть я хочу, чтобы в начале работы программы массив структур считывался из файла, а затем, если пользователь выберет соответствующий пункт меню, - массив записывался (сохранялся) в файл. Сохранение вроде хорошо работает, но, когда вставляю в начало программы функцию чтения из файла, программа начинает работать неправильно. А именно при запуске программы вылазит пустая консоль, в которой абсолютно ничего нельзя сделать. В чём моя ошибка?

P.S. В исходном коде убрал различные участки кода, никак не связанные с этой проблемой, чтобы вы могли быстрее в нём разобраться. Поэтому не надо писать, что где-то какие-то входные данные не проверяются или плохое оформление интерфейса. Как я понимаю, ошибка находится где-то в функции чтения из файла ( fileReading() ). Чтобы удостовериться, что сохранение массива в файл работает нормально, занесите вызов функции fileReading() в комментарий.

P.P.S. Весь код в одно сообщение не вместился, поэтому оставшуюся часть написал во втором сообщении. Код хоть и кажется большим, но разобраться в нём совсем несложно.
Код:
#include<stdio.h>
#include<locale.h>
#include<stdlib.h>
#include<string.h>

typedef struct {
	char manufacturer[23];	//Компания-производитель видеокарты
	char gpu[27];	//Модель графического процессора
	char memoryGeneration[6];	//Поколение видеопамяти
	float memoryCapacity;	//Объём видеопамяти
	long price;	//Цена видеокарты
} videoCard;

void menuOutput(void);	//Вывод меню на экран
void noteAdd(void);	//Добавление новой записи в конец списка
void saveInFile(void);	//Сохранение изменений в файле database.txt
int fileReading(void);	//Чтение из файла database.txt
void listOutput1(void);	//Вывод списка на экран для использования внутри других пользовательских функций

videoCard *array;	//Указатель для создания динамического массива структур
int size=0;	//Переменная для хранения размера массива структур
char enter[500];	//Строка для ввода пользователем какой-либо информации

int main(void)
{
	int menuChoice=0;

	array=(videoCard *)calloc(size, sizeof(videoCard));

	if(fileReading()==-1)
	{
		printf("Не удалось открыть файл database.txt для начала работы.Экстренное завершение программы.\n\n");
		return 0;
	}

	setlocale(LC_ALL, "RU");

	while(1)
	{
		if(menuChoice!=-1)
			menuOutput();

		while(scanf("%d", &menuChoice)!=1)
		{
			printf("\nНеверно выбран пункт меню.Выберите его ещё раз:\n? ");
			fflush(stdin);
		}

		getchar();
		switch(menuChoice)
		{
			case 11: system("cls"); noteAdd(); system("cls"); break;	
			case 61: system("cls"); saveInFile(); system("cls"); break;
			case  0: free(array); exit(0);  

			default:
				printf("\nНеверно выбран пункт меню.Выберите его ещё раз:\n? ");
				menuChoice=-1;
		}
	}

	return 0;
}

//Вывод меню на экран
void menuOutput(void)
{
	printf("===Добавление===\n"
	       "11.Добавить в список новую запись\n"
	       "===Работа с файлом===\n"
	       "61.Сохранить изменения в файле database.txt\n"
	       "\n0.Выход\n\n? ");
}

//Сохранение изменений в файле database.txt
void saveInFile(void)
{
	FILE *databasePtr;

	printf("===Сохранение изменений в файле database.txt===\n\n");

	if((databasePtr=fopen("database.txt", "w")) == NULL)
		printf("Не удалось открыть файл для сохранения.\n");
	else
	{
		for(int i=0; i<size; ++i)
			fwrite(&array[i], sizeof(videoCard), 1, databasePtr);

		fclose(databasePtr);

		printf("Изменения успешно сохранены.\n");
	}

	printf("\nEnter - вернуться в меню\n");
	while(getchar()!='\n')
		;
}

//Чтение из файла database.txt
int fileReading(void)
{
	FILE *databasePtr;

	if((databasePtr=fopen("database.txt", "r")) == NULL)
		return -1;

	for(int i=0; !feof(databasePtr); ++i)
	{
		array=(videoCard *)realloc(array, ++size);

		fread(&array[i], sizeof(videoCard), 1, databasePtr);
	}

	fclose(databasePtr);

	return 1;
}

//Вывод списка на экран для использования внутри других пользовательских функций
void listOutput1(void)
{
	if(size==0)
	{
		printf("Список пуст.\n");
		return;
	}
	printf("## Компания-производитель  Графический процессор       Видеопамять   Цена(б.р.)\n");
	printf("-------------------------------------------------------------------------------\n");
	
	for(int i=0; i<size; ++i)
		printf("%-2d %-22s  %-26s  %.1fGB-%-5s   %-8ld\n",
			    i+1, array[i].manufacturer, array[i].gpu, array[i].memoryCapacity, array[i].memoryGeneration, array[i].price);
}

Последний раз редактировалось Аватар; 03.06.2015 в 06:41.
Pug_from_Mordor вне форума Ответить с цитированием
Старый 03.06.2015, 00:37   #2
Pug_from_Mordor
Пользователь
 
Аватар для Pug_from_Mordor
 
Регистрация: 09.11.2014
Сообщений: 40
По умолчанию

Код:
//Добавление новой записи в конец списка
void noteAdd(void)
{	
	printf("===Добавление новой записи в список===\n\n");
	printf("Исходный список:\n");
	listOutput1();
	printf("\n");

	array=(videoCard*)realloc(array, ++size);

	printf("Введите компанию-производитель видеокарты (например: ASUS): ");
	while(1)
	{
		gets(enter);

		if(strlen(enter)>22)
		{
			printf("\nВведено слишком длинное название компании-производителя.Введите его ещё раз: ");
			continue;
		}

		break;
	}

	strcpy(array[size-1].manufacturer, enter);

	printf("Введите модель графического процессора (например: Geforce GTX 960): ");
	while(1)
	{
		gets(enter);

		if(strlen(enter)>26)
		{
			printf("\nВведено слишком длинное название графического процессора.Введите его ещё раз: ");
			continue;
		}

		break;
	}
	
	strcpy(array[size-1].gpu, enter);

	printf("Введите объём видеопамяти в гигабайтах (например: 4): ");
	while(1)
	{
		if(scanf("%f", &array[size-1].memoryCapacity)!=1)
		{
			printf("\nНеверно введён объём видеопамяти.Введите его ещё раз: ");
			fflush(stdin);
			continue;
		}

		if(array[size-1].memoryCapacity<=0 || array[size-1].memoryCapacity>16)
		{
			printf("\nВведено неверное значение объёма видеопамяти.Введите его ещё раз: ");
			continue;
		}

		break;
	}

	getchar();
	printf("Введите поколение видеопамяти (например: GDDR3): ");
	while(1)
	{
		gets(enter);

		if(strlen(enter)>5)
		{
			printf("\nВведено слишком длинное название поколения видеопамяти.Введите его ещё раз: ");
			continue;
		}

		break;
	}
	
	strcpy(array[size-1].memoryGeneration, enter);

	printf("Введите цену видеокарты в белорусских рублях (например: 5430000): ");
	while(1)
	{
		if(scanf("%ld", &array[size-1].price)!=1)
		{
			printf("\nНеверно введёна цена видеокарты.Введите её ешё раз: ");
			fflush(stdin);
			continue;
		}

		if(array[size-1].price<0 || array[size-1].price>99999999)
		{
			printf("\nВведена неверная цена видеокарты.Введите её ещё раз: ");
			continue;
		}

		break;
	}
	
	getchar();
	printf("\nЗапись успешно добавлена.\n\n");
	printf("Список после добавления записи:\n");
	listOutput1();
	printf("\nEnter - вернуться в меню\n");
	while(getchar()!='\n')
		;
}

Последний раз редактировалось Аватар; 03.06.2015 в 06:41.
Pug_from_Mordor вне форума Ответить с цитированием
Старый 03.06.2015, 07:37   #3
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Код:
//Чтение из файла database.txt
int fileReading(void)
{
	FILE *databasePtr;
	if((databasePtr=fopen("database.txt", "r")) == NULL)
		return -1;

fseek (databasePtr, 0, 2);               // получаем количество
FileLen = ftell(databasePtr);            // байт в файле
RecLen = FileLen /sizeof(videoCard);            // байт в файле
array=(videoCard *)realloc(array, RecLen);
fread(array, sizeof(videoCard), RecLen , databasePtr);

	fclose(databasePtr);

	return 1;
}
Годится идея?

Кстати могу предложить такое: http://www.programmersforum.ru/showthread.php?t=105501
Т.е. Работать с файлом без размещения всего сразу в памяти.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 03.06.2015, 22:42   #4
Pug_from_Mordor
Пользователь
 
Аватар для Pug_from_Mordor
 
Регистрация: 09.11.2014
Сообщений: 40
По умолчанию

Спасибо, очень сильно помог. Разобрался в работе твоего алгоритма. Вот получившаяся функция чтения структур из файла в динамический массив:
Код:
//Чтение из файла database.txt
int fileReading(void)
{
	FILE *databasePtr;
	int FileLen;

	if((databasePtr=fopen("database.txt", "r")) == NULL)
		return -1;

	fseek(databasePtr, 0, SEEK_END);	//Устанавливаем указатель позиции в файле на последний байт
	FileLen = ftell(databasePtr);	/*Присваиваем переменной FileLen индекс байта, на который указывает указатель позиции. 
	Таким образом мы вычислим общее количество байт в файле*/
	size = FileLen /sizeof(videoCard);	/*Делим количество байт в файле на размер одной переменной(структуры). Таким образом мы узнаём сколько переменных(структур)
	находится в файле*/
	array=(videoCard *)realloc(array, size);	//Перераспределяем память в массиве array под нужное количество элементов
	fseek(databasePtr, 0, SEEK_SET);	//Устанавливаем указатель позиции на начало файла
	fread(array, sizeof(videoCard), size, databasePtr);	//Считываем из файла все переменные(структуры) и записываем их в массив array

	fclose(databasePtr);

	return 1;
}

Последний раз редактировалось Pug_from_Mordor; 03.06.2015 в 22:45.
Pug_from_Mordor вне форума Ответить с цитированием
Старый 03.06.2015, 22:47   #5
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

А я бы на твоем месте сделал так как DBF - хранил бы в начале файла кол-во записей. Чтоб не становиться в конец и вычислять размер, а сразу - считал int, создал массив и следующим же чтивом его наполнил.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 03.06.2015, 23:09   #6
Pug_from_Mordor
Пользователь
 
Аватар для Pug_from_Mordor
 
Регистрация: 09.11.2014
Сообщений: 40
По умолчанию

Если время останется, то попробую. В моей базе данных есть ещё одна проблема: когда пользователь вводит 0 в меню после добавления записи, программа должна закрыться, а она прекращает свою работу(вылазит новое окно о прекращении). Тут дело даже не в работе с файлом, а именно в добавлении структуры в массив.
Причём ошибка из-за инициализации численных переменных в структуре. Код тот же, только без функций работы с файлом. Можете посмотреть?
Код:
#include<stdio.h>
#include<locale.h>
#include<stdlib.h>
#include<string.h>

typedef struct {
	char manufacturer[23];	//Компания-производитель видеокарты
	char gpu[27];	//Модель графического процессора
	char memoryGeneration[6];	//Поколение видеопамяти
	float memoryCapacity;	//Объём видеопамяти
	long price;	//Цена видеокарты
} videoCard;

void menuOutput(void);	//Вывод меню на экран
void noteAdd(void);	//Добавление новой записи в конец списка
void listOutput1(void);	//Вывод списка на экран для использования внутри других пользовательских функций

videoCard *array;	//Указатель для создания динамического массива структур
int size=0;	//Переменная для хранения размера массива структур
char enter[500];	//Строка для ввода пользователем какой-либо информации

int main(void)
{
	int menuChoice=0;

	array=(videoCard *)calloc(size, sizeof(videoCard));

	setlocale(LC_ALL, "RU");

	while(1)
	{
		if(menuChoice!=-1)
			menuOutput();

		while(scanf("%d", &menuChoice)!=1)
		{
			printf("\nНеверно выбран пункт меню.Выберите его ещё раз:\n? ");
			fflush(stdin);
		}

		getchar();
		switch(menuChoice)
		{
			case 11: system("cls"); noteAdd(); system("cls"); break;	
			case  0: free(array); exit(0);  

			default:
				printf("\nНеверно выбран пункт меню.Выберите его ещё раз:\n? ");
				menuChoice=-1;
		}
	}

	return 0;
}

//Вывод меню на экран
void menuOutput(void)
{
	printf("===Добавление===\n"
	       "11.Добавить в список новую запись\n"
	       "\n0.Выход\n\n? ");
}

//Добавление новой записи в конец списка
void noteAdd(void)
{	
	printf("===Добавление новой записи в список===\n\n");
	printf("Исходный список:\n");
	listOutput1();
	printf("\n");

	array=(videoCard*)realloc(array, ++size);

	printf("Введите компанию-производитель видеокарты (например: ASUS): ");
	while(1)
	{
		gets(enter);

		if(strlen(enter)>22)
		{
			printf("\nВведено слишком длинное название компании-производителя.Введите его ещё раз: ");
			continue;
		}

		break;
	}

	strcpy(array[size-1].manufacturer, enter);

	printf("Введите модель графического процессора (например: Geforce GTX 960): ");
	while(1)
	{
		gets(enter);

		if(strlen(enter)>26)
		{
			printf("\nВведено слишком длинное название графического процессора.Введите его ещё раз: ");
			continue;
		}

		break;
	}
	
	strcpy(array[size-1].gpu, enter);

	printf("Введите объём видеопамяти в гигабайтах (например: 4): ");
	while(1)
	{
		if(scanf("%f", &array[size-1].memoryCapacity)!=1)
		{
			printf("\nНеверно введён объём видеопамяти.Введите его ещё раз: ");
			fflush(stdin);
			continue;
		}

		if(array[size-1].memoryCapacity<=0 || array[size-1].memoryCapacity>16)
		{
			printf("\nВведено неверное значение объёма видеопамяти.Введите его ещё раз: ");
			continue;
		}

		break;
	}

	getchar();
	printf("Введите поколение видеопамяти (например: GDDR3): ");
	while(1)
	{
		gets(enter);

		if(strlen(enter)>5)
		{
			printf("\nВведено слишком длинное название поколения видеопамяти.Введите его ещё раз: ");
			continue;
		}

		break;
	}
	
	strcpy(array[size-1].memoryGeneration, enter);

	printf("Введите цену видеокарты в белорусских рублях (например: 5430000): ");
	while(1)
	{
		if(scanf("%ld", &array[size-1].price)!=1)
		{
			printf("\nНеверно введёна цена видеокарты.Введите её ешё раз: ");
			fflush(stdin);
			continue;
		}

		if(array[size-1].price<0 || array[size-1].price>99999999)
		{
			printf("\nВведена неверная цена видеокарты.Введите её ещё раз: ");
			continue;
		}

		break;
	}
	
	getchar();
	printf("\nЗапись успешно добавлена.\n\n");
	printf("Список после добавления записи:\n");
	listOutput1();
	printf("\nEnter - вернуться в меню\n");
	while(getchar()!='\n')
		;
}

//Вывод списка на экран для использования внутри других пользовательских функций
void listOutput1(void)
{
	if(size==0)
	{
		printf("Список пуст.\n");
		return;
	}
	printf("## Компания-производитель  Графический процессор       Видеопамять   Цена(б.р.)\n");
	printf("-------------------------------------------------------------------------------\n");
	
	for(int i=0; i<size; ++i)
		printf("%-2d %-22s  %-26s  %.1fGB-%-5s   %-8ld\n",
			    i+1, array[i].manufacturer, array[i].gpu, array[i].memoryCapacity, array[i].memoryGeneration, array[i].price);
}

Последний раз редактировалось Stilet; 04.06.2015 в 09:18.
Pug_from_Mordor вне форума Ответить с цитированием
Старый 04.06.2015, 09:44   #7
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
ошибка из-за инициализации численных переменных в структуре.
Не оч. понял. Ткни в код, на какой строке ошибка и как ее текст выглядит.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 04.06.2015, 16:01   #8
Pug_from_Mordor
Пользователь
 
Аватар для Pug_from_Mordor
 
Регистрация: 09.11.2014
Сообщений: 40
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
Не оч. понял. Ткни в код, на какой строке ошибка и как ее текст выглядит.
Уменьшил размер кода, убрав все проверки:
Код:
#include<stdio.h>
#include<locale.h>
#include<stdlib.h>
#include<string.h>

typedef struct {
	char manufacturer[23];	//Компания-производитель видеокарты
	char gpu[27];	//Модель графического процессора
	char memoryGeneration[6];	//Поколение видеопамяти
	float memoryCapacity;	//Объём видеопамяти
	long price;	//Цена видеокарты
} videoCard;

void menuOutput(void);	//Вывод меню на экран
void noteAdd(void);	//Добавление новой записи в конец списка

videoCard *array;	//Указатель для создания динамического массива структур
int size=0;	//Переменная для хранения размера массива структур

int main(void)
{
	int menuChoice=0;

	array=(videoCard *)calloc(size, sizeof(videoCard));

	setlocale(LC_ALL, "RU");

	while(1)
	{
		if(menuChoice!=-1)
			menuOutput();

		scanf("%d", &menuChoice);

		getchar();
		switch(menuChoice)
		{
			case 11: system("cls"); noteAdd(); system("cls"); break;	
			case  0: free(array); exit(0);  

			default:
				printf("\nНеверно выбран пункт меню.Выберите его ещё раз:\n? ");
				menuChoice=-1;
		}
	}

	return 0;
}

//Вывод меню на экран
void menuOutput(void)
{
	printf("===Добавление===\n"
	       "11.Добавить в список новую запись\n"
	       "\n0.Выход\n\n? ");
}

//Добавление новой записи в конец списка
void noteAdd(void)
{	
	printf("===Добавление новой записи в список===\n\n");

	array=(videoCard*)realloc(array, ++size);

	printf("Введите компанию-производитель видеокарты (например: ASUS): ");
	gets(array[size-1].manufacturer);

	printf("Введите модель графического процессора (например: Geforce GTX 960): ");
	gets(array[size-1].gpu);

	//printf("Введите объём видеопамяти в гигабайтах (например: 4): ");
	//scanf("%f", &array[size-1].memoryCapacity);

	//getchar();
	printf("Введите поколение видеопамяти (например: GDDR3): ");
	gets(array[size-1].memoryGeneration);

	//printf("Введите цену видеокарты в белорусских рублях (например: 5430000): ");
	//scanf("%ld", &array[size-1].price);
	
	//getchar();
	printf("\nЗапись успешно добавлена.\n\n");
	printf("Enter - вернуться в меню\n");
	while(getchar()!='\n')
		;
}
В функции добавления записи занёс считывание чисел в комментарии. Так всё работает. Если вернуть считывание из комментариев, то при выходе из программы (0 - в меню) будет выдавать ошибку.

Последний раз редактировалось Stilet; 04.06.2015 в 17:15.
Pug_from_Mordor вне форума Ответить с цитированием
Старый 04.06.2015, 21:11   #9
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Если вернуть считывание из комментариев, то при выходе из программы (0 - в меню) будет выдавать ошибку.
А если я тебе скажу что протестировал на GCC твой код, и никакой ошибке у меня не было, хотя я раскомментировал все кроме getchar?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Чтение из файла V1rus.25 Помощь студентам 9 15.04.2013 17:10
Чтение из файла clasterit Паскаль, Turbo Pascal, PascalABC.NET 6 04.11.2011 17:46
TP7 чтение из файла, работает но не работает!? Qousio Помощь студентам 7 02.06.2009 09:37
Чтение из файла Amen БД в Delphi 2 09.12.2008 10:40
Чтение из файла Need_Help Паскаль, Turbo Pascal, PascalABC.NET 5 19.05.2007 05:37