簡體   English   中英

動態大小數據庫中的 Memory 泄漏

[英]Memory leakage in a dynamic size database

我嘗試創建一個動態數據庫,用戶在其中輸入他們想要創建的數據庫的大小,但是在輸入一定數量的大小后我得到了 memory 泄漏並且我不確定我做錯了什么因為我應該釋放所有東西。

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

typedef struct _product_t
{
    char *product;
    float price;
} product_t;

product_t *newDatabase(product_t *database, int *dbSize, int newSize)
{
    product_t *newdatabase = (product_t *)malloc(sizeof(*newdatabase) * newSize);

    if (newSize < *dbSize)
    {
        for (int i = 0; i <= newSize; i++)
        {
            if (database[i].product != NULL)
            {
                free(database[i].product);
            }
        }
    }
    else
    {
        for (int i = 0; i <= *dbSize; i++)
        {
            if (database[i].product != NULL)
            {
                free(database[i].product);
            }
        }
    }
    for (int i = *dbSize; i < newSize; i++)
    {
        // newdatabase[i].product = (char*)malloc(sizeof(char)*100);
        newdatabase[i].product = NULL;
        newdatabase[i].price = -1;
    }

    *dbSize = newSize;
    free(database);
    return newdatabase;
}
int main(void)
{
    product_t *database = NULL;
    int dbSize = 0;
    char cmd;
    do
    {
        printf("Command?");
        scanf(" %c", &cmd);
        switch (cmd)
        {

        case 'q':
            printf("Bye!");

            break;
        case 'n':
            printf("Size? ");
            int newSize2 = 0;
            scanf("%d", &newSize2);
            if (newSize2 < 0)
            {
                printf("Must be larger than 0");
                break;
            }
            else
            {
                database = newDatabase(database, &dbSize, newSize2);
                break;
            }
        default:
            printf("Unkown command '%c'\n", cmd);
        }
    } while (cmd != 'q');

    return 0;
}

#edit number 3 我選擇刪除產品指針的 malloc,並決定使用 if 和 else 語句釋放所有非 NULL 值

  1. 對於第一個 malloc,您將 newSize 指針分配給 product_t,但您想要分配它們的數組:
    product_t *newdatabase = malloc(newSize * sizeof *newdatabase);
  1. 釋放數據庫指針后不能引用它。

  2. 為什么只為 i >= newSize 釋放 database[i].product? 大概您想釋放所有這些(但請參閱下面的 realloc 和代碼示例)。

  3. 考慮使用realloc()來調整數組的大小。 如果成功,您的舊版本將被保留。

  4. 讓客戶端記住以前的數據庫大小很笨拙,因此請考慮創建一個結構來保存數據和大小。

  5. 當您分配固定長度的字符串時,在類型中對其進行編碼會更容易。 使用常量 ( PRODUCT_LEN ) 而不是硬編碼魔法值。

  6. 0字節的malloc() / realloc()是實現定義的。 我的實現返回 NULL,因此將其作為特例處理。

  7. malloc()不保證初始化 memory 所以要么在之后初始化它,要么使用 calloc。

  8. 我們不在 C 中強制轉換 void *(malloc 的結果)。

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

#define PRODUCT_LEN 100

typedef struct {
    size_t size;
    char (*products)[PRODUCT_LEN];
    float *prices;
} database;

database *newDatabase() {
    return calloc(1, sizeof(database));
}

database *resizeDatabase(database *db, size_t newSize) {
    if(!db) return NULL;
    database tmp;
    tmp.products = realloc(db->products, newSize * sizeof *db->products);
    if(newSize && !tmp.products) {
        printf("realloc of products failed\n");
        // handle error
        return NULL;
    }
    db->products = tmp.products;
    tmp.prices = realloc(db->prices, newSize * sizeof *db->prices);
    if(newSize && !tmp.prices) {
        printf("realloc of prices failed\n");
        // handle error; we successfully resize products but failed
        // to resize price.  So we may need to shrink products but
        // what if that now fails?
        return NULL;
    }
    db->prices = tmp.prices;
    for(size_t i = db->size; i < newSize; i++) {
        db->products[i][0] = '\0';
        db->prices[i] = -1;
    }
    db->size = newSize;
    return db;
}

void freeDatabase(database *db) {
    if(!db) return;
    free(db->products);
    free(db->prices);
    free(db);
}

int main(void) {
    database *db = newDatabase();
    size_t tests[] = { 0, 1, 2, 1, 0 };
    size_t tests_len = sizeof tests / sizeof *tests;
    for(size_t i = 0; i < tests_len; i++) {
        database *newDb = resizeDatabase(db, tests[i]);
        if(!newDb) {
            printf("resizefailed %zu\n", tests[i]);
            return 1;

        }
        db = newDb;
    }
    freeDatabase(db);
}

這是 valgrind 運行:

==533946== HEAP SUMMARY:
==533946==     in use at exit: 0 bytes in 0 blocks
==533946==   total heap usage: 9 allocs, 9 frees, 440 bytes allocated
==533946== 
==533946== All heap blocks were freed -- no leaks are possible

要比較的較新版本

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


            typedef struct _product_t {
                char *product;
                float price;
            } product_t;


            product_t *newDatabase(product_t *database, int *dbSize, int newSize) {

    for (int i = 0; i < *dbSize; i++) {
        if (database[i].product != NULL) {
            free(database[i].product);
        }
   }
// Free the previous memory allocated for the database


                // Free the previous memory allocated for the database
                free(database);

                // Allocate new space for newSize products on the heap
                database = (product_t*) malloc(newSize * sizeof(product_t));

                // Initialize all products in the database with NULL and -1
                for (int i = 0; i < newSize; i++) {
                    database[i].product = NULL;
                    database[i].price = -1;
                }

                // Update the database size
                *dbSize = newSize;

                // Return the pointer to the new database
                return database;
            }
            int main(void) {
                product_t *database = NULL;
                int dbSize = 0;
                char cmd;
                do{
                    printf("Command?");
                    scanf(" %c", &cmd);
                    switch (cmd) {

                    case 'q':
                        printf("Bye!");

                        break;
                    case 'n':
                        printf("Size? ");
                        int newSize2 = 0;
                        scanf("%d", &newSize2);
                        if(newSize2 < 0) {
                            printf("Must be larger than 0");
                            break;
                        }
                        else{
                        database = newDatabase(database, &dbSize, newSize2);
                        break;
                        }
                    default:
                        printf("Unkown command '%c'\n",cmd);
                        }
                }while(cmd != 'q');
                return 0;

            }

暫無
暫無

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

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