二级指针
如果一个指针变量指向的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,又成“二级指针”。
举例分析:
//创建int类型的变量a,值是5,假设变量地址为0x01
int a=5;
int *p=&a;
int **p1=&p;
*p=?,*p1=?,**p1=?
1、*p=?
- 分析之前先确定p是指针(地址),*p是存取值
- 假设&a=0x01,&p=0x05
创建指针变量p,p指向a。
p是一个指针,它存放的是一个地址,因为p指向了a,所以它存放的是a的地址。
所以p=a的地址=0x01
*p是取值,取指针p所对应内存单元中的内容,因为指针p的指向地址是0x01
所以*p使取地址0x01对应的值
所以*p=5;
2、*p1=?
创建二级指针变量p1,p1指向了p,所以p1存放的是p的地址。
所以p1=&p=0x05;
所以*p1是取内存编号0x05所对应的值,0x05里存的是a的地址
所以*p1=a的地址0x01。
3、**p1=?
已经得出*p1=a的地址0x01;
那么**p1就相当于*0x01,也就是取内存地址编号为0x01所对应的内存单元中的值,这个值就是a的值(*0x01=a=5)。所以**p1=5;
4、把上面总结一下就是:*p是取指针p的值,p的地址=a的地址,*p就是取a的地址的值,就是5。*p1是取指针p1的值,p1的地址=p的地址,就是取p的地址的值,就是0x01,同样0x01它也是a的地址。**p1是取二级指针p1的值,综上已经得出*p1就是a的地址,那么我再取a的地址的值,那就是5。
四、指针为什么要区分类型?
* 指针变量在64位编译器中占8个字节
五、数组指针
所谓数组元素的指针就是数组元素的地址。
注意:
数组名不代表整个数组,只代表数组首元素的地址。
“p=a”的作用是“把a数组的首元素的地址赋给指针变量”,而不是“把数组a各元素的值赋给p”。
数组指针的作用:
使用数组指针简介访问数组的元素
数组指针的定义:
int *p;
数组指针的初始化:
int a[4]={1,2,3,4};
int *p=a; //数组指针 定义了一个指针变量p指向数组的首地址
int *p=&a[0]; //等价上面一句话
数组指针的用法:
(1)p+1:表示指向数组的下一个元素
(2)p-1:指向数组的上一个元素
指针遍历数组:
for(int i =0;i<4;i++){
Printf(“%d\t”,*p++);
}
误区:a++是错误的,因为a是数组,他是一个常量。
总结:
获取a[i]地址的方法有几种?
(1)&a[i]
(2)a+i
(3)int *p=a; p+i;
获取a[i]值的方法有几种?
(1)a[i]
(2)*(a+i)
(3)int *p=a; *(p+i)
(4)*(&a[i])
逆序数组:
void nixuArray(int arr[],int len){
//实现思路:让第一个数字与最后一个数字调换位置
//让第二个数字与倒数第二个数字调换位置,以此类推
//定义数组指针,指向数组
int *p=arr;
//定义两个整型变量,让这两个变量分别从数组两端向中间缩进
int i=0,j=len-1;
//定义一个整型变量,作为数字交换时的中转站
int temp=0;
//i<j表示还没调换完
while(i<j){
//调换收尾对应的值的位置
temp = *(p+i);
*(p+i)=*(p+j);
*(p+j)=temp;
//修改下标
i++,j--;
}
}
void main(){
//创建数组
int arr[10]={1,2,3,4,5,6,7,8,9,10};
//调用被调函数,数显数组逆序
nixuArray(arr,strlen(arr));
//循环打印逆序后的数组
for(int i=0;i<){
printf(“%d\t”,arr[i]);
}
}
六、一维指针数组
概念:
一个数组的元素值为指针则是指针数组。
定义:
数据类型 * 数组名 [数组长度];
Int *pa[3];
使用:
int a=3,b=4,c=5;
int *pa[3]={&a,&b,&c};
pa[0] a的地址
pa 数组的首地址,又是变量a的地址
指针变量之间的运算:
(1)两个指针之间的减法运算
1)0x0006-0x0003=3(意义不大)
2)常见的用法:两个指针都指向同一个数组
I.判断两个指针变量指向的元素是否连续
II.判断两个指针变量之间相隔几个元素
int a[5]={1,2,3,4,5};
int *p=a; //p指向了数组的第一个元素
Int *p1=&a[3]; //p1指向了数组的第四个元素
printf(“p1-p=%d\n”,p1-p); //地址差值:(p1-p)*sizeof(int)
注意:两个指针变量之间没有加法运算
* 如果两个指针指向同一个元素,那么他们相减的结果是0
* 判断两个指针变量指向的元素是否相邻,他们相减的结果是+1,-1
(2)两个指针之间的关系运算
// 1表示p1在高位
// 0表示p在高位或者他们指向同一个位置
printf(“p1>p=%d\n”,p1>p);
七、用数组名访问二维数组
3个重要的公式:
a[i]+j = a[i][j];
a[i]=*(a+i);
*(*(a+i)+j)=a[i][j]; //和前两个等价交换
八、二维数组指针的定义、初始化
二维数组指针:
行指针,用来指向二维数组的每一行,存放的是行的首地址。
定义格式:
数据类型 (*行指针变量名) [数组第二维的长度];
九、字符串指针
作用:用来保存一个字符串
定义:char *字符串指针变量名=“字符串”;
例子:
//hahahahahah hehehehe 这个字符串储存在常量区
//str只保存了字符串常量的首地址
//指针变量都是占用8个字节
char *str=”hahahahahah hehehehe”;
print(“%s\n”,str);
//计算长度使用strlen()函数,引入<string.h>
//str是一个指针变量,它保存的是字符串常量的首地址,也是第一个字符的首地址
注意:
1、使用字符数组来保存的字符串是保存栈里的,保存栈里面的东西可读可写。
2、使用字符指针来保存字符串,它保存的是字符串常量地址,常量区是只读的。所以不可以修改字符串中的字符。
注意:
char *str=null; //str=malloc(100);加上这句就正确了
scanf(“%s\n”,str);
//输入后会报错,是因为输入完字符串后,系统没有为字符串分配内存空间。必须要先分配内存空间,然后再存入。
另一种正确的写法:
char ch3[100];
char *str=ch3;
scanf(“%s\n”,str3);
九、二维字符数组
例:char ch2[3][10]={{‘1’},{‘b’},{‘c’}};
用二维数组来保存多个字符串
//用二维的字符数组可以存储多个字符串
//第一维存的是每个字符串的首地址
//每个字符串的长度,不能超过第二维长度
char ch3[3][5]={{‘abc’},{‘def’},{‘kkkk’}};
十、字符串指针和字符数组区别
//字符串指针
char *ss=”abc”;
//字符数组
char ss[]=”abc”;
区别:
ss是一个指针变量,指向可以改变
ss=”hello word”;
S1是一个数组名,是常量,不能被赋值
s1=”hello word”; //错误的 |
|