再学习c指针-结构体

2014-07-24

这是一年前的笔记。

先看一下下面这个程序:

#include <stdio.h>
#include <stdlib.h>
struct node 
{
    int data;
    struct node *next;
};
void push(struct node *nd,int kl);
void show(struct node *nd);
int main(int argc, const char *argv[])
{
    struct node *head=NULL;
    printf("head所在地址:%p\n",&head);
    printf("head本身的内容(也是地址):%p\n",head);
    push(head,1);
    push(head,2);
    show(head);
    return 0;
}
void push(struct node *nd,int kl)
{
    printf("--调用函数push--\n");
    printf("nd所在地址:%p\n",&nd);
    printf("nd本身的内容(是地址):%p\n",nd);
    struct node *p=nd;
    printf("p所在地址:%p\n",&p);
    printf("p本身的内容(是地址):%p\n",p);
    struct node *tmp;
    if (p==NULL)
    {
        p=(struct node *)malloc(sizeof(struct node));
        p->data=kl;
        p->next=NULL;
        printf("p本身的内容(是地址):%p\n",p);
        nd=p;
    }
    else
    {
        while(p->next!=NULL)
        {
            p=p->next;
        }
        tmp=(struct node *)malloc(sizeof(struct node));
        tmp->data=kl;
        tmp->next=NULL;
        p->next = tmp;
    }
}
void show(struct node *nd)
{
    struct node *p=nd;
    while(p!=NULL)
    {
        printf("%d",p->data);
        p=p->next;
    }
}

运行结果如下:

head所在地址:0x7fff608297e8
head本身的内容(也是地址):(nil)
--调用函数push--
nd所在地址:0x7fff608297a8
nd本身的内容(是地址):(nil)
p所在地址:0x7fff608297b0
p本身的内容(是地址):(nil)
p本身的内容(是地址):0x1f29010
--调用函数push--
nd所在地址:0x7fff608297a8
nd本身的内容(是地址):(nil)
p所在地址:0x7fff608297b0
p本身的内容(是地址):(nil)
p本身的内容(是地址):0x1f29030   

可以看到1、2并未入栈,mani()中的show(head);并未输出1、2。

这是为什么呢?

main()中的结构体*head本身内容是nil,调用push(head,1);时候,局部变量*nd本身内容为nil(实参head就是nil)。由于struct node *p=nd;,局部变量*p的的本身内容也为nil。由于p==NULL,进入if的第一个分支,该分支malloc一块内存(假定首地址为0x1——地址写法有问题,只是图个简洁)并由*p指向它,nd=p;使得*nd本身内容为0x1(即*nd就是内存0x1处对应的结构体)。如此,这次push就结束了,但是head本身内容并未改变,所以这次push是没用的,之后的push(head,2);也是达不到目的。
要解决这个问题,其中一个办法是将*head作为全局变量,在push()函数中的if语句的第一个分支的最后加上head=p;。如此,main()中的show(head);就可以输出1和2了。如果不想把head变成全局变量,那么将push函数改为void push(struct node **,int)也是可以的,但是函数内部的变动要大些,调用push时候也变成这样:push(&head,1)

下面这种做法也是可以的:

#include <stdio.h>
#include <stdlib.h>
struct node 
{
    int data;
    struct node *next;
};
void push(struct node *nd,int kl);
void show(struct node *nd);
int main(int argc, const char *argv[])
{
    struct node *head=(struct node *)malloc(sizeof(struct node));
    head->next=NULL;
    printf("head所在地址:%p\n",&head);
    printf("head本身的内容(也是地址):%p\n",head);
    push(head,1);
    push(head,2);
    show(head);
    return 0;
}
void push(struct node *nd,int kl)
{
    printf("--调用函数push--\n");
    printf("nd所在地址:%p\n",&nd);
    printf("nd本身的内容(是地址):%p\n",nd);
    struct node *p=nd;
    struct node *tmp;
    while(p->next!=NULL)
    {
        p=p->next;
    }
    tmp=(struct node *)malloc(sizeof(struct node));
    tmp->data=kl;
    tmp->next=NULL;
    p->next=tmp;
}
void show(struct node *nd)
{
    struct node *p=nd;
    while(p!=NULL)
    {
        printf("%d\t",p->data);
        p=p->next;
    }
}

内存中的情况大致如下:

这个版本有一个问题,就是head本身的data段虽然存在,但是没有内容(也可以手动初始化,例如堆栈中的第一个入栈的数,但是这样的话设计上显得不够完美)。

让push返回一个struct指针也是一个思路,如下:

#include <stdio.h>
#include <stdlib.h>
struct node 
{
    int data;
    struct node *next;
};
struct node * push(struct node *nd,int kl);
void show(struct node *nd);
int main(int argc, const char *argv[])
{
    struct node *head=NULL;
    printf("head所在地址:%p\n",&head);
    printf("head本身的内容(也是地址):%p\n",head);
    head=push(head,1);
    head=push(head,2);
    show(head);
    return 0;
}
struct node * push(struct node *nd,int kl)
{
    printf("--调用函数push--\n");
    printf("nd所在地址:%p\n",&nd);
    printf("nd本身的内容(是地址):%p\n",nd);
    struct node *p=nd;
    printf("p所在地址:%p\n",&p);
    printf("p本身的内容(是地址):%p\n",p);
    struct node *tmp;
    if (p==NULL)
    {
        p=(struct node *)malloc(sizeof(struct node));
        p->data=kl;
        p->next=NULL;
        printf("p本身的内容(是地址):%p\n",p);
        nd=p;
    }
    else
    {
        while(p->next!=NULL)
        {
            p=p->next;
        }
        tmp=(struct node *)malloc(sizeof(struct node));
        tmp->data=kl;
        tmp->next=NULL;
        p->next = tmp;
    }
    return nd;
}
void show(struct node *nd)
{
    struct node *p=nd;
    while(p!=NULL)
    {
        printf("%d\t",p->data);
        p=p->next;
    }
}
( 完 )