针与数组
1.数组名本身就是一个指针,代表数组的首元素地址。
2.对数组元素进行下标访问的本质,就是对数组名和下标做指针计算的结果解引用
-- arr[i] 等价于 *(arr + i),先算 arr + i ,最后解引用*(arr + i)
-- &pa[0] => pa + 0 => (pa + 0)
3.与通常意义上的指针变量不同
数组名是个指针常量,不能通过再次赋值令其指向其它数据
int a = 10;
arr = &a; //不可以!!
arr++;//不可以!目的是让它指向下一个元素,但arr不可更改!
关系比较方式:
int a[5] = {1,2,3,4,5};
int *pa = a;
for(pa = a; pa < a + size; pa++ ) // a+size指向最后一个元素的地址,一开始pa指向的第一个元素的地址肯定小于最后一个元素的地址
示例:
//数组和指针的那点事儿
#include <stdio.h>
int main(void) {
int a[5] = {1,2,3,4,5};//定义初始化数组,a表示数组的第1个元素的首地址
//a++; //a不允许修改
int *pa = a; //定义初始化指针变量pa来保存数组a的首地址,pa指向a
//以后通过pa访问数组跟通过a访问数组一模一样,但是pa可以++,a不能++
int size = sizeof(a)/sizeof(a[0]); //换算数组元个数
//int size = sizeof(pa)/sizeof(pa[0]);
//写法1:
for(int i = 0; i < size; i++) {
a[i] = a[i] + 1;
*(a+i) = *(a + i) + 1;
pa[i] = pa[i] + 1;
*(pa+i) = pa[i] + 1;
}
for(int i = 0; i < size; i++) {
printf("%d %d %d %d\n", a[i], *(a+i), pa[i], *(pa+i));
}
//写法2:
for(pa = a; pa < a + size; pa++)
*pa = *pa + 1;
for(pa = a; pa < a + size; pa++)
printf("%d ", *pa);
printf("\n");
return 0;
}
注意!
int a[4] = {1,2,3,4};
int *pa = a; //pa指向数组a
则! a = &a[0] = a + 0 = pa + 0 = &pa[0] = pa++ 不能 a++ !!!
a[i] = *(a + i) = pa[i] = *(pa + i)
a[i]本质做两部运算:第一步先算 a + i,先获取第 i 个元素的首地址,第二部做解引用操作: *(a + i) ,最终获取第i个元素值
*pa++:先算pa++,结果是pa,然后对pa做解引用,获取指向的内存值,最后让pa+1,指向下一个元素!
注意!:sizeof(a)/sizeof(a[0]) != sizeof(pa)/sizeof(pa[0]),因为pa始终4/8字节!!!!!
其内存图如下,非常重要!!!!!
泛型指针 ----- void* (无类型指针)
1.仅存储内存地址,不指定目标类型
例如:void *p = &a; //通过p知道a的类型是什么么?
2.目标类型不确定,不能直接解引用,*p; //gcc迷茫了
3.使用前必须先做数据类型转换
4.泛型指针做指针计算,以1字节为单位
p = 0x1000;
p++; //0x001
范例:
//无类型指针
#include <stdio.h>
int main(void) {
int a = 100;
void *p = &a; //定义初始化无类型指针变量p保存a的首地址
//printf("%d\n", *p); //gcc报错
//1.间接法:
int *p1 = (int *)p; //将无类型指针p强转为int类型指针赋值给p1,p1也指向a
*p1 = 200; //一次性修改4字节内存
printf("%d\n", *p1); //一次性获取4字节内存
//2.直接法
*(int *)p = 200; //先将无类型指针p强转为int类型指针,然后解引用一次性获取4字节数据
//然后通过赋值运算符一次性再修改4字节数据
printf("%d\n", *(int *)p); //一次性获取4字节内存
//运算
printf("%p\n", p);
printf("%p\n", ++p);
printf("%p\n", ++p);
printf("%p\n", ++p);
return 0;
}
切记:源类型变量在强制转换前后保持不变