簡體   English   中英

使用C的struct分配內存錯誤

[英]Allocation memory error with use 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;
}

我想問題是scanf只讀取一個字符串,直到出現分隔符為止(在您的情況下,該分隔符是分隔輸入的多個名稱的空格)。 分隔符之后的字符保留在輸入緩沖區中,並由其他對scanf調用立即處理。

您應該考慮使用getline讀取名稱並檢查其他對scanf調用的返回值。

您用於重新分配數組的代碼不正確。 您沒有為新的陣列大小分配足夠的空間。 重新分配這些數組時,將傳遞單個元素的大小,因此該數組的長度仍為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);

重新分配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 *));

這將使數組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));

並向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;

請注意,我已經使用sizeof(*buffer)而不是sizeof(char *) 這使編譯器可以確定類型和大小。 這樣,如果由於某種原因更改了buffer的類型,則不必在代碼中更改更多的位置。 為簡便起見,我省去的另一件事是,您應始終檢查返回值以確保它們不是NULL

問題是您的重新分配電話。 例如你

realloc(books,sizeof(char*))

這會將指向books的內存重新分配為一個指向字符大小的指針,而這正是您已經擁有的大小。 這將導致您索引已分配內存的邊界 ,這是未定義的行為

如果你想超過一個元素分配你需要要分配的元素個數,例如乘以基本類型大小

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM