C语言实现栈初始化出错

在gcc 4.7环境下写了一个简单的链表表示栈的结构,如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct Lnode{
    int data;
    struct Lnode *next;
}Lnode;
//初始化链栈
void initStack(Lnode *ln){
    ln=(Lnode *)malloc(sizeof(Lnode));
    if(ln == NULL){
        printf("error");
    }
    ln->next=NULL;
}
//判断链栈是否为空
int StackEmpty(Lnode *ln){
    return (ln->next==NULL?1:0);
}
//进栈
void push(Lnode *ln,int x){
    Lnode *p;
    p=(Lnode *)malloc(sizeof(Lnode));
    if(p ==NULL){
        printf("ERROR");
        exit(0);
    }
    p->next=NULL;
    p->data=x;
    p->next=ln->next;
    ln->next=p;
}
//出栈
int pop(Lnode *ln,int *x){
    Lnode *p=ln->next;
    if(p ==NULL){
        return 0;
    }
    *x=p->data;
    ln->next=p->next;
    free(p);
    return 1;
}
void printStack(Lnode *ln){
    Lnode *p=ln->next;
    while((p->next)!=NULL){
        printf("%d\n",p->data);
        p=p->next;
    }
}
int main(void){
    Lnode ln;
    int x;
    initStack(&ln);
    push(&ln,2);
    push(&ln,3);
    push(&ln,4);
    push(&ln,5);
    pop(&ln,&x);
    printf("出栈元素为:%d\n",x);

    printStack(&ln);
    return 0;
}

但是在执行initStack函数的ln->next=NULL之后变量的值并没有指向应该的0x0,而是0x39.
如图:
图片说明
这个问题很严重,导致程序后面执行循环时指针访问到不确定的位置报错
是什么原因呢

图片说明

我运行起来没问题哦!

void initStack(Lnode *ln){
这里不对,你用一个指针,只能说函数内外共享这个指针指向的存储地址
但是,如果你在函数内让它指向一个新的地址(malloc那里),那么不会反应到调用者形参(main的ln上)

正确的做法是使用指针的指针,这样才能把分配的新指针带出来。

修改后的代码

// Q694867.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


#include<stdio.h>
#include<stdlib.h>
typedef struct Lnode{
    int data;
    struct Lnode *next;
}Lnode;
//初始化链栈
void initStack(Lnode **ln){
    *ln=(Lnode *)malloc(sizeof(Lnode));
    if(*ln == NULL){
        printf("error");
    }
    (*ln)->next=NULL;
}
//判断链栈是否为空
int StackEmpty(Lnode *ln){
    return (ln->next==NULL?1:0);
}
//进栈
void push(Lnode *ln,int x){
    Lnode *p;
    p=(Lnode *)malloc(sizeof(Lnode));
    if(p ==NULL){
        printf("ERROR");
        exit(0);
    }
    p->next=NULL;
    p->data=x;
    p->next=ln->next;
    ln->next=p;
}
//出栈
int pop(Lnode *ln,int *x){
    Lnode *p=ln->next;
    if(p ==NULL){
        return 0;
    }
    *x=p->data;
    ln->next=p->next;
    free(p);
    return 1;
}
void printStack(Lnode *ln){
    Lnode *p=ln->next;
    while((p->next)!=NULL){
        printf("%d\n",p->data);
        p=p->next;
    }
}
int main(void){
    Lnode * ln;
    int x;
    initStack(&ln);
    push(ln,2);
    push(ln,3);
    push(ln,4);
    push(ln,5);
    pop(ln,&x);
    printf("popped element is: %d\n",x);

    printStack(ln);
    return 0;
}

还有一种改法,根本不需要初始化和分配空间,因为堆栈上的ln实际上就是了

int main(void){
    Lnode ln;
    ln.next = NULL;
    int x;
    //initStack(&ln);
    push(&ln,2);
    push(&ln,3);
    push(&ln,4);
    push(&ln,5);
    pop(&ln,&x);
    printf("popped element is: %d\n",x);

    printStack(&ln);
    return 0;
}

图片说明

看这个图,调用初始化前后,next都是0x39,说明没有反应到ln上

再看使用了指针的指针的情况
图片说明

此时next就是0了。

指针类型也是一个变量,当指针类型作为形参做值传递时,会发生拷贝行为,所以initStack()中的Lnode* ln与mian()中的&ln是两个变量,不信可以分别打印出两者的地址查看是否一致;
修改方式是参数采用指针传递即Lnode** ln。

典型的指针使用不严谨, Lnode ln;和 ln=(Lnode *)malloc(sizeof(Lnode));这两行代码让你的传进去的In和初始化栈函数执行后的In不是同一块内存。