删除资源时,编程最终崩溃。伪通用动态数组列表的C实现

发布于 2025-01-13 16:24:49 字数 7839 浏览 5 评论 0原文

我已经用 C 实现了一个针对原始类型的伪通用动态数组。它采用枚举常量作为每种类型的标识符 - INTLONG_INTDECIMALCHAR。主结构list有一个成员_assets,它是一个void指针(具有抽象级别)。这个 void 指针在 C 文件实现中被类型转换为另一个结构(这是容器的主要内部工作)。我测试了所有类型的列表,它工作得很好。当我创建 2 个列表,执行一些操作,然后按照创建顺序同时删除这两个列表时,出现了问题。它给了我一个错误:- 检测到严重错误 c0000374;并显示无法打开“free-base.cpp”。删除通过 free_assets 方法进行。当我在使用第二个列表对象之前删除第一个列表对象时,这两个列表工作得很好,这很不寻常,因为它们是两个不同的对象。

primitive_list.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 

primitive_list.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);
}

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

I have implemented a pseudo-generic dynamic array in C, for primitive types. It takes enum constants as identifier for each type- INT, LONG_INT, DECIMAL, CHAR. The main struct list has a member _assets, which is a void pointer (to have a level of abstraction). This void pointer is type-casted to another struct (which is the main internal working of the container) in the C file implementation. I tested the list with all the types, and it worked perfectly fine. The problem arose when I created 2 lists, performed some operations, and then deleted the both lists together in the same order they were created. It gives me an error:- Critical error detected c0000374; and says, unable to open 'free-base.cpp'. The deletion takes play through the free_assets method. The 2 lists work perfectly fine when I delete the first list object before using the second list object, which is quiet unusual, since they are 2 different objects.

primitive_list.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 

primitive_list.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);
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

热风软妹 2025-01-20 16:24:50

您这里的代码有点令人困惑,因为您似乎无缘无故地将底层结构埋藏在另一个结构中。您没有理由不能简单地(如果您想将实现细节保持私有)在标头和实现中编写 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 变量都会设置为与函数上次返回时相同的值。这就是为什么您可以从此函数返回 &res 来获取函数外部的有效指针:res 变量存储在程序的全局内存中,而不是存储在函数的堆栈框架。

这个程序有(至少!)两个问题:

  1. 指向您创建的每个 list 的指针都是相同的,因此创建的每个 list 都会覆盖该对象的内存。 Last list,它不仅会泄漏内存(指向 _assets 结构的指针),而且只使最后创建的列表有效。事实上,您的 numschars 列表应该与创建 chars 时具有完全相同的值。
  2. 您正在对未使用 malloc 分配的内存调用 free。因为您从 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; 
}

Your code here is a bit confusing, as it appears you're burying your underlying structure in another structure for no reason. There's no reason you cannot simply (if you want to keep implementation details private) write typedef struct list list; in the header and in your implementation have

struct list {
    int capacity; 
    int size; 
    void *arr; 
    list_types type; 
    int empty;
};

This way, there would be much less confusion about having to deal with the _assets pointer; you could simply address the list members directly without a dereference and cast (this is needlessly confusing).

Your main issue here is actually due to bad memory management in your create_list function due to its implementation. Specifically, these two lines:

list *create_list(list_types type)
{
    static list res; 
    
    /* ... */
    
    return &res; 
}

What the static keyword does here is to define a global variable shared between all invocations of this function. That is, every time you call create_list, the res variable is set to the same value as it was at the last return from the function. This is why you can return &res from this function to get a valid pointer outside the function: the res variable is stored in global memory for your program instead of in the function's stack frame.

There are then (at least!) two issues with this program:

  1. The pointer to every list you create will be the same, so every list created will override the memory of the last list, which not only leaks memory (the pointer to the _assets structure), but makes only the last created list valid. In fact, your nums and chars lists should have exactly the same value ones chars is created.
  2. You're calling free on memory you didn't allocate with malloc. Because you return the address of a bona-fide global variable from your create_list function, you're returning a pointer to memory created by the Operating System when your program is first loaded. You DO NOT own this memory, and attempting to call free on it has exactly the effect you're seeing here: it will crash your program.

Both of these issues can be resolved in the same way: properly manage your memory. Generally, if you want to create a structure in memory in C, you should be calling malloc with the proper size, initializing the value of the new memory, and returning the pointer to it back to the caller. This can be implemented in your case as:

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

Or, if you change the layout of list as I suggest above, simply:

list *create_list(list_types type)
{
    list res = malloc(sizeof(list); 
    res->type = type; 
    res->capacity = 1; 
    // ...
    return res; 
}
时光礼记 2025-01-20 16:24:50

这里有一个问题:

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

You have a problem here:

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

This function is called twice in main(), but returns a pointer to a static variable, meaning it will return the same address every time it is called. So when main() appears to create pointers to two different lists, they are actually pointers to a single list, namely static list res.

失眠症患者 2025-01-20 16:24:50

您的代码中存在多个问题:

  • 向用户隐藏实现不需要像发布的那样间接,您可以只声明struct list而无需定义。

  • create_list 返回一个static 对象的地址,毫不奇怪地释放它会产生未定义的行为,更不用说所有列表对象实际上都是同一个对象。

  • _alloc()switch 块开头的行 int n = (self)->capacity; 永远不会被执行。将此行移至 switch 语句之前。

  • 您不应使用以 _ 开头的标识符。

  • 括号(self)毫无用处且令人困惑。

这是一个简化版本:

primitive_list.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);
int list_get(const list *self, int index, ...);
int list_set(list *self, int index, ...);
int list_empty(const list *self);
int list_length(const list *self);
void list_print(const char *msg, const list *self);
void list_free(list **self);
#endif

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

int list_get(const list *self, int index, ...) {
    int rc = 0;
    if (index >= 0 && index < self->length) {
        va_list arg;
        va_start(arg, index);
        switch (self->type) {
        case INT:
            *va_arg(arg, int *) = ((int *)self->arr)[index];
            rc = 1;
            break;
        case LONG_INT:
            *va_arg(arg, long long *) = ((long long *)self->arr)[index];
            rc = 1;
            break;
        case DECIMAL:
            *va_arg(arg, double *) = ((double *)self->arr)[index];
            rc = 1;
            break;
        case CHAR:
            *va_arg(arg, char *) = ((char *)self->arr)[index];
            rc = 1;
            break;
        }
        va_end(arg);
    }
    return rc;
}

int list_set(list *self, int index, ...) {
    int rc = 0;
    if (index >= 0 && index < self->length) {
        va_list arg;
        va_start(arg, index);
        switch (self->type) {
        case INT:
            ((int *)self->arr)[index] = va_arg(arg, int);
            rc = 1;
            break;
        case LONG_INT:
            ((long long *)self->arr)[index] = va_arg(arg, long long);
            rc = 1;
            break;
        case DECIMAL:
            ((double *)self->arr)[index] = va_arg(arg, double);
            rc = 1;
            break;
        case CHAR:
            ((char *)self->arr)[index] = (char)va_arg(arg, int);
            rc = 1;
            break;
        }
        va_end(arg);
    }
    return rc;
}

int list_empty(const list *self) {
    return self->length == 0;
}

int list_length(const list *self) {
    return self->length;
}

void list_print(const char *msg, const list *self) {
    if (msg) {
        printf("%s: ", msg);
    }
    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;
    }
}

test.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", nums);
    list_print("chars", chars);

    double x;
    char c;
    if (list_get(nums, 2, &x))
        printf("nums[2] = %f\n", x);
    if (list_get(chars, 2, &c))
        printf("chars[2] = '%c'\n", c);
    if (list_set(nums, 3, 123.45))
        printf("set nums[3] to %f\n", 123.45);
    if (list_set(chars, 3, '*'))
        printf("set chars[3] to '%c'\n", '*');

    // print the lists
    list_print("nums", nums);
    list_print("chars", chars);

    // free the lists
    list_free(&nums);
    list_free(&chars);
    return 0;
}

输出:

nums: 3.141590 6.250000 22.222200 100.000000
chars: A w Z q P
nums[2] = 22.222200
chars[2] = 'Z'
set nums[3] to 123.450000
set chars[3] to '*'
nums: 3.141590 6.250000 22.222200 123.450000
chars: A w Z * P

There are multiple problems in your code:

  • hiding the implementation from the user does not require an indirect as posted, you can just declare the struct list without a definition.

  • create_list returns the address of a static object, no surprise freeing this has undefined behavior, not to mention the fact that all list objects objects are actually the same object.

  • the line int n = (self)->capacity; at the beginning of the switch block in _alloc() is never executed. Move this line before the switch statement.

  • you should not use identifiers starting with a _.

  • parenthesizing (self) is useless and confusing.

Here is a simplified version:

primitive_list.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);
int list_get(const list *self, int index, ...);
int list_set(list *self, int index, ...);
int list_empty(const list *self);
int list_length(const list *self);
void list_print(const char *msg, const list *self);
void list_free(list **self);
#endif

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

int list_get(const list *self, int index, ...) {
    int rc = 0;
    if (index >= 0 && index < self->length) {
        va_list arg;
        va_start(arg, index);
        switch (self->type) {
        case INT:
            *va_arg(arg, int *) = ((int *)self->arr)[index];
            rc = 1;
            break;
        case LONG_INT:
            *va_arg(arg, long long *) = ((long long *)self->arr)[index];
            rc = 1;
            break;
        case DECIMAL:
            *va_arg(arg, double *) = ((double *)self->arr)[index];
            rc = 1;
            break;
        case CHAR:
            *va_arg(arg, char *) = ((char *)self->arr)[index];
            rc = 1;
            break;
        }
        va_end(arg);
    }
    return rc;
}

int list_set(list *self, int index, ...) {
    int rc = 0;
    if (index >= 0 && index < self->length) {
        va_list arg;
        va_start(arg, index);
        switch (self->type) {
        case INT:
            ((int *)self->arr)[index] = va_arg(arg, int);
            rc = 1;
            break;
        case LONG_INT:
            ((long long *)self->arr)[index] = va_arg(arg, long long);
            rc = 1;
            break;
        case DECIMAL:
            ((double *)self->arr)[index] = va_arg(arg, double);
            rc = 1;
            break;
        case CHAR:
            ((char *)self->arr)[index] = (char)va_arg(arg, int);
            rc = 1;
            break;
        }
        va_end(arg);
    }
    return rc;
}

int list_empty(const list *self) {
    return self->length == 0;
}

int list_length(const list *self) {
    return self->length;
}

void list_print(const char *msg, const list *self) {
    if (msg) {
        printf("%s: ", msg);
    }
    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;
    }
}

test.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", nums);
    list_print("chars", chars);

    double x;
    char c;
    if (list_get(nums, 2, &x))
        printf("nums[2] = %f\n", x);
    if (list_get(chars, 2, &c))
        printf("chars[2] = '%c'\n", c);
    if (list_set(nums, 3, 123.45))
        printf("set nums[3] to %f\n", 123.45);
    if (list_set(chars, 3, '*'))
        printf("set chars[3] to '%c'\n", '*');

    // print the lists
    list_print("nums", nums);
    list_print("chars", chars);

    // free the lists
    list_free(&nums);
    list_free(&chars);
    return 0;
}

Output:

nums: 3.141590 6.250000 22.222200 100.000000
chars: A w Z q P
nums[2] = 22.222200
chars[2] = 'Z'
set nums[3] to 123.450000
set chars[3] to '*'
nums: 3.141590 6.250000 22.222200 123.450000
chars: A w Z * P
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文