我已經在 C 中為原始型別實作了一個偽通用動態陣列。它將列舉常量作為每個型別的識別符號 - INT, LONG_INT, DECIMAL, CHAR。主結構list有一個成員_assets,它是一個void指標(具有抽象級別)。這個void指標在 C 檔案實作中被型別轉換為另一個結構(這是容器的主要內部作業)。我用所有型別測驗了串列,它作業得非常好。當我創建 2 個串列,執行一些操作,然后按照它們創建的相同順序一起洗掉這兩個串列時,問題就出現了。它給了我一個錯誤:- Critical error detected c0000374; 并說,unable to open 'free-base.cpp'。洗掉通過free_assets方法。當我在使用第二個串列物件之前洗掉第一個串列物件時,這兩個串列作業得非常好,這很不尋常,因為它們是兩個不同的物件。
原始串列.h
#ifndef PRIMITIVE_LIST_H
#define PRIMITIVE_LIST_H
typedef enum { INT, LONG_INT, DECIMAL, CHAR } list_types;
typedef struct
{
void *_assets;
} list;
list *create_list(list_types type);
void push(list **self, ...);
void pop(list **self);
void*at(list *self, const int index);
int empty(list *self);
unsigned length(list *self);
void print_list(list *self);
void free_assets(list **self);
#endif
原始串列.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "primitive_list.h"
typedef struct
{
int capacity;
int size;
void *arr;
list_types type;
int empty;
} _list;
_list _create_list(list_types type)
{
_list res;
res.type = type;
res.capacity = 1;
res.size = 0;
res.empty = 1;
return res;
}
void _alloc(_list *self)
{
switch ((self)->type)
{
int n = (self)->capacity;
case INT:
(self)->arr = calloc(n, sizeof(int));
break;
case LONG_INT:
(self)->arr = calloc(n, sizeof(long long));
break;
case DECIMAL:
(self)->arr = calloc(n, sizeof(double));
break;
case CHAR:
(self)->arr = calloc(n, sizeof(char));
break;
}
return;
}
void _realloc(_list *self, size_t Buffer_size)
{
(self)->capacity = Buffer_size;
list_types type = (self)->type;
int n = (self)->capacity;
int s = (self)->size;
if (type == INT) {
int *new_array = (int *)calloc(n, sizeof(int));
for (size_t i = 0; i < s; i )
{
new_array[i] = ((int *)(self)->arr)[i];
}
free((self)->arr);
(self)->arr = (void *)new_array;
} else if (type == LONG_INT) {
long long *new_array = (long long *)calloc(n, sizeof(long long));
for (size_t i = 0; i < s; i )
{
new_array[i] = ((long long *)(self)->arr)[i];
}
free((self)->arr);
(self)->arr = (void *)new_array;
} else if (type == DECIMAL) {
double *new_array = (double *)calloc(n, sizeof(double));
for (size_t i = 0; i < s; i )
{
new_array[i] = ((double *)(self)->arr)[i];
}
free((self)->arr);
(self)->arr = (void *)new_array;
} else if (type == CHAR) {
char *new_array = (char *)calloc(n, sizeof(char));
for (size_t i = 0; i < s; i )
{
new_array[i] = ((char *)(self)->arr)[i];
}
free((self)->arr);
(self)->arr = (void *)new_array;
}
return;
}
void _push(_list *self, ...)
{
if ((self)->empty)
{
(self)->empty = 0;
_alloc(self);
}
if ((self)->size == (self)->capacity)
_realloc(self, (self)->capacity * 2);
va_list arg;
va_start(arg, self);
switch ((self)->type)
{
case INT:
((int *)(self)->arr)[(self)->size] = va_arg(arg, int);
break;
case LONG_INT:
((long long *)(self)->arr)[(self)->size] = va_arg(arg, long long);
break;
case DECIMAL:
((double *)(self)->arr)[(self)->size] = va_arg(arg, double);
break;
case CHAR:
((char *)(self)->arr)[(self)->size] =(char)va_arg(arg, int);
break;
}
(self)->size ;
va_end(arg);
return;
}
void _pop(_list *self)
{
if ((self)->empty)
{
fprintf(stderr,"List is empty!\n");
return;
}
(self)->size--;
return;
}
void *_at(_list *self, const int index)
{
void *res;
switch ((self)->type)
{
case INT:
res = malloc(sizeof(int));
*((int *)res) = ((int *)(self)->arr)[index];
break;
case LONG_INT:
res = malloc(sizeof(long long));
*((long long *)res) = ((long long *)(self)->arr)[index];
break;
case DECIMAL:
res = malloc(sizeof(double));
*((double *)res) = ((double *)(self)->arr)[index];
break;
case CHAR:
res = malloc(sizeof(char));
*((char *)res) = ((char *)(self)->arr)[index];
break;
}
return res;
}
int _empty(_list *self)
{
return self->empty;
}
unsigned _length(_list *self)
{
return self->size;
}
void _print_list(_list *self)
{
for (size_t i = 0; i < self->size; i )
{
switch(self->type)
{
case INT:
printf("%d ", ((int *)self->arr)[i]);
break;
case LONG_INT:
printf("%lld ", ((long long *)self->arr)[i]);
break;
case DECIMAL:
printf("%lf ", ((double *)self->arr)[i]);
break;
case CHAR:
printf("%c ",((char*)self->arr)[i]);
break;
}
}
printf("\n");
return;
}
void _free_list(_list *self)
{
free((self)->arr);
}
list *create_list(list_types type)
{
static list res;
_list obj = _create_list(type);
res._assets = malloc(sizeof(_list));
*((_list*)res._assets) = obj;
return &res;
}
void push(list **self, ...)
{
va_list arg;
va_start(arg, self);
switch (((_list *)(*self)->_assets)->type)
{
case INT:
_push(((_list *)(*self)->_assets), va_arg(arg, int));
break;
case LONG_INT:
_push(((_list *)(*self)->_assets), va_arg(arg, long long));
break;
case DECIMAL:
_push(((_list *)(*self)->_assets), va_arg(arg, double));
break;
case CHAR:
_push(((_list *)(*self)->_assets), (char)va_arg(arg, int));
break;
}
va_end(arg);
return;
}
void pop(list **self)
{
_pop(((_list *)(*self)->_assets));
return;
}
void *at(list *self, const int index)
{
return _at((_list *)self->_assets, index);
}
int empty(list *self)
{
return _empty((_list *)self->_assets);
}
unsigned length(list *self)
{
return _length((_list *)self->_assets);
}
void print_list(list *self)
{
_print_list((_list *)self->_assets);
return;
}
void free_assets(list **self)
{
_free_list(((_list *)(*self)->_assets));
free((*self)->_assets);
}
測驗.c
#include <stdio.h>
#include <stdlib.h>
#include "primitive_list.h"
int main(int argc, char **argv)
{
//Decimal List
list *nums = create_list(DECIMAL);
push(&nums, 3.14159);
push(&nums, 6.25);
push(&nums, 22.2222);
push(&nums, 100.0);
print_list(nums);
//Character list
list *chars = create_list(CHAR);
push(&chars, 'A');
push(&chars, 'w');
push(&chars, 'Z');
push(&chars, 'q');
push(&chars, 'P');
print_list(chars);
//Code causing the error
free_assets(&nums);
free_assets(&chars);
return 0;
}
uj5u.com熱心網友回復:
您這里的代碼有點令人困惑,因為您似乎無緣無故地將底層結構埋在另一個結構中。沒有理由你不能簡單地(如果你想保持實作細節保密)typedef struct list list;在標題中寫入,并且在你的實作中
struct list {
int capacity;
int size;
void *arr;
list_types type;
int empty;
};
_assets這樣一來,必須處理指標的困惑就會大大減少;您可以簡單地直接尋址串列成員而無需取消參考和強制轉換(這會造成不必要的混亂)。
您這里的主要問題實際上是由于您的create_list功能由于其實作而導致的記憶體管理不善。具體來說,這兩行:
list *create_list(list_types type)
{
static list res;
/* ... */
return &res;
}
這里static關鍵字的作用是定義一個在該函式的所有呼叫之間共享的全域變數。也就是說,每次呼叫create_list時,res變數都會設定為與函式最后一次相同的值return。這就是為什么您可以&res從該函式回傳以獲取函式外部的有效指標:該res變數存盤在程式的全域記憶體中,而不是存盤在函式的堆疊幀中。
那么(至少!)這個程式有兩個問題:
- 指向每個
list你創建的指標都是一樣的,所以每個list創建的都會覆寫 last 的記憶體list,這不僅會泄漏記憶體(指向_assets結構的指標),而且只會使最后創建的串列有效。實際上,您的nums和chars串列應該具有完全相同的值chars。 - 你正在呼叫
free你沒有分配的記憶體malloc。因為你從你的函式中回傳了一個真正的全域變數的地址,所以你回傳了create_list一個指向在你的程式第一次加載時由作業系統創建的記憶體的指標。您不擁有此記憶體,并且嘗試呼叫free它與您在此處看到的效果完全相同:它會使您的程式崩潰。
這兩個問題都可以用同樣的方式解決:妥善管理你的記憶。一般來說,如果你想在 C 中的記憶體中創建一個結構,你應該以malloc適當的大小呼叫,初始化新記憶體的值,并將指向它的指標回傳給呼叫者。這可以在您的情況下實作為:
list *create_list(list_types type)
{
list res = malloc(sizeof(list));
_list obj=_create_list(type);
res._assets=malloc(sizeof(_list));
*((_list *)res._assets)=obj;
return res;
}
或者,如果您list按照我上面的建議更改布局,只需:
list *create_list(list_types type)
{
list res = malloc(sizeof(list);
res->type = type;
res->capacity = 1;
// ...
return res;
}
uj5u.com熱心網友回復:
你這里有問題:
list*create_list(list_types type)
{
static list res;
_list obj=_create_list(type);
res._assets=malloc(sizeof(_list));
*((_list*)res._assets)=obj;
return &res;
}
這個函式在 中被呼叫了兩次main(),但回傳一個指向靜態變數的指標,這意味著每次呼叫它都會回傳相同的地址。因此,當main()似乎創建指向兩個不同串列的指標時,它們實際上是指向單個串列的指標,即static list res.
uj5u.com熱心網友回復:
您的代碼中有多個問題:
對用戶隱藏實作不需要像發布的那樣間接,您可以只宣告
struct list沒有定義。create_list回傳static物件的地址,毫不奇怪釋放 this 具有未定義的行為,更不用說所有串列物件物件實際上都是同一個物件這一事實。塊
int n = (self)->capacity;開頭的行永遠不會執行。將此行移到陳述句之前。switch_alloc()switch您不應該使用以 . 開頭的識別符號
_。括號
(self)是無用且令人困惑的。
這是一個簡化版本:
原始串列.h:
#ifndef PRIMITIVE_LIST_H
#define PRIMITIVE_LIST_H
typedef enum { INT, LONG_INT, DECIMAL, CHAR } list_type;
typedef struct list list;
list *list_create(list_type type);
int list_push(list *self, ...);
void list_pop(list *self);
void *list_at(const list *self, int index);
int list_empty(const list *self);
int list_length(const list *self);
void list_print(const list *self);
void list_free(list **self);
#endif
原始串列.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "primitive_list.h"
struct list {
list_type type;
int capacity;
int length;
void *arr;
};
list *list_create(list_type type) {
list *res = malloc(sizeof(*res));
if (res) {
res->type = type;
res->capacity = 0;
res->length = 0;
res->arr = NULL;
} else {
fprintf(stderr, "list_create: out of memory!\n");
}
return res;
}
static int list_element_size(list_type type) {
switch (type) {
case INT: return sizeof(int);
case LONG_INT: return sizeof(long long);
case DECIMAL: return sizeof(double);
case CHAR: return sizeof(char);
}
return 0;
}
int list_push(list *self, ...) {
va_list arg;
if (self->length == self->capacity) {
if (self->capacity == 0) {
self->capacity = 1;
self->arr = calloc(self->capacity, list_element_size(self->type));
if (self->arr == NULL) {
fprintf(stderr, "list_push: out of memory!\n");
return 0;
}
} else {
size_t size = self->capacity * list_element_size(self->type);
void *new_arr = realloc(self->arr, size * 2);
if (new_arr == NULL) {
fprintf(stderr, "list_push: out of memory!\n");
return 0;
}
memset((char *)new_arr size, 0, size);
self->arr = new_arr;
self->capacity *= 2;
}
}
va_start(arg, self);
switch (self->type) {
case INT:
((int *)self->arr)[self->length ] = va_arg(arg, int);
break;
case LONG_INT:
((long long *)self->arr)[self->length ] = va_arg(arg, long long);
break;
case DECIMAL:
((double *)self->arr)[self->length ] = va_arg(arg, double);
break;
case CHAR:
((char *)self->arr)[self->length ] = (char)va_arg(arg, int);
break;
}
va_end(arg);
return self->length;
}
void list_pop(list *self) {
if (self->length == 0) {
fprintf(stderr, "list_pop: list is empty!\n");
} else {
self->length--;
}
}
void *list_at(const list *self, int index) {
if (index < 0 || index >= self->length)
return NULL;
void *res = malloc(list_element_size(self->type));
if (res == NULL) {
fprintf(stderr, "list_at: out of memory!\n");
return 0;
}
switch (self->type) {
case INT:
*((int *)res) = ((int *)self->arr)[index];
break;
case LONG_INT:
*((long long *)res) = ((long long *)self->arr)[index];
break;
case DECIMAL:
*((double *)res) = ((double *)self->arr)[index];
break;
case CHAR:
*((char *)res) = ((char *)self->arr)[index];
break;
}
return res;
}
int list_empty(const list *self) {
return self->length == 0;
}
int list_length(const list *self) {
return self->length;
}
void list_print(const list *self) {
for (int i = 0; i < self->length; i ) {
switch (self->type) {
case INT:
printf("%d ", ((int *)self->arr)[i]);
break;
case LONG_INT:
printf("%lld ", ((long long *)self->arr)[i]);
break;
case DECIMAL:
printf("%f ", ((double *)self->arr)[i]);
break;
case CHAR:
printf("%c ", ((char *)self->arr)[i]);
break;
}
}
printf("\n");
}
void list_free(list **self) {
if (*self) {
free((*self)->arr);
free(*self);
*self = NULL;
}
}
測驗.c:
#include <stdio.h>
#include <stdlib.h>
#include "primitive_list.h"
int main(int argc, char **argv) {
//Decimal List
list *nums = list_create(DECIMAL);
list_push(nums, 3.14159);
list_push(nums, 6.25);
list_push(nums, 22.2222);
list_push(nums, 100.0);
//Character list
list *chars = list_create(CHAR);
list_push(chars, 'A');
list_push(chars, 'w');
list_push(chars, 'Z');
list_push(chars, 'q');
list_push(chars, 'P');
// print the lists
list_print(nums);
list_print(chars);
// free the lists
list_free(&nums);
list_free(&chars);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/442974.html
上一篇:警告:在將陣列分配給int指標時,從'int'初始化'int*'使指標從整數而不進行強制轉換
下一篇:如何獲取字串陣列的長度
