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;
}
}