Почему я получаю ошибку сегмента в этой C программе? Работа с fscanf и printf - PullRequest
1 голос
/ 22 апреля 2020

Я перепробовал множество вещей, относящихся к fscanf и функциям печати, функция Fight находится в другом файле и имеет этот прототип

void Fight( char * combatant1, int ac1, int hp1, int hitbonus1, int damagebonus1, char * combatant2, int ac2, int hp2, int hitbonus2, int damagebonus2);

Но я не думаю, что вот откуда исходит ошибка. Я все еще получаю ошибку сегмента, когда строка закомментирована. Кто-нибудь может мне с этим помочь? Файлы данных выглядят так:

Имя ## ## ## ##

Вот мой код

void printInfo(FILE *f1, FILE *f2){
    char* name1;
    char* name2;
    int armor1;
    int armor2;
    int hp1;
    int hp2;
    int hb1;
    int hb2;
    int db1;
    int db2;
    fscanf(f1, "%s %d %d %d %d", name1, &armor1,&hp1,&hb1,&db1);
    printf("\nName=%s, Armor=%d, Hit Points=%d, Hit Bonus=%d, Damage Bonus=%d", name1,armor1,hp1,hb1,db1);
    fscanf(f2, "%s %d %d %d %d", name2, &armor2,&hp2,&hb2,&db2);
    printf("\nName=%s, Armor=%d, Hit Points=%d, Hit Bonus=%d, Damage Bonus=%d", name2,armor2,hp2,hb2,db2);
    //Fight(name1,armor1,hp1,hb1,db1,name2,armor2,hp2,hb2,db2);
}

1 Ответ

5 голосов
/ 22 апреля 2020

Каждый указатель после его объявления должен быть инициализирован по действительному адресу. И этот адрес, чтобы быть действительным, должен быть выделен. Ваши указатели

char* name1;
char* name2;

фактически не указывают на допустимые области памяти. Таким образом, когда fscanf пытается записать имена по адресам, указанным name1 и name2, он фактически записывает неверные адреса, вызывая ошибку сегментации.

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

char name1[50];
char name2[50];

или динамически

char* name1 =  malloc(50);// That is (50*sizeof char). But sizeof(char) is 1.
char* name2 =  malloc(50);

В этом примере 50 байтов были выделены как максимальный размер строка. Чтобы сохранить в них не более 49 символов (один символ требуется для ограничителя строки), вы можете использовать правильный формат строки в fscanf. Например,

fscanf(f1, "%49s %d %d %d %d", name1, &armor1,&hp1,&hb1,&db1);

Структурированное программирование

Хотя это не связано с вашей проблемой, я замечаю, как ваша функция Fight имеет 10 параметров:

void Fight( char * combatant1, int ac1, int hp1, int hitbonus1, int damagebonus1, char * combatant2, int ac2, int hp2, int hitbonus2, int damagebonus2);

Определение функции со слишком большим количеством параметров иногда может привести к неэффективности с точки зрения потребления стека (особенно во встроенных системах, где только первые 3 или 4 параметра используют регистры процессора, а все остальные параметры копируются в стек).

Решение - структурированное программирование. В вашем случае у вас есть ровно 2 бойца, каждый из которых имеет 5 свойств. Таким образом, определение структуры бойца следующим образом:

typedef struct
{
    char name[50];
    int ac;
    int hp;
    int hitbonus;
    int damagebonus;
} Combatant_t;

будет просто соответствовать интерфейсу функции Fight(), так как вы можете просто передать ему два указателя на бойцов. Его подпись станет:

void Fight(Combatant_t *cb1, Combatant_t *cb2);

Ваш printInfo() станет:

void printInfo(FILE *f1, FILE *f2)
{
    Combatant_t *comb1 = malloc( sizeof(Combatant_t) );
    Combatant_t *comb2 = malloc( sizeof(Combatant_t) );
    /* Note: malloc might fail. Remember to manage that scenario */ 

    /* memset to 0 newly allocated structs */
    memset( comb1, 0, sizeof(*comb1) );
    memset( comb2, 0, sizeof(*comb2) );

    fscanf(f1, "%49s %d %d %d %d", comb1->name, &(comb1->ac), &(comb1->hp), &(comb1->hitbonus), &(comb1->damagebonus));
    printf("\nName=%s, Armor=%d, Hit Points=%d, Hit Bonus=%d, Damage Bonus=%d", comb1->name, comb1->ac, comb1->hp, comb1->hitbonus, comb1->damagebonus);
    fscanf(f1, "%49s %d %d %d %d", comb2->name, &(comb2->ac), &(comb2->hp), &(comb2->hitbonus), &(comb2->damagebonus));
    printf("\nName=%s, Armor=%d, Hit Points=%d, Hit Bonus=%d, Damage Bonus=%d", comb2->name, comb2->ac, comb2->hp, comb2->hitbonus, comb2->damagebonus);

    //Fight( comb1, comb2);

     /* Remember to free comb1 an comb2 as soon as you don't need them anymore */
}
...