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

C语言——指针

地址是由物理的电线上产生的,能够标识唯一一个内存单元。在C语言中,地址也叫做指针。

在32位机器中,有32根地址线。地址是由32个0/1组成的二进制序列,也就是用4个字节来存储地址。

在64位机器中,有64根地址线。地址是由64个0/1组成的二进制序列,也就是用8个字节来存储地址。

指针类型

1. 指针类型可以决定指针解引用的时候访问多少个字节(指针的权限)

type* p;
//说明p是指针变量
//type:说明p指向的对象的类型
//说明p解引用的时候访问的对象的大小是sizeof(type)

2. 指针类型还可以决定指针+1时的步长

  • 整型指针+1,跳过4个字节
  • 字符型指针+1,跳过1个字节
  • type* p  + n,跳过n*sizeof(type)个字节

野指针

野指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

野指针的形成原因:

  1. 指针未初始化
  2. 指针越界访问
  3. 指针指向的空间释放

如何规避野指针:

  1. 指针初始化:明确知道指针类型时,应直接初始化;不知道指针初始化为什么值时,暂时初始化为NULL
  2. 小心指针越界
  3. 指针指向空间释放,及时置NULL
  4. 避免返回局部变量的地址
  5. 指针使用前检查有效性

指针运算

1. 指针 +- 整数

#define N_VALUES 5;
float values[N_VALUES];
float *vp;
for(vp=&values[0];vp<&values[N_VALUES]; )
{*vp++;
}

2. 指针 - 指针

指针 - 指针得到的数值的绝对值时指针和指针之间的元素个数

指针- 指针运算的前提是:两个指针指向同一块空间

int main()
{int arr[10] = { 0 };printf("%d\n", &arr[9] - &arr[0]);  //9return 0;
}

3. 指针的关系运算

地址是有大小的,指针的关系运算就是在比较指针的大小

#define N_VALUES 5;
float values[N_VALUES];
float *vp;for(vp = &values[N_VALUES]; vp > &values[0]; )
{*--vp = 0;
}//简化后
for(vp = &values[N_VALUES - 1];vp >= &values[0]; vp-- )
{*vp = 0;
}
//应避免写成简化后的代码。因为C语言规定:
//允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较
//但是不允许与指向第一个元素之前的那个内存位置的指针进行比较

指针与数组

指针:指针变量的大小是4/8个字节,是专门用来存放地址的

数组:是一块连续的空间,可以存放一个或多个类型相同的数据

二者的联系

数组中,数组名就是数组首元素的地址,数组名==地址==指针

当我们知道数组首元素的地址时,因为数组又是连续存放的,所以可以通过指针来遍历访问数组

二级指针

二级指针是用来存放一级指针变量的地址的

int main()
{int a = 10;int* p = &a;//p是一级指针变量,指针变量也是变量,变量是在内存中开辟空间的,是变量就有地址int** pp = &p;//pp是二级指针变量,二级指针变量用来存放一级指针变量的地址 //int* 是在说明pp指向的是int*类型的变量//* 说明pp是指针变量*(*(pp)) = 100; //将100赋给了aprintf("%d\n", a);  //100return 0;
}

指针数组

指针数组是存放指针的数组,数组的每个元素都是指针类型

int arr1[10]; //整型数组——存放整型的数组
char arr2[10];//字符数组——存放字符的数组
int* arr3[10];//指针数组——存放指针的数组
int main()
{int* arr1[10];//存放整型指针的数组char* arr2[10];//存放一级字符指针的数组char** arr3[10];//存放二级字符指针的数组return 0;
}

例:利用指针数组模拟二维数组

int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };int* parr[] = { arr1,arr2,arr3 };int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ", parr[i][j]);  //模拟了一个二维数组,但实际上是三个分开的数组}printf("\n");}return 0;
}

数组指针

数组指针,是指向数组的指针,存放的是数组地址的指针变量

int (*p1)[10];  //数组指针
//*p1是指针,指向的是数组,所以*p1是数组指针变量int* p2[10];  //指针数组

数组指针:是指针,是指向数组的指针

指针数组:是数组,是存放指针的数组

 类比一下整型指针和字符指针

  • 整型指针:指向整型变量的指针,存放整型变量地址的指针变量
  • 字符指针:指向字符变量的指针,存放字符变量地址的指针变量
  • 数组指针:指向数组的指针,存放数组地址的指针变量
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int(*p)[10] = &arr;  //数组的地址,存储到数组指针变量return 0;
}

函数指针

函数指针:就是指向函数的指针

int Add(int x, int y)
{return x + y;
}
int main()
{//类比数组指针/*int arr[10] = { 0 };int(*pa)[10] = &arr;*/printf("%p\n", &Add);printf("%p\n", Add);  //两种写法//函数名是函数的地址//&函数名也是函数的地址int (*pf)(int,int) = &Add;  //pf是函数指针变量//int (*)(int,int)是函数指针类型return 0;
}

函数名表示的是函数的地址。与数组不同的是,&函数名表示的也是函数的地址

数组名表示的是数组首元素的地址

有两个例外

  1. sizeof(数组名),这里的数组名表示的是整个数组
  2. &数组名,这里的数组名表示的也是整个数组

 函数指针数组

函数指针数组是数组,数组的每个元素都是函数指针变量

int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}
int main()
{int (*pf1)(int, int) = Add;int (*pf2)(int, int) = Sub;int (*pf3)(int, int) = Mul;int (*pf4)(int, int) = Div;//函数指针数组int (*pfArr[4])(int, int) = { Add,Sub,Mul,Div };return 0;
}

指向函数指针数组的指针

int (*(*p)[4](int,int) = &pfArr;  //函数指针数组的地址
//p就是指向函数指针数组的指针

区分函数指针、函数指针数组以及指向函数指针数组的指针

void test(const char* str)
{printf("%s\n", str);
}
int main()
{void (*pf)(const char*) = test;//pf是函数指针变量  pf是变量名void (*pfArr[10])(const char*);//pfArr是存放函数指针的数组   pfArr是数组名void (*(*p)[10])(const char*) = &pfArr;//P是指向函数指针数组的指针  p是变量名return 0;
}

回调函数

 回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

举个例子:标准库中有一个函数qsort,用来排序,需要包含头文件#include<stdlib.h>

qsort函数的特点:

  1. 使用快速排序的方式
  2. 适用于任意类型的数据
/*void qsort(void* base,  //指向了需要排序的数组的第一个元素size_t num,  //排序元素的个数size_t size,  //一个元素的大小,单位是字节int (*cmp)(const void*,const void*))  //函数指针类型—这个函数指针指向的函数,能够比较base指向数组中的两个元素*//*void* 的指针—无具体类型的指针void* 类型的指针可以接收任意类型的地址
这种类型的指针是不能直接解引用操作的
也不能直接进行指针运算*/#include<stdlib.h>
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;  //控制升序或降序,当前为升序//return *(int*)p2 - *(int*)p1;   //当前为降序
}
void print(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
void test1()  //测试qsort排序整型数据
{int arr[10] = { 9,8,5,4,3,7,6,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);//qsort 默认是升序排序qsort(arr, sz, sizeof(int), cmp_int);print(arr, sz);
}
//测试qsort排序结构体数据
struct Stu
{char name[20];int age;
};
//按照年龄排序
int cmp_stu_by_age(const void* p1, const void* p2)  
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void test2()   
{struct Stu arr[] = { {"zhangsan",20},{"lisi",16},{"wangwu",19}};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);}//按照姓名排序
int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void test3()
{struct Stu arr[] = { {"zhangsan",20},{"lisi",16},{"wangwu",19} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);}
int main()
{//test1();//test2();test3();return 0;
}

相关文章:

C语言——指针

地址是由物理的电线上产生的&#xff0c;能够标识唯一一个内存单元。在C语言中&#xff0c;地址也叫做指针。 在32位机器中&#xff0c;有32根地址线。地址是由32个0/1组成的二进制序列&#xff0c;也就是用4个字节来存储地址。 在64位机器中&#xff0c;有64根地址线。地址是…...

手搓二分查找

第一种&#xff1a; 该种方法是若a[mid]目标数&#xff0c;则让r一直等于mid&#xff0c;让l往右移动&#xff0c;一直移动到rl&#xff0c;这时候跳出循环&#xff0c;在循环外判断 但是不能写成让lmid&#xff0c;让r往左移动&#xff0c;比如a[2]key&#xff0c;这时&#x…...

pycharm调试(步过(Step Over)、单步执行(Step Into)、步入(Step Into)、步出(Step Out))

pycharm调试 pycharm调试 pycharm调试为什么要学会调试&#xff1f;1. 步过 (Step Over)2. 单步执行 (Step Into)3. 步入&#xff08;Step Into&#xff09;4. 步出&#xff08;Step Out&#xff09; 为什么要学会调试&#xff1f; 调试可以帮助初学者更深入地理解编程基础&am…...

Linux是什么,该如何学习

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Linux的起源与发展 2、Linux在现代计算机领域…...

C++ | Leetcode C++题解之第7题整数反转

题目&#xff1a; 题解&#xff1a; class Solution { public:int reverse(int x) {int rev 0;while (x ! 0) {if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {return 0;}int digit x % 10;x / 10;rev rev * 10 digit;}return rev;} };...

Linux------一篇博客了解Linux最常用的指令

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;Linux &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#…...

vscode安装通义灵码

作为vscode的插件&#xff0c;直接使用 通义灵码-灵动指间&#xff0c;快码加编&#xff0c;你的智能编码助手 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研…...

RIP协议(路由信息协议)

一、RIP协议概述 RIP协议&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;是一种基于距离矢量的内部网关协议&#xff0c;即根据跳数来度量路由开销&#xff0c;进行路由选择。 相比于其它路由协议&#xff08;如OSPF、ISIS等&#xff09;&#…...

SpringBoot根据配置类动态加载不同环境下的自定义配置

dev环境配置 Profile({"dev","test"}) PropertySource("classpath:dev.properties") public class DevConfigLoader { }Profile("prod") PropertySource("classpath:prod.properties") public class ProdConfigLoader { }P…...

什么?穷哥们没钱RLHF?跟我一起DPO吧,丐版一样用

本次DPO训练采用TRL的方式来进行训练 Huggingface TRL是一个基于peft的库&#xff0c;它可以让RL步骤变得更灵活、简单&#xff0c;你可以使用这个算法finetune一个模型去生成积极的评论、减少毒性等等。 本次进行DPO的模型是一个500M的GPT-2&#xff0c;目的是训练快&#x…...

【Leetcode笔记】102.二叉树的层序遍历

目录 知识点Leetcode代码&#xff1a;ACM模式代码&#xff1a; 知识点 vector、queue容器的操作 对vector<int> vec;做插入元素操作&#xff1a;vec.push_back(x)。对queue<TreeNode*> que;做插入元素操作&#xff1a;que.push(root);。队列有四个常用的操作&…...

进程的状态

目录 1.操作系统的进程状态 2.Linux系统的进程状态 特殊的进程状态 进程的查看 1.操作系统的进程状态 a.新建&#xff1a;就是新建一个进程 b.运行&#xff1a;PCB结构体在运行队列中排队 c.阻塞&#xff1a;PCB结构体在等待队列中&#xff0c;等待非CPU资源就续 d:挂起…...

spring-boot集成websocket

引入Maven依赖包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>跟随spingboot版本</version> </dependency>后端代码 /*** 开启WebSocket支持*…...

【Python】【Flask】提交表单后报500错误

【背景】 日常用户使用的一个Online的基于Flask做的工具,今天忽然报错,看现象是点击表单提交按钮后发生错误。报500内部错误。 【分析】 用print步步为营接近root cause。 报错对应视图函数的展示部分正常执行。提交表单按钮后的内容全部没有正常执行。 提交表单用的方法是…...

Golang vs Java

目录 前言 一、语言背景与特性 二、性能与效率 三、生态系统与库支持 四、开发体验与工具支持 五、微服务架构设计中的对比 六、总结与建议 前言 在当今的软件开发世界中&#xff0c;选择合适的编程语言对于项目的成功至关重要。GoLang&#xff08;也称为Golang&#x…...

HomePlug AV

目录 HomePlug AV的基本概念基本术语网络概念网络实例 HomePlug AV物理层&#xff08;PHY&#xff09;HomePlug AV OFDM收发器架构PHY的调制模式FC调制和ROBO调制物理层的特点OFDM频域/时域转换开窗/槽式OFDM信号和噪声PHY发送控制——信道自适应PHY帧格式&#xff08;Symbol&a…...

【面试八股总结】超文本传输协议HTTP(二)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、HTTP缓存技术 将资源&#xff08;如网页、图像、脚本等&#xff09;的副本存储在客户端或中间代理服务器上&#xff0c;以便将来的请求可以直接从缓存中获取&#xff0c;而不必重新从服务器下载资源。这有助于减少网…...

SQL Server中视图使用子查询的性能影响与优化方案

在SQL Server中&#xff0c;视图&#xff08;View&#xff09;是一种虚拟的表&#xff0c;其内容由查询定义。在视图中&#xff0c;我们可以使用子查询来组合和呈现数据&#xff0c;这为数据呈现提供了灵活性&#xff0c;但同时也可能带来一些性能上的问题。本文将深入分析视图…...

Adaboost集成学习 | Matlab实现基于SVM-Adaboost支持向量机结合Adaboost集成学习时间序列预测(股票价格预测)

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 Adaboost集成学习 | 基于SVM-Adaboost支持向量机结合Adaboost集成学习时间序列预测(股票价格预测)基于SVM(支持向量机)和AdaBoost集成学习的时间序列预测(如股票价格预测)是一种结合了两种强大机器学习算…...

Apache DolphinScheduler 【安装部署】

前言 今天来学习一下 DolphinScheduler &#xff0c;这是一个任务调度工具&#xff0c;现在用的比较火爆。 1、安装部署 1.0、准备工作 1.0.1、集群规划 dolphinscheduler 比较吃内存&#xff0c;所以尽量给 master 节点多分配一点内存&#xff0c;桌面和虚拟机里能关的应用…...

手把手教你用4090D单卡24G显存本地跑DeepSeek-R1:KTransformers保姆级安装与避坑指南

手把手教你用4090D单卡24G显存本地跑DeepSeek-R1&#xff1a;KTransformers保姆级安装与避坑指南 最近在折腾大模型本地部署的朋友们&#xff0c;应该都听说过DeepSeek-R1这个671B参数的"巨无霸"。传统认知里&#xff0c;这种规模的模型至少需要专业级GPU集群才能跑起…...

PlatformIO脚本进阶:告别修改库文件,用Python脚本精准控制FreeRTOS heap文件编译

PlatformIO脚本进阶&#xff1a;精准控制FreeRTOS堆管理文件编译的工程实践 在嵌入式开发中&#xff0c;第三方库的管理一直是个令人头疼的问题。特别是像FreeRTOS这样的实时操作系统&#xff0c;其源代码结构往往包含多个可选组件&#xff0c;开发者需要根据具体硬件和需求选择…...

七年之痒:从零复现MaskRCNN的踩坑与重生指南

1. 为什么2024年还要复现MaskRCNN&#xff1f; 七年前第一次看到MaskRCNN的物体检测效果时&#xff0c;那种震撼感至今难忘。作为首个实现实例分割的经典网络&#xff0c;它在COCO数据集上展现的精准边界识别能力&#xff0c;让当时还在用Faster R-CNN的我们直呼"魔法&quo…...

从‘画图’到‘造芯’:模拟版图工程师必须懂的CMOS工艺那些事儿

从‘画图’到‘造芯’&#xff1a;模拟版图工程师必须懂的CMOS工艺那些事儿 当你第一次打开PDK文档&#xff0c;面对密密麻麻的设计规则表格时&#xff0c;是否感觉像在解读天书&#xff1f;作为模拟版图工程师&#xff0c;我们每天都在与纳米级的几何图形打交道&#xff0c;但…...

3个高效学习技巧:如何用JiYuTrainer实现课堂学习体验优化

3个高效学习技巧&#xff1a;如何用JiYuTrainer实现课堂学习体验优化 【免费下载链接】JiYuTrainer 极域电子教室防控制软件, StudenMain.exe 破解 项目地址: https://gitcode.com/gh_mirrors/ji/JiYuTrainer 问题场景&#xff1a;当数字化教学遇上学习需求冲突 "…...

英飞凌Aurix2G TC3XX 中断路由与DMA联动实战解析

1. 中断与DMA联动的核心价值 第一次接触英飞凌Aurix2G TC3XX的中断路由功能时&#xff0c;我像发现新大陆一样兴奋。传统嵌入式开发中&#xff0c;ADC采样完成→CPU读取数据→存入内存的流程就像用勺子一勺一勺地运水&#xff0c;而中断触发DMA的机制则像接上了自来水管——数据…...

从游戏排行榜到实时榜单:手把手用无旋Treap(Fhq Treap)实现一个高性能排名系统

从游戏排行榜到实时榜单&#xff1a;手把手用无旋Treap&#xff08;Fhq Treap&#xff09;实现一个高性能排名系统 在当今的互联网应用中&#xff0c;实时排名系统无处不在——从游戏中的玩家战力榜&#xff0c;到直播平台的礼物贡献榜&#xff0c;再到电商的热销商品排行。这些…...

如何用LuckyLilliaBot在5分钟内构建QQ机器人:OneBot 11协议完全指南

如何用LuckyLilliaBot在5分钟内构建QQ机器人&#xff1a;OneBot 11协议完全指南 【免费下载链接】LuckyLilliaBot NTQQ的OneBot API插件 项目地址: https://gitcode.com/gh_mirrors/li/LuckyLilliaBot 想要快速搭建一个功能强大的QQ机器人吗&#xff1f;LuckyLilliaBot为…...

[小红书AI自动化教程]凌晨2点我在睡觉,AI偷偷发了篇小红书爆款:醒来99+点赞,人类社媒苦役终结?

我把小红书交给 OpenClaw&#xff0c;它开始自己干活了 凌晨两点&#xff0c;我在睡觉&#xff0c;它却偷偷发了一篇爆款。 醒来点赞99&#xff0c;评论全是“姐妹求链接”。这不是科幻。去年我还为追热点熬夜秃头&#xff0c;如今一句“今天发什么”&#xff0c;AI 就能完成选…...

BERT文本分割-中文模型企业应用:内容平台文档结构化

BERT文本分割-中文模型企业应用&#xff1a;内容平台文档结构化 1. 引言&#xff1a;为什么需要文本分割技术 在日常工作中&#xff0c;我们经常会遇到这样的情况&#xff1a;会议记录、访谈稿、讲座内容等长篇口语文字材料缺乏段落结构&#xff0c;阅读起来十分困难。这些由…...