我写了一个管理图书馆的代码;编译完成但在模拟过程中我获得了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;
}
答案 0 :(得分:1)
我想问题是scanf
只读取一个字符串,直到一个分隔符,在你的情况下 - 一个空格分隔多个输入的名字。分隔符后面的字符保留在输入缓冲区中,并通过对scanf
的其他调用立即处理。
您应该考虑使用getline
来读取名称,并检查来自scanf
的其他来电的返回值。
答案 1 :(得分:1)
重新分配数组的代码不正确。您没有为新阵列大小分配足够的空间。重新分配这些数组时,会传递单个元素的大小,因此数组的长度仍为1而不是subs_num + 1
。传递给realloc
的大小应该是元素的数量乘以单个元素的大小(以字节为单位)。
将subs_library
和books
初始化为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);
答案 2 :(得分:0)
您的重新分配realloc(books, sizeof(char *))
仅分配一个指针char *
的大小,而不是您需要的放大数组的大小:
books=realloc(books,sizeof(char*));
您需要将指针(char *
)的大小乘以您计划存储在数组中的书籍数量。您保留了books_num
中的图书数量。
正如Joachim Pileborg所说,对于每次分配/重新分配,您希望它比当前大小多一个。对于第一次分配(malloc()
),您希望为一本书分配,这是sizeof(char *)
的1倍。这恰好等同于您现有的代码,这很好。但重新分配(realloc()
)每次重新分配相同的大小(仅对一个指针足够),因此您不会扩大分配。您需要将一个指针(sizeof(char *)
)所需的大小乘以所需的指针数,即books_num + 1
。正如约阿希姆的回答一样,这是
books = realloc(books, (books_num + 1)*sizeof(char *));
这会将数组books
的分配扩大一个指针。然后,在下一行,您正确分配一个大小为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
。
答案 3 :(得分:0)
问题是你的重新分配电话。例如,你做
realloc(books,sizeof(char*))
这会将指向books
的内存重新分配为一个指向大小字符的指针,这正是您已经拥有的内容。这将引导您索引已分配内存的越界,这是未定义的行为。
如果要分配多于一个元素,则需要将基本类型大小与要分配的元素数相乘,例如。
realloc(books, (books_num + 1) * sizeof(char *))