我们在学习数据结构中的线性表,或者栈队列的时候都遇到了初始化需要传双指针,初学者很不好理解为什么要传递双指针。我根据我个人学习的经验写了这个文章,希望对初学者有一些帮助。同时有不对的地方希望大神们补充。
我们先简单介绍函数调用时的三种参数传递的方法吧~~
1.简单的值传递
这是函数参数传递中最简单的一种,原理是将实参拷贝一份,然后把拷贝的值传递给形参,子函数中如果改变了形参,也只是改变拷贝的数值,并不影响原来的值。
#include<iostream>
using namespace std;
void add(int x)
{
x++;
}
void main()
{
int x = 5;
add(x);
cout<<x<<endl;
}
如上的c++代码原本想要修改x的值,但因为是值传递,最后输出的x还是5
就好像是:我将放在桌子上的笔记拷贝一份给你,你修改了备份,但是我桌子上的笔记并没有改变。
2.指针
int x = 5;
int *p = &x;
那么p表示x的地址,而*p表示该地址的值
主函数将变量的地址通过取地址符&x传过去,子函数通过*x来访问该地址里面的值,因为他们都是对同一个地址修改,所以里面的值自然被修改了。
就好像是:我告诉你我的笔记在那个桌子上(对应内存地址),你直接去桌子上找到那个笔记并修改,因此我的笔记就被修改了。
#include<iostream>
using namespace std;
void add(int *x)
{
(*x)++;
}
void main()
{
int x = 5;
add(&x);
cout<<x<<endl;
}
通过指针直接修改了x的值,输出为6
3.引用
暂时先不用,引用类似于别名
——————-这是并不怎么华丽的分界线——————–
有了上面的知识,我们再来讨论为什么在线性表中我们要用双指针。
我们已经知道了,如果我们要在函数中修改一个变量,我们在传递参数的时候用传递地址,通过指针来修改。
那么问题来了,我们如果要在一个子函数中修改一个指针呢?
我们要将这个指针看作是刚才的那个普通的变量,将指针的地址当参数传递过去。
错误示范如下:
#include <iostream>
using namespace std;
int x = 1, y = 2;
void change(int *p)
{
p = &y;
}
void main()
{
int *p = &x;
cout << *p << endl;
change(p);
cout << *p << endl;
getchar();
}
子函数中修改了指针的指向,如果将指针看成是一个变量,那么这里的参数传递相当于值传递,返回时*p的值还为1
修改为:
#include <iostream>
using namespace std;
int x = 1, y = 2;
void change(int **p)
{
*p = &y;
}
void main()
{
int *p = &x;
cout << *p << endl;
change(&p);
cout << *p << endl;
getchar();
}
为了方便理解,我们可以将其中的*p看成是之前的简单变量x。
那么我们是么时候用指针?什么时候用双指针呢?
当我们在子函数中需要修改传过来的变量,并希望返回时它的值已经改变,我们要用指针。
当我们在子函数中需要修改指针指向的时候(不是修改指针的内容),并希望返回时指针指向已经修改,则需要用双指针。
—————————并不帅气的分界线——————–
现在我们再回过头看数据结构,就会比较清楚了
#include <iostream>
#include <fstream>
using namespace std;
#define datatype int
#define MAXSIZE 5
typedef struct
{
datatype data[MAXSIZE];
int top; //栈顶指针
}SeqStack;
//置空栈
void init_SeqStack(SeqStack **s)
{
(*s) = (SeqStack*)malloc(sizeof(SeqStack));
(*s)->top = -1;
}
//部分省略
void main()
{
SeqStack *s; //创建栈指针
init_SeqStack(&s); //初始化栈
input(s); //从文件输入数据
while (1)
{
select(s);
}
}
因为init_SeqStack函数中修改了栈指针s所指向的内容,所以要是使用双指针。