c语言指针为NULL出错

#include<stdio.h>
#include<stdlib.h>

// 定义链队数据节点
typedef struct qnode
{
    int data;
    struct qnode *next;
}DataNode;

// 定义链队头结点
typedef struct 
{
    DataNode *front;
    DataNode *rear;
}LinkQuNode;

// 初始化队列
void InitQueue(LinkQuNode *q)
{
    q = (LinkQuNode *)malloc(sizeof(LinkQuNode));
    q -> front = q -> rear = NULL;
}

// 销毁队列
void DestroyQueue(LinkQuNode *q)
{
    DataNode *pre = q -> front, *p; // pre指向队首节点(除了队头节点的第一个节点)
    if(pre != NULL)
    {
        p = pre -> next;
        while(p != NULL)
        {
            free(p);
            pre = p; p = p -> next;
        }
        free(p);
    }
    free(q);
    printf("队列已销毁");
    return;
}

// 队列判空
void QueueEmpty(LinkQuNode *q)
{
    if(q -> front == NULL)
       printf("队列为空\n");
    else
       printf("队列不为空\n");
}

// 进队列
void enQueue(LinkQuNode *q, int e)
{
    DataNode *p;
    p = (DataNode *)malloc(sizeof(DataNode));
    p -> data = e;
    p -> next = NULL;
    if(q -> rear == NULL) // 当结点是队列中的第一个结点时
      q -> front = q -> rear = p;   // 队头结点和队尾结点同时指向p
    else
    {
        q -> rear -> next = p;
        q -> rear = p;
    }
}

// 出队列, 返回出队列的值e
int deQueue(LinkQuNode *q)
{
    DataNode *t;
    if(q -> rear == NULL) // 队列为空
    {
        printf("队列空\n");
        return 1;
    }
    t = q -> front;
    if(q -> front == q -> rear) // 队列中只有一个数据结点
       q -> front = q -> rear = NULL;
    else
    {
        q -> front = q -> front -> next;
    }
    printf("被删除的元素是:%d\n", t -> data);
    free(t);
    return 0;
}

// 入队功能函数
void pushQueue(LinkQuNode *q)
{
    int i;
    printf("输入要入队的数据:");
    scanf("%d", &i);
    enQueue(q, i);
    printf("入队成功");
}

int main()
{
    int menu;
    LinkQuNode *q;
    InitQueue(q);
    printf("1 入队列     2 出队列\n");
    printf("3 队列判空   4 销毁队列\n");
    printf("5 退出\n");
   
    while(1)
    {
        printf("请输入菜单号:");
        scanf("%d", &menu);
        if(menu == 5)
          break;
        switch(menu)
       {
          case 1: pushQueue(q); break;
          case 2: deQueue(q); break;
          case 3: QueueEmpty(q); break;
          case 4: DestroyQueue(q); break;
          default: printf("1\n");
       }
    }
    return 0;
    
}


这是代码和调试的结果,实在找不出错误的原因,请求大佬告知。


这个问题的原因不是在在函数中开辟的空间地址离开函数就无效。

用 malloc() 函数申请的内存地址离开函数后还是有效,需要主动用 free() 函数释放才会无效。

这段代码出问题的原因在于,传入到 InitQueue() 函数的参数类型不对。下面这种写法,传入到该函数的 q指针参数是传值的方式,在 InitQueue() 函数内部并不能修改外部 q 指针变量的值。

void InitQueue(LinkQuNode *q)

即,在你的 main() 函数的下面语句中,LinkQuNode *q 这个变量的值并不会因为执行 InitQueue(q); 语句而改变。执行 InitQueue(q); 语句后,q这个变量值还是没有初始化,并没有指向 malloc() 分配出来的内存地址。

LinkQuNode *q;
InitQueue(q);


如果你想要修改外部这个q变量的值,要把 InitQueue函数的参数类型改成 void InitQueue(LinkQuNode **q),然后再该函数里面用 *q 来为它赋值。

把 q = (LinkQuNode *)malloc(sizeof(LinkQuNode));//分配空间 提到主函数有效,就是因为这会真正为 q变量赋值。

你可以用 printf("q: %p", &q); 语句打印 L 指针变量的地址来查看 InitQueue() 函数内外 L 的地址,看是否一样。

对于 InitQueue(LinkQuNode *q) 这种函数来说,可以用 q 指针来修改 q 指向的内存地址的值,但是这个 L 是形参,修改 q 本身的值,并不影响外面实参的值。

可改成

q -> front->next = q -> rear->next = NULL;
q -> front->data = q -> rear->data = 0;

原因:

未初始化的内存

如:p已被分配了10个字节。这10个字节可能包含垃圾数据。

char*p=malloc(10);

垃圾数据

如果在对这个p赋值前,某个代码段尝试访问它,则可能会获得垃圾值,您的程序可能具有不可预测的行为。p可能具有您的程序从未曾预料到的值。

结合使用memset和malloc,或者使用calloc。

char*p=malloc(10);

memset(p,’’,10);

 

这样就行了,你永远记住,指针你一旦使用就得指向一块地址。

void InitQueue(LinkQuNode *q)
{
        q = (LinkQuNode *)malloc(sizeof(LinkQuNode));
        q -> front = (DataNode *)malloc(sizeof(DataNode)); 
	q -> rear  = (DataNode *)malloc(sizeof(DataNode));
	q -> rear->next = (DataNode *)malloc(sizeof(DataNode));
        q -> rear->data = 0;
	q -> front->next = NULL;
        q -> front->data = 0;
}

这个是调试结果:调用函数时都是在这个判断句这里出错