简体   繁体   English

使用C的struct分配内存错误

[英]Allocation memory error with use struct for c

I wrote a code for managing a library; 我写了一个管理图书馆的代码。 the compilation is done but during the simulation I obtained an Allocation error (case2) and I don't know why. 编译已经完成,但是在仿真过程中我遇到了Allocation error (case2) ,我不知道为什么。 The first case works correctly but if I entered more than one name in the first case, the second case doesn't work. 第一种情况可以正常工作,但是如果我在第一种情况下输入了多个名称,则第二种情况不起作用。

What did I do wrong? 我做错了什么? I hope I was clear enough. 我希望我足够清楚。

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;
}

I guess the problem is with scanf reading a string only until a separator, in your case - a whitespace separating multiple names entered. 我想问题是scanf只读取一个字符串,直到出现分隔符为止(在您的情况下,该分隔符是分隔输入的多个名称的空格)。 The characters after separator remain in the input buffer and get immediately processed by other calls to scanf . 分隔符之后的字符保留在输入缓冲区中,并由其他对scanf调用立即处理。

You should consider using getline for reading name(s) and checking return values from other calls to scanf . 您应该考虑使用getline读取名称并检查其他对scanf调用的返回值。

Your code to reallocate the arrays is incorrect. 您用于重新分配数组的代码不正确。 You do not allocate enough room for the new array sizes. 您没有为新的阵列大小分配足够的空间。 When you reallocate these arrays, you pass the size of a single element, therefore the array still has a length of 1 instead of subs_num + 1 . 重新分配这些数组时,将传递单个元素的大小,因此该数组的长度仍为1而不是subs_num + 1 The size passed to realloc should be the number of elements times the size of a single element in bytes. 传递给realloc的大小应为元素数乘以单个元素的大小(以字节为单位)。

Initialize subs_library and books to NULL and change your array reallocations: subs_librarybooks初始化为NULL并更改数组重新分配:

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

Into this: 变成这个:

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

And do the same for books , change: 并对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));
    }

To this: 对此:

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

Or simpler: 或更简单:

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

Your reallocation realloc(books, sizeof(char *)) only allocates the size of one pointer char * , not the size of the enlarged array that you need: 重新分配realloc(books, sizeof(char *))仅分配一个指针char *的大小,而不分配您需要的扩大数组的大小:

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

You need to multiply the size of a pointer ( char * ) by the number of books you plan on storing in the array. 您需要将指针( char * )的大小乘以您计划存储在数组中的书籍数量。 You maintain the number of books in books_num . 您可以在books_num维护书籍books_num

As Joachim Pileborg said, with every allocation/reallocation, you want this to be one more than the current size. 正如Joachim Pileborg所说,对于每个分配/重新分配,您都希望它比当前大小多一。 For the first allocation ( malloc() ), you want to allocate for one book, which is 1 times sizeof(char *) . 对于第一个分配( malloc() ),您要分配一本书,它是sizeof(char *) 1倍。 This happens to be equivalent to your existing code, which is fine. 这恰好等同于您现有的代码,这很好。 But the reallocation ( realloc() ) reallocates for the same size every time (only enough for one pointer), so you're not enlarging the allocation. 但是重新分配( realloc() )每次都以相同的大小重新分配(仅足以容纳一个指针),因此您无需扩大分配。 You need to multiply the size required for one pointer ( sizeof(char *) ) by the number of pointers you want, which is books_num + 1 . 您需要将一个指针所需的大小( sizeof(char *) )乘以所需的指针数,即books_num + 1 As in Joachim's answer, this is 正如约阿希姆的回答,这是

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

This will enlarge the allocation of the array books by one more pointer. 这将使数组books的分配再增加一个指针。 Then, on the next line you correctly allocate a string of size 80. 然后,在下一行中,正确分配大小为80的字符串。

Your subs_library has the same reallocation issue. 您的subs_library具有相同的重新分配问题。

Less frequent reallocation 重新分配的频率降低

You might want to resize an allocation less frequently. 您可能希望减少分配大小的频率。 In this situation, you are reallocating every time you add an entry. 在这种情况下,您每次添加条目都将重新分配。 One simple technique to reduce the number of reallocations is to double the allocation size every time it gets full. 减少重新分配数量的一种简单技术是,每次分配满时将分配大小加倍。 But you have to maintain the allocation size (capacity) and check for it whenever you add something. 但是,您必须保持分配大小(容量),并在添加任何内容时进行检查。 For example: 例如:

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

Then the initial allocation is 那么初始分配是

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

And to add some char *new_item to the buffer 并向buffer添加一些char *new_item

/* 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;

Notice that I have used sizeof(*buffer) instead of sizeof(char *) . 请注意,我已经使用sizeof(*buffer)而不是sizeof(char *) This makes the compiler figure out what the type and size is. 这使编译器可以确定类型和大小。 That way, if I change the type of buffer for some reason, I don't have to change more places in the code. 这样,如果由于某种原因更改了buffer的类型,则不必在代码中更改更多的位置。 Another thing that I left out for brevity is that you should always check the return values to make sure they are not NULL . 为简便起见,我省去的另一件事是,您应始终检查返回值以确保它们不是NULL

The problem is your reallocation calls. 问题是您的重新分配电话。 For example you do 例如你

realloc(books,sizeof(char*))

This reallocates the memory pointed to be books to be one pointer to character in size, which is exactly what you already have. 这会将指向books的内存重新分配为一个指向字符大小的指针,而这正是您已经拥有的大小。 This will lead you to index out of bounds of the allocated memory, something which is undefined behavior . 这将导致您索引已分配内存的边界 ,这是未定义的行为

If you want to allocate more than one element you need to multiply the base type size with the number of elements you want to allocate, eg 如果你想超过一个元素分配你需要要分配的元素个数,例如乘以基本类型大小

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM