1 概念:
内存默认以 byte 排序。(可以理解为一维字节数组)
汽油以升(byte)为单位,你加一次油是50升,老板加一次油是88升,
因为汽车类型有大小,(这里称 元素种子 大小)。
所以,每次加油(指针每次加1),跨过的 byte 字节数量,等于 元素种子的大小。
//有些人称此为: 步长
2 指针用法:
& 取对象的地址 * 以对象的值【Value】做地址
u16 A = 10 ; // 内存地址段上取 16bit ,别名 A
u32 B = 11 ; // 内存地址段上取 32bit ,取名字叫 B
int *p; // 分2步理解: 1 整个内存切割成int块,取出一个可用的int块,取名字叫 *P
2 把*p拆开,p保存的是int块的编号。【总内存分割int块后的编号】
3 p的计数类型是int
【就相当于你有1000元,换成2元一张的钞票,能换多少张,钞票的张数编号就是地址编号】
【 1000元,换成5毛一张的钞票,能换多少张,钞票的张数编号就是地址编号】
p = &A; // 取出 A地址编号 给 p对象的Value
*p = 22 ; // 这样 A的值是22
// 【*p】对象p的Value做地址,找到这个地址后,在地址上赋值22,实际就是A=22
u16 A = 10 ; // 内存地址段上取 16bit ,别名 A
u32 B = 11 ; // 内存地址段上取 32bit ,取名字叫 B
Byte *p; // 分2步理解: 1 整个内存切割成Byte块,取出一个可用的Byte块,取名字叫 *P
2 把*p拆开,p保存的是Byte块的编号。【总内存分割Byte块后的编号】
3 p的计数类型是int
【就相当于你有1000元,换成5元一张的钞票,能换多少张,钞票的张数编号就是地址编号】
【 1000元,换成20元一张的钞票,能换多少张,钞票的张数编号就是地址编号】
p = &A; // 取出 A地址编号 给 p对象的Value
*p = 22 ; // 这样 A的值是22
// 【*p】对象p的Value做地址,找到这个地址后,在地址上赋值22,实际就是A=22
注:思考下【p的计数类型是int】 ++P后,地址偏移8bit长度。
这相当于:【零件盒子装钥匙】和【集装箱装钥匙】,集装箱地址加1偏移的bit就大。而钥匙始终
是CPU的int计数类型。
type *var_name;
type 是指针的基类型,它有 int,double,float。。。。等等
int *ptr = NULL;
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
是把总的内存切割成 type块,然后再去找第type块的偏移位置
p也是个对象,它存储的值做地址使用,【*p】定位到对象p的值【Value】的地址上
可以理解成,p存储的是指针值。
【*p】定位到指定的地址上,等待操作
*( volatile int * ) 0x80 = 0x81;
// 方向从右向左
// *取地址
// 系统总内存切割成【volatile int】长度的块,然后找到编号第0x80的块
// int* 0x80 总内存切割成 int块,偏移到 0x80的位置 //相当于【int长度乘以0x80】
//
// 最左边的*是取地址: 【int *】只是int被省略了,
*0x80地址的值 num
*num地址的位置上,再赋值0x81;
// 最左边的*是取地址: 取出对象【*0x80】的值add,然后取对象【*add】给它赋值 0x81
3 二级指针:【从右到左】先获取地址,再对参考类型偏移
语法 int **P = NULL; // 实际完全体是【int* int* P】
*(*P) // 从右向左
分析:
先 *P //【int *】这里int可以略写, 得到了地址编号 ,
再 * //在编号地址上开垦 int类型的长度,等待被赋值。
*P 这个P也是个对象,它的类型type,把总内存切割成tpye块,P的值,就是第n个type块地址,
有了这个地址后,再对他操作。
* 左边也有类型int,就是把总内存切割成int块,第n个【int块】的地址上,再对它操作。
参考:
const int * const int * P = NULL;
byte * type_对象类型 * P = NULL;
byte * byte * P = NULL;
4函数指针:
函数指针变量可以作为某个函数的参数来使用的
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
int max(int x, int y)
{
return x > y ? x : y;
}
int main(void)
{
/* p 是函数指针 */
int (* p)(int, int) = & max; // &可以省略
int a, b, c, d;
printf("请输入三个数字:");
scanf("%d %d %d", & a, & b, & c);
/* 与直接调用函数等价,d = max(max(a, b), c) */
d = p(p(a, b), c);
printf("最大的数字是: %d\n", d);
return 0;
}
typedef unsigned char u8;
地址从0开始自增;地址类型就是cpu类型,且不能被改变。比如32位的cpu地址只能到4g
用*取址符,可以在地址上存放用户类型的数据。比如char或者student
绝对地址每次加1,间隔一个字节;(如果类型+1,就要看这个类型占多少个字节)
*地址 //解释为找到该地址;(取值)或者说:取址符,取出地址上的值
& 这个符号是取地址。
数组的名字就是首地址。 *数组名(就是数组【0】下标0存储的值)
char *地址 //解释为,找到该地址后,取出 char类型的左值;
int *地址 //解释为,找到该地址后,取值 int类型;
int *app //app为变量,它有自己的地址,可以用&app取出地址。
int *app //app为变量,可以赋值。 app=(int *)0xfff2018
函数名 delay() 等效于 #define delay *APP
地址可用长度由设备决定。32位机器最大4GB。
const1 int* const2 *APP
*(int[]){1,2}=99; //匿名数组int【2】,第一个下标值【0】改为99
int *ppp(int X,int Y);
&main();
地址指针*(volatile int*)0x40020010=data;//方向,从右到左
第1*号是 取地址,第2*号是左值类型值(强制类型转换)。0x40020010是地址,data是给左值赋值用的,在地址0x40020010上赋值。
先将0x40020010转为地址类型,再*取址符,取出这个寄存器上的值,再把data的值放到这个寄存器上。
指针*(int*)0x80=0x8f;int *p=(int*)0x80;取地址int *p=&i;*p为房间号*p=NULL;//0给*p这个房间static静态typedef extern continue sizeof const
4级指针:
以下是2级指针、3级指针和4级指针的C语言Demo:
2级指针:
```
#include <stdio.h>
int main() {
int a = 10;
int *p1 = &a;
int **p2 = &p1;
printf("a的值为:%d\n", a);
printf("p1指向的值为:%d\n", *p1);
printf("p2指向的值为:%d\n", **p2);
return 0;
}
```
3级指针:
```
#include <stdio.h>
int main() {
int a = 10;
int *p1 = &a;
int **p2 = &p1;
int ***p3 = &p2; printf("a的值为:%d\n", a);
printf("p1指向的值为:%d\n", *p1);
printf("p2指向的值为:%d\n", **p2);
printf("p3指向的值为:%d\n", ***p3);
return 0;
}
```
4级指针:
```
#include <stdio.h>
int main() {
int a = 10;
int *p1 = &a;
int **p2 = &p1;
int ***p3 = &p2;
int ****p4 = &p3;
printf("a的值为:%d\n", a);
printf("p1指向的值为:%d\n", *p1);
printf("p2指向的值为:%d\n", **p2);
printf("p3指向的值为:%d\n", ***p3);
printf("p4指向的值为:%d\n", ****p4);
return 0;
}
```