接触到一个指针,先不要想它指向哪里,而是把它当成一个变量,这个变量里面存放的值指向哪里。
&取值符,一个变量前边加上它,就代表取该变量的内存地址。
*解指针符,例如:int a=10, *(&a)取的就是该变量的内存地址中存放的内容。
例:int a=10; int *p_a=&a; int **p_p_a=&p_a;
定义一个整形变量a的值是10,定义一个指针p_a指向a的内存地址&a,定义一个指向指针的指针p_p_a指向p_a的内存地址&p_a(&p_a的内存地址中的值就是a的内存地址)。所以*p_a=10,**p_p_a=10;
定义一个整形变量并给他赋值,如:int a=10; 这时会在内存中随意找到一个空间,它保存的值是10。内存会有类似一系列的小空间,每个空间都有对应的地址,地址使用16进制的数字来表示(0x01)。如图(这里0x没有写):
像这样,定义的一个指针p就指向a所在的内存地址。这时,如果想通过指针来改变a的值,需要这样写,下面的 改变的是p指向的内存地址,而不是内存地址中的值。
举个例子(只是在c中会这样):
void numplus(int a){
a++;
}
void main(){
int a=1;
numplus(a);
printf("%d",a);
}
像上面的一段代码,最后的运行结果是a=1,和预想中的结果a=2不同,这是因为在调用numplus()函数时,系统会重新在内存中创建一个名为a的整形变量,并不是将我们之前定义的a传递进去,numplus()函数执行,新创建的整形变量自增,
numplus()执行结束,自动销毁,此时新创建的变量a也跟着销毁,从始至终,之前的变量a都没有发生过改变,所以还是输出1。想要通过函数实现变量自增需要用到指针(也有其他方法,就是将返回类型改成int,再用a来接收),如下代码:
void numplus(int *p){
(*p)++;
}
void main(){
int a=1;
numplus(&a);
printf("%d",a);
}
像这样,a就会自增,这样调用numplus()函数时,会将a的内存地址也就是&a复制给numplus(),就会重新生成一个指针*p,指针*p指向&a,函数执行(*p)++,就是p指针指向的内存地址的值进行自增,函数执行结束后,新生成的*p指针就会销毁掉,可是a中的值也就是&a这个内存地址所存储的值已经发生改变,最后就会输出预期结果2.
再举一个例子:
定义一个数组,一个指针指向数组的第一个数据元素,定义一个方法使指针向后移一位,指向第二个元素。
void remove_p(int arr[],int *p){
p=&arr[1];
}
void main(){
int arr[5]={1,2,3,4,5};
int *p=&arr[0];
printf("%d\n",*p);
remove_p(arr,p);
printf("%d\n",*p);
}
发现结果输出的仍然是1,这是因为在调用函数时传递的是指针p,remove_p()函数会重新生成一个指针p,
remove_p()函数执行改变的是新生成的指针p所指向的地址,
remove_p()函数执行完毕,新生成的指针p就会被销毁,从始至终想要改变的指针p都没有发生任何改变,输出结果也就是1了。想要通过函数来改变的p需要像这样写(也可以改变返回值将函数生成的指针赋给p):
void remove_p(int arr[],int **p){
*p=&arr[1];
}
void main(){
int arr[5]={1,2,3,4,5};
int *p=&arr[0];
printf("%d\n",*p);
remove_p(arr,&p);
printf("%d\n",*p);
}
这样写,在调用remove_p()函数时,将p指针的内存地址传递给remove_p()函数(不是p指针,传递p指针会报错,**p是接收地址),这样remove_p()函数就会生成一个新指针,新指针指向p的内存地址,也就是说新指针的值就是p的内存地址,remove_p()函数执行,改变p的内存地址后,新指针销毁,但是p的内存地址已经被改变。
总结:
指针在函数这里的使用:
在函数的形参为int *p时,想要调用函数,不需要定义指针(也可以定义),只需将变量的内存地址&a传递过去即可。
但是当一个指针指向的是一个数组中的某元素,想要调用函数改变指针时,函数形参为int **p时,这时参数只能接收
定义的指针所指向的内存地址也就是&p.而不能接收指针。也就是说,想在void函数方法中使用指针,只能传递指针
指向的内存地址,不能传递指针