您的位置:首页 > 编程语言 > C语言/C++

C/C++中二级指针的理解

2016-04-12 22:27 127 查看
以前在学习数据结构的时候一直没弄懂函数参数里面传递 ** p 以及使用 &的含义,这里摘抄了一小段文章方便理解。不懂的时候再看看这几段代码。

指针参数是如何传递内存的?

如果函数的参数是一个指针,不要指望用该指针去申请动态内存。见如下例子:

void GetMemory(char *ip, int num)

{

 ip = (char *)malloc(sizeof(char) * num);

}

void Test(void)

{

 char *str = NULL;

 GetMemory(str, 100); // str 仍然为 NULL

 strcpy(str, "hello"); // 运行错误

}

试图用指针参数申请动态内存

毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数ip的副本是 _ip,编译器使 _ip = ip.如果函数体内的程序修改了_ip的内容,就导致参数ip的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_ip申请了新的内存,只是把_ip所指的内存地址改变了,但是ip丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。

如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见如下示例:

void GetMemory(char **p, int num)

{

 *p = (char *)malloc(sizeof(char) * num);

}

void Test(void)

{

 char *str = NULL;

 GetMemory(&str, 100); // 注意参数是 &str,而不是str

 strcpy(str, "hello");

 std::cout<< str << std::endl;

 free(str);

}

这里写一段自己的理解:这个程序是想通过函数给str指针分配一点内存--malloc,然后再给str指针赋值。。。注意这是在另一个函数内部改变str'指针的指向(str原来是指向NULL的,现在要使之指向函数GetMemory内分配的内存区域)所以要使用二级指针来实现,其实质就是改变str指针的指向(比如从 指向A 改为指向B),而不是改变str指针指向地址的内容哦。

用指向指针的指针申请动态内存

当然,我们也可以用函数返回值来传递动态内存。这种方法更加简单,见如下示例:

char *GetMemory(int num)

{

 char *ip = (char *)malloc(sizeof(char) * num);

 return ip;

}

void Test(void)

{

 char *str = NULL;

 str = GetMemory(100);

 strcpy(str, "hello");

 std::cout<< str << std::endl;

 free(str);

}
我们在做链表的时候,我们肯定希望在用一个函数creatLink(...)函数来增加链表节点。那么我们可以有2种方法来实现

第一种,用一级指针

[cpp] view
plain copy

typedef struct node{

...

...

}list;

node *create(list *l){

list *head;

head = l;

malloc...//为节点申请内存空间

...

...

//操作

return head;

}

int main(...){

...

...

list *listhead

createList(listhead);

....

//以后的任何操作,我们都要考虑,我们是否拿到的是链表头指针,到底哪个是链表波的头指针,我们是否要renturn下来返回链表头指针??等。。。。

}

这样做可以达到删除增加节点的目的,但是,在任何情况下,我们的操作都得死死地抓住头指针,也即是我们增加删除节点后,任何对链表长度的修改,我们都要 链表头指针返回,即 return head;所以,我们要通过这个函数最后获得头指针,抓住他,死死地抓住他,然后操作。

第二种方法:用双指针,也即是二级指针。

[cpp] view
plain copy

typedef struct node{

...

...

}list;

void create(list **l){

list *head;

head = *l; //这里不知道写成 *l 对不对,原文是写的l,我自己觉得应该是 *l

malloc...//为节点申请内存空间

...

...

//操作

}

int main(...){

...

...

list *st

createList(st)

....

..

//以后的任何操作,不管是删除还 是插入,我们不需要考虑,我们是否已经return head了,不需要,我们在任何情况下,对链表的操作都只需要使用st来完成,因为,st就是链表的头指针,不变,因为在申明st的时候,已经为st分配 一个地址空间,它是存在的,一直存在,直到main函数结束

}

总结: 如果函数参数中传递的是指针,而且想改变传入指针的指向的话,则可以使用 二级指针来实现。(当然如果不在函数中的情况则可以直接给一级指针重新赋值使之指向另一个数据)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: