需要检查struct是否已初始化

时间:2015-03-06 19:23:19

标签: c struct functional-programming queue

您好我正在制作一个队列抽象数据类型,我遇到了一个问题,我将尽可能清楚地解释。 基本上我有两个结构,一个用于元素,一个用于队列(因此​​可以初始化多个队列)。

struct element
{
    TYPE value;
    struct element* next;
};

struct queue
{
    struct element* head;
    struct element* tail;
    int element_counter;
};

我有一个初始化队列结构的函数。

int make_new_queue(struct queue* name)
{
    name = malloc(sizeof(struct queue));
    name->head = NULL;
    name->tail = NULL;
    name->element_counter = 0;
}

我遇到的问题是这个代码万无一失。例如,我在main函数中初始化了我的第一个队列。

struct queue* first = make_new_queue(first);

但如果有人试图在代码中间的某处再次做同样的事情,那就写下来了:

first = make_new_queue(first);

它会覆盖它并使head和tail指针为NULL。我无法弄清楚的是如何使我的make_new_queue函数更好,并检查队列中是否有我提供的东西,但仍然让我初始化空队列。

抱歉我的英文。我希望你能理解我想做的事情。感谢。

3 个答案:

答案 0 :(得分:1)

将其初始化为NULL并将指针传递给指针:

void make_new_queue(struct queue **name)
{
    if (*name != NULL) return; /* Yet initialized ? */
    *name = malloc(sizeof(struct queue));
    if (*name == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    *name->head = NULL;
    *name->tail = NULL;
    *name->element_counter = 0;
}


struct queue *first = NULL;
make_new_queue(&first);

答案 1 :(得分:0)

您只需检查变量name是否为NULL

如果你的变量是非空的,你可以分配并初始化你的队列,否则就做你想做的事。

答案 2 :(得分:0)

没有好的方法可以在没有用户纪律的情况下强制执行您想要的内容。在我看来,最好的方法是坚持已知的模式。

您可以使用Alter Mann的方法将指针传递给指针以更新结构。缺点是你必须将变量声明和初始化分开。它还依赖于用户将结构的指针初始化为NULL。如果您忘了它,队列指针将不会被初始化,您甚至不知道,因为您无法检查NULL

struct stuff *stuff = NULL;

stuff_initialise(&stuff);

您可以使用原始方法传入结构,并在初始化时返回相同的结构或新结构。它具有与第一种方法相同的问题以及您忘记分配返回值的可能性。但是,您可以将分配和初始化结合起来:

struct stuff *stuff = stuff_new(NULL);

最简单的方法是不传递旧指针并依赖用户在分配后不更改指针。毕竟,标准库的功能也存在同样的问题:

char *buf = malloc(BUFSIZE);
buf = malloc(2 * BUFSIZE);             // Memory leak
buf++;                                 // Allowed, but a bad idea
free(buf);                             // Ouch!

FILE *f = fopen("palomino.txt", "r");
f = stdin;                             // Switch horses midstream?

您应该设计API,以便拥有定义结构范围的匹配函数对:

struct stuff *stuff = stuff_create(...);

// use stuff ...
stuff_destroy(stuff);

良好的命名应明确stuff充当句柄,不应更改,并且在关闭或销毁句柄后,它无效。您应该将这些调用视为函数中的第一个和最后一个语句。 (此方法类似于标准库的malloc / freefopen / fclose对。)

最后,如果您作为句柄的用户想要避免更改,您可以将指针(而不是它指向的内容)定义为const

struct stuff *const handle = stuff_create("X");

handle = stuff_create("Y");            // Compiler error

但我很少看到这一点。 C程序员通常只使用一个朴素的指针,并记住将手指放在加热板上。