指针的使用场景通常只有两个,传递和偏移。
一、指针的传递使用场景
例1
// 在子函数内去改变主函数中某个变量的值
// Created by Lee Lucy on 2024/2/24.
#include <stdio.h>
void change(int j){//j是形参
j=5;
}
int main(int argc, const char * argv[]) {
int i=10;
printf("before change i=%d\n",i);//在这里打断点
//C语言的函数调用是值传递,实参赋值给形参,j=i
change(i);//在这里按下箭头,进入change函数
printf("after change i=%d\n",i);
return 0;
}
代码提示位置打断点,然后调试程序,在内存视图输入&i,可以看到变量i的地址是0x61fe1c。向下键(F7)进入change函数,这时变量j的值的确为10,但是&j的值为0x61fdf0,即j和i的地址并不相同。运行j=5后,change函数实际修改的是地址0x61fdf0上的值,从10变成了5,接着change函数执行结束,变量i的值肯定不会发生改变,因为变量i的地址是0x61fe1c而非0x61fdf0.
程序的执行过程是内存的变化过程,需要关注栈空间的变化。当main函数开始执行时,系统会为main函数开辟函数栈空间,当程序走到int i时,main函数的栈空间就会为变量i分配4字节大小的空间。调用change函数时,系统会为change函数重新分配新的函数栈空间,并为形参变量j分配4字节大小的空间。在调用change(i)时,实际上是将i的值赋值给j,称为值传递(C语言的函数调用均为值传递)。因此当在change函数的函数栈空间内修改变量j的值后,change函数执行结束,其栈空间就会释放,j不再存在,i的值不会改变。
如何在子函数中修改main函数内的某个变量的值?
例2
// Created by Lee Lucy on 2024/2/24.
#include <stdio.h>
void change(int *j){//j是形参
*j=5;//*j等价于变量i,间接访问得到变量i
}
int main(int argc, const char * argv[]) {
int i=10;
printf("before change i=%d\n",i);
change(&i);//传递变量i的地址
printf("after change i=%d\n",i);
return 0;
}
将变量i的地址传递给change函数时,实际效果是j=&i,依然是值传递。j是一个指针变量,内部存储的是变量i的地址,所以通过*j间接访问到了与变量i相同的区域,通过*j=5实现了对i的值的改变。通过单步调试,依然可以看到变量j自身的地址是与变量i的地址依然不相等。
二、指针的偏移使用场景
指针的偏移
把对指针的加减称为指针的偏移,加就是向后偏移,减就是向前偏移。
数组名中存储着数组的起始地址0x61fdf0,其类型为整型指针,所以可以将其赋值给整型指针变量p,从监视窗口看到p+1的值为0x61fdf4。为什么加1后不是0xfdf1呢?因为指针变量加1后,偏移的长度是其基类型的长度,即偏移sizeof(int),通过*(p+1)可以得到元素a[1]。编译器在编译时,数组取下标的操作正是转换为指针偏移来完成的。
float *p; p的加减也是偏移4个字节
// 指针的偏移使用场景,对指针进行加减
// Created by Lee Lucy on 2024/2/24.
#include <stdio.h>
#define N 5
int main(int argc, const char * argv[]) {
//数组名内存储了数组的起始地址,a中存储的就是一个地址值
int a[N]={1,2,3,4,5};
int *p;//定义指针变量p
int i;
p=a;//保证等号两边的数值类型一致
for(i=0;i<N;i++){//正序输出
printf("%3d",*(p+i));//与a[i]等价
}
printf("\n-----------------\n");
p=&a[4];//让指针变量p指向数组最后一个元素
for(i=0;i<N;i++){//逆序输出
printf("%3d",*(p-i));
}
printf("\n");
return 0;
}
指针与一维数组
为什么一维数组在函数调用进行传递时,它的长度子函数无法知道呢?——一维数组名中存储的是数组的首地址。eg.数组名c中存储是一个起始地址,所以子函数change传入了一个地址。定义一个指针变量时,指针变量的类型要和数组的数据类型保持一致,通过取值操作,就可将“h”改为“H”,称为指针法。获取数组元素时,可以通过取下标的方式来获取数组元素并进行修改,称为下标法。
// 指针与一维数组的传递
// 练习传递与偏移
// 数组名作为实参传递给子函数时,是弱化为指针的。
// Created by Lee Lucy on 2024/2/24.
#include <stdio.h>
void change(char *d){
*d='H';
d[1]='E';
*(d+2)='L';
}
int main(int argc, const char * argv[]) {
char c[10]="hello";
change(c);
puts(c);
return 0;
}