[英]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 值
product_t *newdatabase = malloc(newSize * sizeof *newdatabase);
釋放數據庫指針后不能引用它。
為什么只為 i >= newSize 釋放 database[i].product? 大概您想釋放所有這些(但請參閱下面的 realloc 和代碼示例)。
考慮使用realloc()
來調整數組的大小。 如果成功,您的舊版本將被保留。
讓客戶端記住以前的數據庫大小很笨拙,因此請考慮創建一個結構來保存數據和大小。
當您分配固定長度的字符串時,在類型中對其進行編碼會更容易。 使用常量 ( PRODUCT_LEN
) 而不是硬編碼魔法值。
0
字節的malloc()
/ realloc()
是實現定義的。 我的實現返回 NULL,因此將其作為特例處理。
malloc()
不保證初始化 memory 所以要么在之后初始化它,要么使用 calloc。
我們不在 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.