当前位置: 首页 > backend >正文

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;
}

http://www.xdnf.cn/news/611.html

相关文章:

  • 深度学习--mnist数据集实现卷积神经网络的手写数字识别
  • Arduino项目中硬件包括哪些部分
  • 软件开发指南——GUI 开发方案推荐
  • LinearLayout 线性布局
  • MLA(多头潜在注意力)原理概述
  • 【Easylive】seataServer.properties 配置文件详细解析
  • 【python】Asyncio包学习 1-5
  • 【排队论】Probabilistic Forecasts of Bike-Sharing Systems for Journey Planning
  • 日语学习-日语知识点小记-进阶-JLPT-N2阶段(6): - (1)ても てでも特别强调(2)~もしないで = 聞かないで:根本不做某动作”
  • 【Java笔记】volatile 关键字
  • javaSE.四大函数式接口
  • Vue3基础
  • 关于一对多关系(即E-R图中1:n)中的界面展示优化和数据库设计
  • leetcode刷题日记——两数之和
  • Linux——firewalld防火墙
  • 2021-11-10 C++蜗牛爬井进3退1求天数
  • 【C++算法】63.字符串_二进制求和
  • 深度解析AI大模型中的模型微调技术:从基础到实践
  • 知识就是力量——一些硬件的使用方式
  • 第二十七讲:AI+农学导论
  • Python基于知识图谱的医疗问答系统【附源码、文档说明】
  • python基础知识点(3)
  • JAVA学习-多线程
  • linux查看目录相关命令
  • Linux系统中的网络传输、网络管理以及软件仓库的构建
  • @EnableAsync+@Async源码学习笔记之四
  • 2025年第十五届MathorCup数学应用挑战赛D题论文全网首发
  • MSCKF——运动方程IMU状态递推(Propagation)
  • 深度补全网络:CSPN++ 有哪些开源项目
  • 2025华中杯挑战赛B题【单车调度】原创论文讲解