2016-04-27 13 views
1

ここに何か不足していますが、realloc()は構造体の動的配列を縮小しようとすると無効なサイズで失敗します。コードから非必須機能をトリムして投稿する:縮小時のreallocが失敗する

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

char const file_name[] = "animals.dat"; 
typedef enum { 
    false, true } bool; 
typedef struct { 
    char month; 
    char day; 
    short year; 
} date; 
typedef struct { 
    bool parvo_vacc; 
    bool fip_vacc; 
    bool rabies_vacc; 
    bool has_mc; 
    bool worm_vacc; 
} md_history; 
typedef struct { 
    int id; 
    char age; 
    char name[25]; 
    char description[50]; 
    md_history medical; 
    date intake_date; 
    date adopt_date; 
} animal; 
void lookup(animal* list, int size); 
int compare(const void* this, const void* that); 
void sort(animal* list, int size); 
//this brings the new name back with it, since it isnt saved correctly 
//in the new animal 
animal* add(char* name); 
void del(animal* list, int size); 
void print_results(animal** results, int size); 
void print_animal(animal* print); 
void swap(animal* this, animal* that); 
int main(int argc, char **argv) 
{ 
    FILE* readfile = fopen(file_name, "r"); 
    if (readfile == NULL) 
    { 
     printf("Error file not found: %s\n", file_name); 
    } 
    //read data using fread(), keeping track of the number 
    //of bytes missed 
    int num_animals = 0; 
    fread(&num_animals, sizeof(int), 1, readfile); 
    animal* animal_list = (animal*) calloc(num_animals, sizeof(animal)); 
    int errnum = num_animals - (fread(animal_list, 
     sizeof(animal), num_animals, readfile)); 
    if (errnum > 0) 
    { 
     printf("Read encountered %d errors", errnum); 
    } 
    fclose(readfile); 
    char c; 
    char* name = malloc(sizeof(char) * 25); 
    //switch statements dont allow declarations for whatever reason 
    int x; 
    while(c != 'q') 
    { 
     printf("Options: (l)ookup (s)ort (a)dd (d)elete (p)rint (q)uit (e)dit\n"); 
     scanf(" %c", &c); 
     switch (c) 
     { 
      case 'l': 
      lookup(animal_list, num_animals); 
      break; 
      case 's': 
      sort(animal_list, num_animals); 
      break; 
      case 'p': 
      for (x = 0; x < num_animals; x++) 
      { 
       print_animal(&animal_list[x]); 
      } 
      break; 
      case 'a': 
      //after dealing with lots of iostream errors trying to 
      //set the name field in add(), i decided to just return 
      //the new name to here and strcpy it 
      animal_list = realloc(animal_list, sizeof(animal) * (num_animals + 1)); 
      swap(&animal_list[num_animals], add(name)); 
      strcpy(animal_list[num_animals].name, name); 
      num_animals++; 
      //memory leak here, since switch statements dont allow 
      //declarations, i cant save the new animal pointer to a temp 
      //var so it can be deleted 
      break; 
      case 'd': 
      del(animal_list, num_animals); 
      num_animals--; 
      break; 
     } 
    } 
    return 0; 
} 

void swap(animal* this, animal* that) 
{ 
    animal temp; 
    temp.id = this->id; 
    strcpy(temp.name, this->name); 
    temp.age = this->age; 
    strcpy(temp.description, this->description); 
    temp.medical.fip_vacc = this->medical.fip_vacc; 
    temp.medical.has_mc = this->medical.has_mc; 
    temp.medical.parvo_vacc = this->medical.parvo_vacc; 
    temp.medical.rabies_vacc = this->medical.rabies_vacc; 
    temp.medical.worm_vacc = this->medical.worm_vacc; 
    temp.intake_date.day = this->intake_date.day; 
    temp.intake_date.month = this->intake_date.month; 
    temp.intake_date.year = this->intake_date.year; 
    temp.adopt_date.day = this->adopt_date.day; 
    temp.adopt_date.month = this->adopt_date.month; 
    temp.adopt_date.year = this->adopt_date.year; 

    this->id = that->id; 
    strcpy(this->name, that->name); 
    this->age = that->age; 
    strcpy(this->description, that->description); 
    this->medical.fip_vacc = that->medical.fip_vacc; 
    this->medical.has_mc = that->medical.has_mc; 
    this->medical.parvo_vacc = that->medical.parvo_vacc; 
    this->medical.rabies_vacc = that->medical.rabies_vacc; 
    this->medical.worm_vacc = that->medical.worm_vacc; 
    this->intake_date.day = that->intake_date.day; 
    this->intake_date.month = that->intake_date.month; 
    this->intake_date.year = that->intake_date.year; 
    this->adopt_date.day = that->adopt_date.day; 
    this->adopt_date.month = that->adopt_date.month; 
    this->adopt_date.year = that->adopt_date.year; 

    that->id = temp.id; 
    strcpy(that->name, temp.name); 
    that->age = temp.age; 
    strcpy(that->description, temp.description); 
    that->medical.fip_vacc = temp.medical.fip_vacc; 
    that->medical.has_mc = temp.medical.has_mc; 
    that->medical.parvo_vacc = temp.medical.parvo_vacc; 
    that->medical.rabies_vacc = temp.medical.rabies_vacc; 
    that->medical.worm_vacc = temp.medical.worm_vacc; 
    that->intake_date.day = temp.intake_date.day; 
    that->intake_date.month = temp.intake_date.month; 
    that->intake_date.year = temp.intake_date.year; 
    that->adopt_date.day = temp.adopt_date.day; 
    that->adopt_date.month = temp.adopt_date.month; 
    that->adopt_date.year = temp.adopt_date.year; 
} 

void del(animal* list, int size) 
{ 
    printf("Delete by: (n)ame (i)d\n"); 
    char c; 
    while (getchar() != '\n'); 
    scanf("%c", &c); 
    animal* to_delete = NULL; 
    if (c == 'n') 
    { 
     printf("Enter name to delete: "); 
     char to_search[25]; 
     while (getchar() != '\n'); 
     scanf(" %s", to_search); 
     int x; 
     for (x = 0; x < size; x++) 
     { 
      if (strcmp(to_search, list[x].name) == 0) 
      { 
       to_delete = &list[x]; 
      } 
     } 
    } 
    if (c == 'i') 
    { 
     printf("Enter ID to delete: "); 
     int to_search; 
     while (getchar() != '\n'); 
     scanf("%d", &to_search); 
     int x; 
     for (x = 0; x < size; x++) 
     { 
      if (to_search == list[x].id) 
      { 
       to_delete = &list[x]; 
      } 
     } 
    } 
    swap(to_delete, &list[size); 
    list = realloc(list, sizeof(animal) * (size - 1)); //fails right here 
} 

私は配列を間違って縮小していますか?私は(のreallocを知っている)、それはとても見事にないので失敗し、中止し、このメッセージを与える:

*** Error in `./final': realloc(): invalid next size: 0x0000000000c11250 *** 
======= Backtrace: ========= 
/lib/x86_64-linux-gnu/libc.so.6(+0x77725)[0x7f6ae72ba725] 
/lib/x86_64-linux-gnu/libc.so.6(+0x82bfa)[0x7f6ae72c5bfa] 
/lib/x86_64-linux-gnu/libc.so.6(+0x85179)[0x7f6ae72c8179] 
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7f6ae72c6e6f] 
./final[0x401d3e] 
./final[0x400b82] 
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f6ae7263830] 
./final[0x400849] 
======= Memory map: ======== 
00400000-00403000 r-xp 00000000 08:01 3146140       /home/destrovel/cppwork/final 
00602000-00603000 r--p 00002000 08:01 3146140       /home/destrovel/cppwork/final 
00603000-00604000 rw-p 00003000 08:01 3146140       /home/destrovel/cppwork/final 
00c10000-00c31000 rw-p 00000000 00:00 0         [heap] 
7f6ae0000000-7f6ae0021000 rw-p 00000000 00:00 0 
7f6ae0021000-7f6ae4000000 ---p 00000000 00:00 0 
7f6ae702d000-7f6ae7043000 r-xp 00000000 08:01 1069105     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f6ae7043000-7f6ae7242000 ---p 00016000 08:01 1069105     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f6ae7242000-7f6ae7243000 rw-p 00015000 08:01 1069105     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f6ae7243000-7f6ae7403000 r-xp 00000000 08:01 1049974     /lib/x86_64-linux-gnu/libc-2.23.so 
7f6ae7403000-7f6ae7602000 ---p 001c0000 08:01 1049974     /lib/x86_64-linux-gnu/libc-2.23.so 
7f6ae7602000-7f6ae7606000 r--p 001bf000 08:01 1049974     /lib/x86_64-linux-gnu/libc-2.23.so 
7f6ae7606000-7f6ae7608000 rw-p 001c3000 08:01 1049974     /lib/x86_64-linux-gnu/libc-2.23.so 
7f6ae7608000-7f6ae760c000 rw-p 00000000 00:00 0 
7f6ae760c000-7f6ae7632000 r-xp 00000000 08:01 1049970     /lib/x86_64-linux-gnu/ld-2.23.so 
7f6ae77f9000-7f6ae77fc000 rw-p 00000000 00:00 0 
7f6ae782e000-7f6ae7831000 rw-p 00000000 00:00 0 
7f6ae7831000-7f6ae7832000 r--p 00025000 08:01 1049970     /lib/x86_64-linux-gnu/ld-2.23.so 
7f6ae7832000-7f6ae7833000 rw-p 00026000 08:01 1049970     /lib/x86_64-linux-gnu/ld-2.23.so 
7f6ae7833000-7f6ae7834000 rw-p 00000000 00:00 0 
7ffd8a23b000-7ffd8a25c000 rw-p 00000000 00:00 0       [stack] 
7ffd8a331000-7ffd8a333000 r--p 00000000 00:00 0       [vvar] 
7ffd8a333000-7ffd8a335000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 
Aborted (core dumped) 

私のように、呼び出し元の関数にリストを渡す機能を書き直しイムかなりここ

EDITは困惑2501によって提案されたが、それはその行を評価する際に、その同じ場所で

を中止プログラムはまた、GDBはこのを与える変更didntは:

realloc: Assertion `ptr == alloc_last_block' failed! 

EDIT 2:後方に私はヒープを破壊するswap()をデバッグしていますが、なぜその理由が分かりません。私が示唆したようにスワップ()を書き直し、しかしのrealloc()のrealloc(ながら直後失敗)が直前

+0

ためswap(to_delete, &list[size - 1])

万歳する必要swap(to_delete, &list[size])

は、あなたはそれが失敗したとき、あなたがrealloc' 'に渡しているどのようなサイズを確認するためにチェックすることがありますか? –

+1

'realloc()'がどうやって失敗したのですか? 'NULL'を返すことは、それが失敗したことを意味しません。 'realloc()'は、0の割り当てとメモリ不足の場合にNULLを返します。 – chux

+0

このようにreallocを呼び出さないでください。 reallocが失敗し、元のポインタを失ったときにリストを上書きしています。 – bruceg

答えて

2

変数がC

の値によって渡されない機能delに渡されたポインタlistが変更され関数内ではreallocを実行しますが、関数外のポインタは変更されません。原因は未定義の動作です。

ポインタanimal_listは、ここに渡されます。そのポインタlist

del(animal_list, num_animals);  

コピーが、ここでは変更されます。

list = realloc(list, sizeof(animal) * (size - 1)); 

元ポインタanimal_listは変わりません。

これを解決するには、新しいポインタリストの値を返します。

+0

成功を検証する前に 'realloc'の戻り値を代入するために' tmp'変数を使用しないことで、メモリリークのために自分自身を設定することに言及することは重要です。 'realloc'が失敗した場合、' NULL'を返し、 'list'によって最初に指し示されたメモリのブロックを' free'する能力を失いました。 –

関連する問題