............接着上节初始化问题
1.malloc函数的使用:
不知道有没有同学会想,为什么要用mallc初始化,直接用别的变量的地址来初始化它不就好了。
那么不知道你有没有想过,那别的变量哪里啊?难道需要指针的时候先申请一个普通变量,然后再拿来初始化指针?
上章我们讲malloc可以用来初始化指针,它也可以用来动态申请空间,需要指针的时候先申请一个同类型的变量多不方便,
当然是需要多少直接申请多少好啊,所以当你需要更新的指针(或者为指针申请空间)的时候就可以用malloc函数。
我们拿比较常见的带有头节点的单连边解释一下:
#include<iostream>
#include<cstring>
using namespace std;
struct node{
int data;
struct node *next;
};
int main()
{
node *head,*q;
head=(node*)malloc(sizeof(node));//申请头部节点
head->data=0;
head->next=NULL;//为next域指向空
q=head;
int n=0;
scanf("%d",&n);
while(n--){
int temp=0;;
scanf("%d",&temp);
node *p=(node*)malloc(sizeof(node));//更新指针地址,分配新的空间
p->data=temp;
p->next=NULL;
q->next=p;//主要算法区
q=p;// 主要算法区
}
node *t=head->next;
while(t!=NULL){
printf("%d\n",t->data);
t=t->next;
}
}
作者也尝试不用malloc,而是采用需要时,先申请一个node型常变量(我们在这里指的是非指针变量),然后再用指针指向它,
发现并不可行。因为在while循环区域内,每次申请的node常变量的地址都是统一个地方,这就使得计算机一直没有为新变量
分配新的区域,那么在进行下来的算法操作的时候,q->next一直指向同一个地址。这里希望读者能够自行测试一遍,以验证其
是否可行。
2.c++ "&"引用符号的用法
初学c指针的时候,老师一定会讲这么一个函数:
void swap(int *a,int *b){
int temp;
temp=*a;
*a=*b;
*b=temp;
}
老师会说,我们如果在函数参数中定义普通变量,即int a,int b,那么传进来的参数是不会进行交换的,但是定义为指针就可以。
我们都知道函数的生命周期,在函数调用结束后,其内部申请的变量即会销毁。
变量被销毁了,函数又没有返回值,自然不会进行数值交换
有些同学可能会下意识的认为常变量会被销毁(至少我曾经这样认为哈),而指针变量不会。
当然这种想法是严重错误的,指针变量同样会被销毁,没有被销毁的什么呢?!
地址!
这就是指针的思想,指针是通过地址来对那个空间上的值进行操作的,而普通变量直接对应的是空间上的值
我们想一下,上面这个swap函数,调用的时候,传进来的是什么?
int i=3,j=9;
swap(&i,&j);
printf("i:%d j:%d\n",i,j);
没错,是地址!,如果你还是不很懂,那么我想一下,函数调用的每一步是怎么实现的。
假如我们使用的是下面这组
程序1:
void swap(int a,int b){
int t=a;
a=b;
b=t;
}
int main(){
int i=3,j=9;
swap(i,j);
printf("i:%d j:%d",i,j);
return 0;
}
main函数讲i = 3,j = 9传入swap函数,swap函数声明了两个变量,并将a初始化为3,b初始化为9,下来进行了交换操作,
当然我们最后输出的i , j 结果并没有交换。我们可以把这个函数写在函数里面看看,不知道会不会帮助你理解。
程序2:
int main(){
int i=3,j=9;
// swap(i,j);
{
int a=i,b=j;
int t=a;
a=b;
b=t;
}
printf("i:%d j:%d",i,j);
return 0;
}
这两个程序执行的过程差不多是一样的,
不过swap函数中定义的变量在函数调用结束后就销毁了,
而程序2中的变量要在程序结束后才销毁。
然后我们再看传地址的swap程序:
void swap(int *a,int *b){
int temp;
temp=*a;
*a=*b;
*b=temp;
}
int main(){
int i=3,j=9;
swap(&i,&j);
printf("i:%d j:%d\n",i,j);
return 0;
}
地址是存在计算机当中的,自然是不会被销毁,指针是通过这些地址进行的操作,所以传的是地址的时候
函数中的指针也是对这个地址上的值进行操作,地址对应空间上的值是不会随函数中指针的销毁而销毁的。
讲到这里你应该对函数传参有了一定的了解,现在我们在考虑c++ '& '引用的用法
引用是什么意思,我想大家应该都有一定了解,简单的说就是为变量赋了一个新的名字:
int a; ->
&a (a的地址)-> num( a对应的值)
int &b=a;->
下面给个简单示例:
int main()
{
int a=9;
int &b=a;
printf("%d\n",b);
return 0;
}
不知道有没有同学会想,这不就是两个变量名,指向同一个地址嘛,那我用指针不就可以了
确实,很多时候,引用确实可以用指针来代替
但是,当引用变量所指的地址发生改变的时候就不可以用简单的指针来代替了。
举个简单,且常见的例子:
程序1:
void change(int *p){
printf("传进来的地址:%p\n",p);
p=(int *)malloc(sizeof(int));
printf("malloc更新后:%p\n",p);
}
int main(){
int a=9;
int *q;
q=&a;
printf("未传时地址:%p\n",q);
change(q);
printf("传出后地址:%p\n",q);
return 0;
}
运行结果如下:
很明显,我们看到,只有在malloc更新时,函数内的指针地址发生了变化,但并没有将更新后的地址带出change函数。
因为函数内声明的指针已经随着函数调用的结束销毁了,malloc更新的是函数内p的指针地址,而不是传进去的q的地址。
如果我们用引用传递呢?我们只需要在函数声明的时候,在变量名前加上&
程序2:
void change(int *&p){
printf("传进来的地址:%p\n",p);
p=(int *)malloc(sizeof(int));
printf("malloc更新后:%p\n",p);
}
运行结果如下:
我们发现,奇妙的,更新后的地址随着函数调用结束也带了出来!
这就是引用的妙用了,引用声明的变量名可以和用来对进行它初始化的变量当作同一个变量使用。
在程序2中,我们可以看作一直在对同一个变量进行操作;
而程序1,我们是在对两个变量进行操作。
不知道您是否理解了呢?
3.” *& “这是什么意思呢?
我第一次看到这个符号也是很蒙逼,以为是什么没学过的东西,其实还是引用变量,不过是一个指针类型的,仅此而已,哈哈。
int main()
{
int &a;指向整型引用
double &b;指向浮点型引用
struct node &c;指向结构体类型引用
int *&p;指向整型指针的引用
struct node *&q;指向结构体指针的引用
}
能力有限,若有错误或者不足的地方,望大家指出,谢谢!