【问题标题】:Need to check if struct has been initialized需要检查struct是否已经初始化
【发布时间】:2015-03-06 19:23:18
【问题描述】:

您好,我正在制作一个 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);

它覆盖它并使头和尾指针为空。我想不通的是如何使我的 make_new_queue 函数更好,并检查我提供的队列中是否有东西,但仍然让我初始化空队列。

对不起我的英语。我希望你明白我想做什么。谢谢。

【问题讨论】:

  • 您的代码无论如何都不会初始化结构,它会初始化 a 结构 但您没有返回指向它的指针,因此它不起作用,并试图防止这是不可能的,只是不要让任何傻瓜使用你的代码。
  • 您可以创建一个函数来分配和返回一些新结构,而无需将其他结构传递到那里(为什么要这样做?)。

标签: c struct functional-programming queue


【解决方案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);

【讨论】:

  • if (*name != NULL) return;if (*name == NULL) return; ?
  • @SorryIwontTell if (*name != NULL) return; 如果指针已经初始化,OP 似乎想要退出。
【解决方案2】:

您可以简单地检查变量name 是否为NULL

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

【讨论】:

  • 如果它包含一些垃圾(它可能会包含它),它将无法工作。
  • 你们俩都是对的。我认为你的函数的行为是错误的。您必须创建一个没有参数的函数,该函数返回指向您的初始化队列的指针。
【解决方案3】:

如果没有用户的纪律,真的没有什么好方法可以强制执行您想要的。在我看来,最好的方法是坚持已知模式。

您可以使用 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/fclosepairngs。)

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

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

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

但我很少看到这个。 C 程序员通常只使用朴素的指针,并记住不要让手指离开加热板。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 2015-08-01
    • 2011-10-12
    • 2015-05-23
    • 2019-01-25
    相关资源
    最近更新 更多