При работе с бинарными файлами .exe вызвал срабатывание точки останова СИ
Я вызываю две эти функции(это реализовано в main): сначала добавляю данные в файл, затем считываю в массив структур и вывожу. Первая функция работает, а при вызове второй функции - "срабатывание точки останова" при присвоении переменной fp указателя на поток - при вызове функции fopen(). Помогите разобраться с проблемой не понимаю, где ошибка. Может быть это из-за глобальных переменных? Функция number_input просто присваивает значение по указателю.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct member { // структура члена сборной команды по футболу
char full_name[60]; // ФИО
char club[30];
char role[12]; // goalkeeper, defender, midfielder, striker
int age;
int matches;
int goals_scored;
};
int contain_latin_letters(char str[50], int len) { // функция проверяет, является ли символ допустимым для использования (латинские буквы и цифры)
char aval[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM "; // массив допустимых символов
int aval_length = strlen(aval); // подсчитываем длину строки aval c помощью функции из библиотеки string.h
int f = 0;
for (int j = 0; j < len; j++) {
for (int i = 0; i < aval_length; i++) {
if (aval[i] == str[j]) // если находим совпадение, то возвращаем 1 (правда - символ является допустимым)
f++;
}
}
if(f == len)
return 1;
return 0; // если не будет возвращена 1, то возвращаем 0 (ложь)
}
void number_input(char str[256], int* p) { // функция присвоит необходимое(числовое) значение переменной в основной функции, находящейся по адресу(2-ой аргумент)
char string[256];
printf("%s", str);
fgets(string, sizeof(string), stdin);
while (sscanf(string, "%i", p) != 1) {
printf("Incorrect input, try again!! %s", str);
fgets(string, sizeof(string), stdin);
}
}
FILE* fp;
struct member* arr;
int arr_len = 0;
void add_data() {
fp = fopen("database.bin", "wb");
arr_len++;
arr = realloc(arr, sizeof(struct member*) * arr_len);
printf(" Input information about new member:");
do {
printf("\nFull name - ");
getchar();
gets(arr[arr_len - 1].full_name);
} while (!contain_latin_letters(arr[arr_len - 1].full_name, strlen(arr[arr_len - 1].full_name)));
do {
printf("Club - ");
gets(arr[arr_len - 1].club);
} while (!contain_latin_letters(arr[arr_len - 1].club, strlen(arr[arr_len - 1].club)));
do {
printf("Role (goalkeeper, defender, midfielder, striker) - ");
gets(arr[arr_len - 1].role);
} while (!(!strcmp(arr[arr_len - 1].role, "goalkeeper") || !strcmp(arr[arr_len - 1].role, "defender") || !strcmp(arr[arr_len - 1].role, "midfielder") || !strcmp(arr[arr_len - 1].role, "striker")));
number_input("Age of member - ", &arr[arr_len - 1].age);
number_input("Number of matches played for team - ", &arr[arr_len - 1].matches);
number_input("Number of scored goals - ", &arr[arr_len - 1].goals_scored);
char* c = (char*)arr; // устанавливаем указатель на начало структуры
// посимвольно записываем в файл структуру
for (int i = 0; i < sizeof(struct member) * arr_len; i++)
{
putc(*c++, fp);
}
fclose(fp);
}
void output_database() {
fp = fopen("database.bin", "rb");
char* c = (char*)arr;
// считываем посимвольно из файла
int i;
while ((i = getc(fp)) != EOF)
{
*c = i;
c++;
}
for (i = 0; i < arr_len; i++)
printf("%s %s %s %d %d %d\n", arr[i].full_name, arr[i].club, arr[i].role, arr[i].age, arr[i].matches, arr[i].goals_scored);
fclose(fp);
}
int main(void) {
int f;
printf("\tMenue:\n1 -> Add data\n2 -> Output database\n0 -> End process\n");
do {
place:;
printf("\nInput number of the option from menue: ");
scanf("%d", &f);
switch (f) {
case 0:
return 0;
break;
case 1:
add_data();
break;
case 2:
output_database();
break;
default:
printf("Wrong input, make it again!! ");
goto place;
break;
}
} while (f != 0);
return 0;
}
Ответы (1 шт):
я решил для начала просто минимальной правкой заставить работать код (для тех, кто решил минусовать - листайте дальше, там будет лучше)
void output_database() {
fp = fopen("database.bin", "rb");
// возмьем размер массива
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
// размер файла должен быть кратен размеру структуры
if (sz % sizeof(struct member) != 0)
{
// упс
fclose(fp);
}
// теперь мы можем выставить этот самый размер!
arr_len = sz / sizeof(struct member);
rewind(fp); // отмотаем на начало файла
arr = malloc(sz); // выделим достаточно места
char* c = (char*)arr;
// считываем посимвольно из файла
int i;
while ((i = getc(fp)) != EOF)
{
*c = i;
c++;
}
for (i = 0; i < arr_len; i++)
printf("%s %s %s %d %d %d\n", arr[i].full_name, arr[i].club, arr[i].role, arr[i].age, arr[i].matches, arr[i].goals_scored);
fclose(fp);
}
все, можно запускать, оно уже выводит данные. Но давайте посмотрим на это неподобство - чтения файла посимвольно. Зачем, если можно прочитать буквально одной строкой.
fread(arr, sizeof(struct member), arr_len, fp);
И все. Правда есть ещё странная запись. Давайте перепишем запись как нужно.
fwrite(arr, sizeof(struct member), arr_len, fp);
и никаких циклов. Мало того, что это быстрее, так ещё и понятнее.
В результате функция превратилась вот в такое
void output_database() {
int record_size = sizeof(struct member);
FILE* fp = fopen("database.bin", "rb");
// возьмем размер массива
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
if (sz % record_size != 0)
{
// упс
fclose(fp);
}
int arr_len = sz / record_size;
rewind(fp);
struct member* arr = malloc(sz);
fread(arr, record_size, arr_len, fp);
// вывод
for (int i = 0; i < arr_len; i++)
printf("%s %s %s %d %d %d\n", arr[i].full_name, arr[i].club, arr[i].role, arr[i].age, arr[i].matches, arr[i].goals_scored);
fclose(fp);
free(arr);
}
В коде ещё куча страшного, но это тема отдельных разговоров. Например, сигнатуру этой функции void number_input(char str[256], int* p) лучше исправить где то на такую
void number_input(char* str, int* p)