接触C语言也快两年了,对指针的理解也一直迷迷糊糊,虽然能用指针解决一些问题,但是对于复杂一点的问题,如两级指针的运用,却感到力不从心,无法做到运用自如,两下子就被搞得晕乎乎的了,究其原因,还是对于指针的理解不深刻导致的。
今天在回顾链表的创建时遇到了一些想不通的情况,于是下了“不到黄河心不死”的决心要把指针弄懂,弄透,终于对指针的理解有了质的提高,发现我以前对指针的理解大错特错了,于是将今天所悟记录下来,方便日后回顾。
如下:
typedef struct _node
{
int data;
struct node* next;
}node;
函数CreateList(node * head)为创建链表的函数;
在main()中有如下语句:
int main()
{
node *head = 0x1111;(这里仅为举例)
CreateList(head);
print(head);
}
但是创建并不成功,什么也打印不出来,在CreateList中,我企图为head开辟空间存入数据,函数逻辑是没有错的,但是却没得到预期结果,我感到很奇怪。我开始是这样认为的,主函数的head的值比如是0X1111(当然这里是NULL),以值传递的方式传入CreateList,那CreateList中head的值仍然是0X1111,在CreateList中为head开辟了内存,也就是为地址0X1111开辟了内存,然后存入数据,既然main函数中head的值也是0X1111,那么当调用CreateList后,main函数中的head也指向了在CreateList中开辟的内存,自然就创建好了链表,但是为什么不行呢?后来经过思考,也是冥冥中恍然大悟,我对指针的理解千错万错就在这里。如 int i = 100; int *p = &i;这样p就指向了i,假设i的地址是addr1,那么p的值也是addr1,接下来如果执行p = new int;我的理解是系统为p开辟了新的内存,也就是为地址addr1开辟了新的内存,地址addr1指向这块内存(现在想起来这种想法误导我很深啊!怪不得以前觉得一些使用指针得到的结果很奇怪),后面我通过打印p的值发现p的值居然不是addr1,而是另外一个值addr2,我仿佛糟了晴天霹雳,呵呵,这真是个伟大的发现,就是这个addr2让我对指针的理解如梦方醒。现在我来概括一下:开始我一直以为int *p = new int 这个语句不是简单的变量赋值,而是为p的值addr(某个地址)开辟一片内存,让p的值addr指向这个新开辟的内存,无论后面执行多少次这个语句,其作用不过是让p的值addr指向新开辟的内存,而p的值addr永远不会变,是1就一直是1,是2就一直是2,这是我以前的想法。现在的理解是:int *p = new int这个语句就是简单的赋值,如果p原来的值为addr1,那么将new int后的值为addr2赋给p,于是p的值就变成了addr2,自然就指向了新内存(天哪,多么简单,不就是变量的赋值吗?真不知道为什么以前想那么复杂),而不是为p原来的值addr1开辟新内存.
现在回过头来看这个例子,当执行完main()后,main()中的head仍然为0x1111,虽然在CreateList中head的初始值也是0x1111,但当在CreateList中执行开辟如new,malloc之类的语句时,不是我开始想的那样为地址0x1111开辟地址,CreateList中head的值已经不再是0x1111,新开辟的内存不是由0x1111指向的,所以在main()中的head是没有指向新开辟的内存,它原来指向哪里,现在还指向那里,它原来为空,现在还为空,因为它的地址仍然是0x1111.
正确的做法是:
CreateList(node ** head);
int main()
{
node *head = 0x1111;(这里仅为举例)
CreateList(&head);
print(head);
}
这样,调用CreateList(node ** head)后,main()中head的值才不为0x1111,而是指向新开辟的内存的值,也许是0xxxxx,呵呵,管它是什么,不重要,反正不是0x1111.
这个对指针认识的过程有很多浅显的地方,让大牛看了觉得可笑,但是我只是记录学习过程中的领悟,方便以后回顾,也是记录我这个菜鸟的成长路程,学习路上总有写可笑的事情。
Good night!!