C语言指针2
1.指针大小为什么是4字节或8字节
系统是32位的,则我们能够编号的范围是0-2^32,即为4G的大小,这样一来,为了能够访问到任何一个地址,则我们的指针变量所占空间大小最起码是包含所有的地址表示,反过来,想要表示4G空间的大小,至少是四字节,因此在32位系统下指针大小为4字节,而在64位系统下指针大小为8字节
2.既然指针大小是相同的,为什么要区分不同类型的指针
(1)这里说的不同类型,指的是指向的类型
对指针而言,指向的类型是很重要的一个指标
(2)决定了指针所能操作的内存范围
思考:为什么指针所指类型会决定指针所能操作的内存范围,需从存储角度来理解
int main() {int val = 0x11223344;char* pc = (char*)&val;short* ps = (short*)&val;int* pi = &val;printf("*pc = %x\n", *pc);printf("*ps = %x\n", *ps);printf("*pi = %x\n", *pi);return 0;
}
*pc = 44
*ps = 3344
*pi = 11223344其中pc 、ps、pi指向的地址相同
(3)决定了+1的能力(即指针+1,到底加几个字节)
int main() {int val = 0x11223344;char* pc = (char*)&val;short* ps = (short*)&val;int* pi = &val;printf("pc = %p, pc+1 = %p\n", pc,pc+1);printf("ps = %p, ps+1 = %p\n", ps, ps + 1);printf("pi = %p, pi+1 = %p\n", pi, pi + 1);return 0;
}
pc = 000000555155FA94, pc+1 = 000000555155FA95 加1个字节
ps = 000000555155FA94, ps+1 = 000000555155FA96 加2个字节
pi = 000000555155FA94, pi+1 = 000000555155FA98 加4个字节
struct BBB {
long lA1;
char cA2;
char cA3;
long lA4;
long lA5;
}*p;p = (struct BBB*)0x100000
p + 0x1 = 0x100010
(unsigned long)p + 0x1 = 0x100001
(unsigned long*)p + 0x1 = 0x100004
(char*)p + 0x1 = 0x100001
指针加1,结果是对该指针增加1个储存单位。“存储单位”,指的是指针指向的数据类型所占的内存的字节数。不同类型的指针加1后,增加的大小不同。
在32位系统 int 4字节 char 1字节 unsigned long 4字节
在64位系统 int 4字节 char 1字节 unsigned long 4字节
在32系统,指针变量占4字节
在64系统,指针变量占8字节
3.指针与数组
1.数组指针:首先它是一个指针,它指向一个数组,它是“指向数组的指针”简称,对于数组指针,强调的是指针的概念,只不过,指针的能力是用来指向数组类型的,并且方括号中的数字是固定的,例如:int(*p)[10],p就是指向数组的指针,其中p指针规定了只能指向整型的数组,且数组大小只能是10个整型元素,不能多也不能少,多了少了都会认为其指针的能力与指向的实体不符
2.指针数组:首先它是一个数组,数组的元素都是指针,它是“存储指针的数组”简称。对于指针数组,强调的是数组的概念,只不过,数组保存的类型是指针
//保存指针的数组--指针数组
int* br[3] = {&a,&b,&c};
//数组指针--指向数组的指针
int (*p)[3] = &br;
// *优先级低于括号
int ar[3] = { 1,2,3 };
int *p1 = ar;
int(*ptr)[3] = &ar;printf("ar[0] = %d\n", ar[0]);
printf("&ar[0] = 0x%p, &ar[0]+1 = 0x%p\n", &ar[0],&ar[0]+1);
printf("ar = 0x%p, ar+1 = %p\n", ar,ar+1);
printf("&ar = 0x%p, &ar+1 = 0x%p\n", &ar,&ar+1);
ar[0] = 1
&ar[0] = 0x000000E9A075F668, &ar[0]+1 = 0x000000E9A075F66C
ar = 0x000000E9A075F668, ar+1 = 000000E9A075F66C
&ar = 0x000000E9A075F668, &ar+1 = 0x000000E9A075F674
int ar[10][10] = { 0 };
printf("ar = %d\n", sizeof(ar));
printf("int = %d\n", sizeof(int));short* br[10][10] = { 0 };
printf("br = %d\n", sizeof(br));
printf("char* = %d\n", sizeof(char*));
ar = 400
int = 4
br = 800
char* = 8
试分析以下指针
1.char *(* c[10])(int **p);
2.int (*(*(*pfunc)(int *))[5])(int *);
4.指针与函数
函数指针,首先它是一个指针,只不过,指针所指向的类型是函数,它是“指向函数的指针”简称
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
需要注意的是,指向函数的指针变量没有 ++ 和 -- 运算。
函数名充当函数入口地址
void fun() {printf("This is fun()\n");
}int fun1(int a, int b) {printf("This is fun1()\n");
}int main() {fun();fun1(1, 2);//指向函数的指针-函数指针void(*pfun)() = &fun;void(*pfun_)() = fun;(*pfun)();(pfun_)();int(*pfun1)(int, int) = &fun1;int(*pfun_1)(int a, int b) = &fun1;int a = 1, b = 2;int res = (*pfun1)(a, b); //通过函数指针调用fun1函数return 0;
}
//解构函数指针,相当于执行函数
(*pfun)();
函数指针--回调函数
函数回调本质为函数指针作为函数参数,函数调用时传入函数地址,这使我们的代码变得更加灵活,可复用性更强。
现要编写一个函数实现对数组排序,可以升序排序,也可以降序排序,为了应对不同场景需求,我们需要编写不同的函数,然后这些函数很多代码逻辑是相似的,而我们只需要更改其中判断条件
回调函数:我们可以定义一个函数,个函数需要两个int型参数,函数内部实现代码是将两个整形数字做比较,将比较结果的bool值作为函数的返回值返回出来
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}//升序排序
bool compup(int a, int b) {return a>b;
}//降序排序
bool compdown(int a, int b) {return a < b;
}//将比较函数 compup 或 compdown 作为参数传进
void sort(int* arr,int len ,bool(*comp)(int, int)) {for (int i = 0; i < len - 1; i++) {for (int j = 0; j < len - i - 1; j++) {if (comp(arr[j], arr[j+1])) {swap(&arr[j], &arr[j+1]);}}}
}void show(int* arr, int len) {for (int i = 0; i < len; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int a[] = { 16,1,9,4,7,10,3,5 };int len = sizeof(a) / sizeof(int);show(a, len);//函数指针,函数回调//函数名充当函数入口地址sort(a, len, compup);show(a, len);return 0;
}