之前在写数据结构(链栈)的算法实现的时候出现了一个小问题,我想要实现元素入栈的功能,函数的原型及定义如下:
LinkStack* PushElem(LinkStack *linkstack,int element)
{
if (IsEmptyStack(linkstack))
{
cout<<"该栈为空,无法插入元素"<<endl;
return linkstack;
}
else
{
LinkNode *newnode=new LinkNode;
if (!newnode)
{
cout<<"内存分配失败"<<endl;
return linkstack;
}
else
{
newnode->data=element;
newnode->next=linkstack->top;
linkstack->top=newnode;
return linkstack;
}
}
}
但是奇怪的是,如果不用一个新的LinkStack变量去存储PushElems()函数的返回值的话,传入该函数的LinkStack*指针变量是不会发生改变的。之前认为的是当我给函数传入指针参数的话,该指针所指向的内容应该会发生改变啊!结果却并没有改变。后来在《编写高质量代码——改善C++程序的150个建议》找到了答案。书里面提到了一个例子:
void GetMemory(char *pStr,int num)
{
pStr=new char[num];
}
int main()
{
char *strHello=NULL;
GetMemory(strHello,100);
strcpy(strHello,"Hello C++ Tips");
delete [] strHello;
return 0;
}
其实该示例是无法改变strHello的内存的,
strHello的内存依旧为NULL,所以当把字符串复制给strHello时,程序会崩溃。书里给的解释如下:
“指针函数的每个参数,编译器都要为其生成一个临时副本,指针参数pStr的副本为_pStr,并且会使_pStr=pStr=0x00000000。
在函数内的程序修改了_pStr的内容,也就是改变了_pStr的内存地址,而pStr却丝毫未变,仍旧为NULL。所以函数GetMemory
不能输出任何东西。不仅如此,每执行一次该函数就会造成新的一块内存泄漏。”
将GetMemory函数修改如下:
void GetMemory(char **p,int num)
{
*p=new char [num]
}
“实参str传入函数GetMemory时,传入的是存放指针str的地址address_str,编译器为其生成临时副本_address_str,并且_address_str=address_str=0x000f1850(可能是任意非NULL地址),因此在执行函数语句前,_address_str指向的也是0x00000000。在函数内部,程序修改了_address_str所指向的内存地址,因为两者应指向相同的地址,所以address_str所指向的地址也会发生改变,那么采用指针的指针这种方式可以实现动态内存的传递。”
之前我定义链栈的结构体如下:
typedef struct node
{
int data;
struct node *next;
}LinkNode;
所以如果要改成指针的指针的话,应该修改为下面的这种定义:
typedef struct node
{
int data;
struct node *next;
}LinkNode,*LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
}LinkStack;
所以LinkStack*为一个指针,该指针指向的是LinkStackPTR*(这个同样也是个指针)。所以修改之后便可以达到指向指针的指针的目的了。所以当把LinkStack*传入函数后,函数体内部对指针的修改在函数生命周期结束后依旧有效,可以到达修改的目的。如果你需要修改int*的内容,那么你应该传递int**给函数,同理其他的也是如此。