1. 数组指针
char* arr3[6];
char* (*p3)[6] = &arr3;
p3指向一个数组arr3
arr3有6个元素
每个元素的类型是char*
2. 函数指针
指向函数的指针
存放的是函数的地址
int test(const char* str) { }
int (*pf) (const char*) = test
pf指向test函数
test函数的参数是const char*
test函数的返回类型是int
3. (* (void (*) () ) 0) ()
强制类型转换
(void (*) ()) 是函数指针
(void (*) ()) 是0的强制类型转换【(类型):强制类型转换】
把0强制类型转换成函数指针类型
放的是函数地址(0作为地址处的函数)
4. void (* signal (int, void (*) (int) ) (int);
signal是函数名
(int, void (*) (int)是函数指针类型
void (* ) (int)也是函数指针类型,说明signal函数返回的也是一个函数指针类型
以上代码是一次函数声明,声明的signal函数的参数,signal (int, void (*) (int)
第一个参数类型是int
第二个参数类型是函数指针
参数是int,返回类型是int
signal函数的返回类型是一个函数指针
简化
typedef void (* pf_t) (int); //把void (*) (int)类型重命名为pf_t
void (* signal (int, void (*) (int) ) (int);
可以简化成:
pf_t signal (int,pf_t) ;
一、笔试
1.指针是什么
指针的本质是地址
口头上的指针一般指指针变量
指针变量就是一个变量而已,就是一块内存空间,用来存放地址
要学习指针,必须知道内存
内存——内存的单元(1 byte)——编号——地址——指针
编号、地址、指针是同一个东西
两个操作符
&:取地址
*:解引用
int* pa = &a; //pa是指针变量
*pa = 20; //通过pa找到a,并修改a的值为20
2.指针类型的意义(决定2件事)
2-1 决定了+1/-1操作跳过几个字节(步长)
2-2 决定了解引用操作时的权限,访问几个字节
int*:访问4个字节
double*:访问8个字节
3.指针的运算
3-1 +-整数
3-2 指针 - 指针
3-3 指针的关系运算
...
4.指针数组
本质是数组
存放指针的数组
数组中存放的是指针(地址)
3个int*类型的变量
int* pa;
int* pb;
int* pc;
把这3个int*类型的变量存放到数组中
int* arr[3] = {pa,pb,pc}; //3个变量的类型是int*
5.数组名是什么
5-1 数组名大部分情况下表示首元素地址
有2个列外,表示整个数组
5-1-1 sizeof(数组名)
表示整个数组
计算的是整个数组的大小,单位时字节
5-1-2 &数组名
表示整个数组
取出的是整个数组的地址
5-2 &数组名:取出的是数组的地址
数组指针
int a = 0;
int* pa = &a;//pa是整型指针
char ch = ‘w';
char* pc = &ch;//pc是字符指针
int arr[10] = {1,2,3};
int(*parr)[10] = &arr;//parr是数组指针
*:告诉是指针
[10]:10个元素
int:每个元素是int类型
函数指针
int Add(int x,int y)
{
return x+y;
}
int (*pf (int x,int y)) = &Add;//函数的地址存放到函数指针变量中
printf(“%d\n”,&Add);
int sum = (*pf)(2,3);//解引用
函数指针实现回调函数
回调函数:通过函数指针调用的函数就是回调函数
函数指针数组
存放函数指针的数组
int (*pfArr[4] )(int,int)
pfArr[4] :数组,可以放4个元素
int(*)(int,int):数组元素类型
int a[ ] = {1,2,3,4};
sizeof(a); //sizeof(数组名),表示整个数组
sizeof(a + 0); //a不是单独放在sizeof内部,也没有取地址,所以a就是首元素地址,
a+0还是首元素地址;
a<==>&a[0] , a + 0<==>&a[0]+ 0
sizieof(*a);a--首元素地址,*a--首元素
*a就是对首元素地址的解引用,找到的就是首元素
a<==>&a[0], *a<==>*&a[0]
*和&抵消
sizeof(a+1); //第二个元素地址 4/8字节
sizeof(a[1]) // 第二个元素地址
sizeof(&a); //&取的是数组的地址 4/8字节
sizeof(*&a); //&a取出数组的地址
*&a对地址解引用,拿到a
sizeof(*&a)<==>sizeof(数组名)
sizeof(&a+1); //跳过一个数组的地址(一个数组【int a[ ] = {1,2,3,4};】的地址:4个整型元素),还是地址,4/8字节
sizeof(&a[0]); //第一个元素地址
sizeof(&a[0]+1); //第一个元素地址+1<==>第二个元素地址<==>&a[1]
字符数组
char arr[ ] = {'a','b','c','d','e','f'};
sizeof(arr); //sizeof(数组名),整个数组大小
sizeof(arr+0) //首元素地址+0,还是首元素地址
sizeof(*arr); //首元素地址解引用,拿到首元素arr[0]
sizeof(arr[1]) //第二个元素地址
sizeof(&arr) //&arr是数组的地址
sizeof(&arr+1) //取地址+1,跳过整个地址
sizeof(&arr[0] + 1) //第二个元素地址
char arr[ ] = {'a','b','c','d','e','f'};
strlen(arr); //随机值
strlen(arr + 0); //随机值
strlen(*arr); //首元素地址解引用,拿到首元素
//野指针,报错
strlen(arr[1]); //野指针
strlen(&arr) //随机值
strlen(&arr + 1) //随机值-6
strlen(&arr[0]+ 1) //随机值-1
sizeof
操作符
只关注占用内存空间大小,不关注内存中存放的是什么
strlen
库函数
只针对字符串
求字符串长度,关注的是字符串中‘\0’
计算'\0'之前的字符个数
char arr[ ] = "abcdef";
sizeof(arr); //7; 隐藏了一个\0,所以是7个元素
sizeof(arr+0) //首元素地址+0,还是首元素地址
sizeof(*arr) //首元素地址解引用,拿到a
sizeof(arr[1]) //第2个元素
sizeof(&arr) //取出整个数组地址
sizeof(&arr+1) //取地址+1
sizeof(&arr[0]+1) //首元素地址+1
char arr[ ] = "abcdef";
strlen(arr) //字符串长度
strlen(arr+0 //首元素地址+0,还是首元素地址
strlen(&arr) //取出整个数组地址
strlen(&arr + 1) //随机值
strlen(&arr[0] + 1) //5;元素地址+1
char* p = "abcdef";
sizeof(p); //指向字符a,4/8
sizeof(p+1) //4/8
sizeof(*p) //1
sizeof(p[0]) //
sizeof(&p) //
sizeof(&p + 1) //
sizeof(&p[0]+1) //
strlen(p); //6
strlen(p+1) //跳过1个字符,b的后面开始数;5
strlen(*p) //error
strlen(p[0]) //error
strlen(&p) //随机值
strlen(&p + 1) //随机值
strlen(&p[0]+1) //
int a[3][4] = {0};
sizeof(a); //3*4*4; 3行4列*4字节
sizeof(a[0][0]); //
sizeof(a[0]); // 数组名[下标]:访问该行元素,列j的取值0——3;a[0]是第一行
sizeof(a[0]+1) //a[0]第一行第一个元素1地址;a[0]+1----第一行第二个元素地址
sizeof(*(a[0]+1)) //第一行第二个元素
sizeof(a+1) //a表示首元素地址(二维数组的首元素地址是第一行地址);a+1是第二行地址
sizeof(*(a+1)) // 对第二行的地址解引用,拿到第二行
sizeof(&a[0]+1) //&a[0]:对第一行取地址,拿到第一行的地址;&a[0]+1拿到第二行的地址
sizeof(*(&a[0] +1)) //对第二行地址解引用,拿到第二行数据
sizeof(*a) //a表示第一行的地址;*a对第一行地址解引用,拿到第一行的数据
sizeof(a[3]) //访问任意一行
p[4][2] ——>*(*(p-+4)+2)