【问题标题】:Why is `pLQ->tail` a null pointer?为什么`pLQ->tail`是一个空指针?
【发布时间】:2019-04-14 05:04:13
【问题描述】:

我正在处理一个队列并且一直遇到排队问题。以下是我认为相关的代码:

typedef struct Qnode QNODE;
struct Qnode
{
  int length;
  QNODE* next;
  QNODE* prev;
};

typedef struct lqueue lQUEUE;
struct lqueue
{
   QNODE *head;
   QNODE *tail;
};

lQueue lqueue_init_default(void)
{
lQUEUE* pQ = NULL;
pQ = (lQUEUE*)malloc(sizeof(lQUEUE));
if (pQ != NULL)
{
    pQ->head = NULL;
    pQ->tail = NULL;
}
pQ->head = pQ->tail;
return pQ;
}

Status lqueue_henqueue(lQueue* hLQ, int lc)
{
lQUEUE* pLQ = (lQUEUE*)hLQ;
QNODE* new = (QNODE*)malloc(sizeof(QNODE));
if (new == NULL)
{
    printf("Couldn't allocate space.\n");
    return FAILURE;
}
new->length = lc;
new->next = pLQ->tail->next;

pLQ->tail = new;
return SUCCESS;
}

每当我尝试运行程序时,都会在运行时收到此错误:
抛出异常:读取访问冲突。 pLQ->tail 是 nullptr。
为什么是空指针?跟初始化函数有关系吗?
这是它的名称:

int cl = 0;//Individual car length
lQueue hLQ = lqueue_init_default();//Handle to the left queue
printf("Enter the length of the lcar:\n");
            scanf("%d", &cl);
            lqueue_henqueue(hLQ, cl);

【问题讨论】:

  • 你必须展示lqueue_henqueue是如何被调用的
  • lQueue lqueue_init_default(void) 您是否忘记了返回类型上的*
  • 不,因为当我这样做时,会出现编译器错误。

标签: c pointers linked-list queue


【解决方案1】:

你的代码很容易出现undefined behavior...看看这个if声明:

if (pQ != NULL)
{
    pQ->head = NULL; // This pointer is now 'NULL'
    pQ->tail = NULL; // This is also 'NULL'
}

应该这个...

if (pQ != NULL)
{
    pQ->head = (QNODE*)calloc(1, sizeof(lQUEUE)); // This is proper pointer initialization...
    pQ->tail = (QNODE*)calloc(1, sizeof(lQUEUE));
}

还有这个:

lQueue lqueue_init_default(void)

应该是这样的:

lQueue * lqueue_init_default(void) // Since you are returning a pointer...

您会看到代码运行良好,因为没有未定义的行为...

请注意,您可以never access an object that is assigned to NULL...(仅当您不希望您的程序行为未定义...)所以,这个:

pQ->tail = NULL;

至少不安全...分配给NULL的结构指针通常只有在销毁时才能看到。 .. 下面给出一个例子...


另外,不相关,但是有一个结构的析构函数,当你不再需要这个结构时调用它,否则它会之后泄漏内存...

void destroy_lqueue(struct lqueue ** queue)
{
    if (queue != NULL)
        queue = NULL;
    free(queue);
}

【讨论】: