使用struct for c的分配内存错误

我写了一个管理库的代码; 编译完成但在模拟过程中我获得了一个Allocation error (case2) ,我不知道为什么。 第一种情况正常,但如果我在第一种情况下输入了多个名称,则第二种情况不起作用。

我做错了什么? 我希望我足够清楚。

 typedef struct { char name[80]; char **books; int books_num; } Subscription; int main() { // Variables declaration: int option = 0, subs_num = 0, i = 0, books_num = 0; Subscription *subs_library; char **books; char subs_new_name[80], book_new_name[80]; printf("Choose an option\n"); do { scanf("%d", &option); switch (option) { case 1: printf("Case 1: enter a new name\n"); scanf("%s", subs_new_name); if (subs_num == 0) { subs_library = malloc(sizeof(Subscription)); } else { subs_library = realloc(subs_library, sizeof(Subscription)); } strcpy(subs_library[subs_num].name, subs_new_name); subs_library[subs_num].books_num = 0; subs_num++; printf("ADDED\n"); break; case 2: printf("Case 2: enter the book name\n"); scanf("%s", book_new_name); if (books_num == 0) { books = malloc(sizeof(char*)); books[books_num] = malloc(80 * sizeof(char)); } else { books = realloc(books, sizeof(char*)); books[books_num] = malloc(80 * sizeof(char)); } if (books[books_num] == NULL) { printf("Allocation Error\n"); exit(1); } strcpy(books[books_num], book_new_name); books_num++; printf("ADDED\n"); break; } } while (option != 7); return 0; } 

您重新分配数组的代码不正确。 您没有为新arrays大小分配足够的空间。 重新分配这些数组时,传递单个元素的大小,因此数组的长度仍为1而不是subs_num + 1 。 传递给realloc的大小应该是元素的数量乘以单个元素的大小(以字节为单位)。

subs_librarybooks初始化为NULL并更改数组重新分配:

  if (subs_num == 0) { subs_library = malloc(sizeof(Subscription)); } else { subs_library = realloc(subs_library, sizeof(Subscription)); } 

进入这个:

  subs_library = realloc(subs_library, (subs_num + 1) * sizeof(*subs_library)); 

并为books做同样的事情,改变:

  if (books_num == 0) { books = malloc(sizeof(char*)); books[books_num] = malloc(80 * sizeof(char)); } else { books = realloc(books, sizeof(char*)); books[books_num] = malloc(80 * sizeof(char)); } 

对此:

  books = realloc(books, (books_num + 1) * sizeof(*books)); books[books_num] = malloc(80 * sizeof(char)); 

或者更简单:

  books = realloc(books, (books_num + 1) * sizeof(*books)); books[books_num] = strdup(book_new_name); 

我想问题是scanf只读取一个字符串直到一个分隔符,在你的情况下 – 一个空格分隔多个输入的名字。 分隔符后的字符保留在输入缓冲区中,并由其他对scanf调用立即处理。

您应该考虑使用getline读取名称并检查其他对scanf调用的返回值。

问题是你的重新分配电话。 比如你做的

 realloc(books,sizeof(char*)) 

这将指向books的内存重新分配为一个指向字符大小的指针,这正是您已经拥有的内容。 这将导致您索引超出已分配内存的范围 ,这是未定义的行为

如果要分配多个元素,则需要将基本类型大小与要分配的元素数相乘,例如

 realloc(books, (books_num + 1) * sizeof(char *)) 

您的重新分配realloc(books, sizeof(char *))仅分配一个指针char *的大小,而不是您需要的放大数组的大小:

  books=realloc(books,sizeof(char*)); 

您需要将指针( char * )的大小乘以您计划存储在数组中的书籍数量。 您在books_num保留了书籍books_num

正如Joachim Pileborg所说,对于每次分配/重新分配,您希望它比当前大小多一个。 对于第一个分配( malloc() ),您希望为一本书分配,这是sizeof(char *) 1倍。 这碰巧等同于您现有的代码,这很好。 但重新分配( realloc() )每次重新分配相同的大小(仅对一个指针足够),因此您不会扩大分配。 您需要将一个指针所需的大小( sizeof(char *) )乘以所需的指针数,即books_num + 1 。 正如约阿希姆的回答一样,这是

  books = realloc(books, (books_num + 1)*sizeof(char *)); 

这将通过一个指针扩大arraysbooks的分配。 然后,在下一行,您正确分配一个大小为80的字符串。

您的subs_library具有相同的重新分配问题。

重新分配的频率较低

您可能希望不那么频繁地调整分配大小。 在这种情况下,每次添加条目时都要重新分配。 减少重新分配数量的一种简单技术是每次填充时将分配大小加倍。 但是你必须保持分配大小(容量)并在添加内容时检查它。 例如:

 char **buffer; /* buffer of pointers to char */ int capacity = 1; /* number of elements allocated for */ int size = 0; /* number of elements actually used */ 

然后初始分配是

 /* Initial allocation */ buffer = malloc(capacity*sizeof(*buffer)); 

并将一些char *new_item添加到buffer

 /* When adding an element */ if ( size == capacity ) { /* Double allocation every time */ capacity *= 2; /* Reallocate the buffer to new capacity */ realloc(buffer, capacity*sizeof(*buffer)); } /* Item will fit, add to buffer */ buffer[size++] = new_item; 

请注意,我使用了sizeof(*buffer)而不是sizeof(char *) 。 这使得编译器可以确定类型和大小。 这样,如果由于某种原因改变buffer的类型,我不必更改代码中的更多位置。 我为了简洁而遗漏的另一件事是你应该总是检查返回值以确保它们不是NULL