C语言二刷指针篇
&取得变量的地址
printf("%p\n", &a);
printf("%p\n", a);
printf("%p\n", &a[0]);
printf("%p\n", &a[1]);
前三个输出相同,a[0]和a[1]之间相差4
指针就是保存地址的变量,指针里放的是别的变量的地址
p指向i代表p里面的值就是i变量的地址
int *p,q;//*p是int类型
int* p,q;//q是int类型
对于函数:
void f(int *p);
在被调用的时候得到了某个变量的指针:
int i=0;f(&i);
在函数里面可以通过这个指针访问到外面的这个i
如何通过指针访问和操作变量
#include<stdio.h>void f(int* p);
void g(int k);int main() {int i = 6;printf("&i=%p\n", &i);f(&i);g(i);return 0;
}void f(int* p) {printf("p=%p\n", p);printf("*p=%d\n", *p);
}
void g(int k) {printf("k=%d\n", k);
}
上面的代码中,printf("&i=%p\n", &i);用于输出变量i的地址,以便观察变量i在内存中的存储位置。%p是格式化输出符号,用于输出指针(地址)类型的值。
f(&i);调用f函数,并将i的地址作为参数传递给f函数。这样f函数就可以通过指针操作来访问和修改i的值(虽然在这个f函数中没有修改i的值)。
g(i);调用g函数,并将i的值(而不是地址)作为参数传递给g函数。这样g函数会得到i的一个副本,对这个副本的任何操作都不会影响main函数中的i。
f函数接受一个整型指针p作为参数,被初始化为i的地址。
printf("p=%p\n", p);输出指针p的值,也就是i的地址。这与在main函数中输出的&i的值应该是相同的。
printf("*p=%d\n", *p);输出指针p所指向的内存位置的值。由于p指向i,所以这里输出的就是i的值,即6。
&i=000000034277F9F4p=000000034277F9F4
*p=6k=6
修改上面的代码:
#include<stdio.h>void f(int* p);
void g(int k);int main() {int i = 6;printf("&i=%p\n", &i);f(&i);g(i);return 0;
}void f(int* p) {printf("p=%p\n", p);printf("*p=%d\n", *p);*p = 26;
}
void g(int k) {printf("k=%d\n", k);
}
如果在f函数定义时将*p修改为26,那么最后k的值也会是26。
指针的使用
场景一:
交换两个变量
#include<stdio.h>void swap(int* pa, int* pb);int main() {int a = 5;int b = 6;swap(&a, &b);printf("a=%d,b=%d\n",a,b);return 0;
}
void swap(int* pa, int* pb) {int t = *pa;*pa = *pb;*pb = t;
}
场景二:
- 函数返回多个值,某些值就只能通过指针返回
- 传入的参数实际上是需要保存带回的结果的变量
#include <stdio.h>// 这个函数通过指针返回两个值,一个是两个数的和,一个是两个数的乘积
void cal(int num1, int num2, int* sum, int* product) {*sum = num1 + num2;*product = num1 * num2;
}int main() {int num1 = 5;int num2 = 3;int sum_result, product_result;cal(num1, num2, &sum_result, &product_result);printf("The sum of %d and %d is %d\n", num1, num2, sum_result);printf("The product of %d and %d is %d\n", num1, num2, product_result);return 0;
}
在cal函数中sum和product是指针类型的,在main函数中sum和product是整数类型的。
- 函数返回运算的状态,结果通过指针返回
- 常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错:-1和0
- 但是当任何数值都是有效的可能结果时,就得分开返回
#include<stdio.h>int divide(int a, int b, int* result) {int ret = 1;if (b == 0)ret = 0;else {*result = a / b;}return ret;
}int main(void) {int a = 5;int b = 2;int c;if (divide(a, b, &c)) {printf("%d/%d=%d\n", a, b, c);}return 0;
}
上面的代码中通过指针将除法结果返回给调用者,并使用函数返回值表示运算是否成功,这种方式在处理可能出现错误的运算时比较常用。
常见错误:
指针在得到地址前不能被赋值(除了NULL),因为此时被赋的值是一个未知的地址。
如果一个指针没有被初始化(即没有被赋予一个有效的地址)就进行解引用赋值操作会导致未定义行为。
int *ptr;
*ptr = 10; // 错误,ptr未初始化,其值是不确定的,此时进行解引用赋值可能导致程序崩溃或产生不可预测的结果
指针可以被赋予NULL值,这是一种特殊的赋值,表示指针不指向任何有效的内存地址。
int *ptr = NULL;
当要给指针赋予一个有意义的值时,这个值应该是一个已经合法分配内存的地址,比如通过malloc等内存分配函数获得的地址,或者是某个已存在变量的地址。
int num = 5;
int *ptr = # // 正确,将指针ptr指向变量num的地址
从这个意义上说,不能随意将指针指向一个未知的地址,但可以将其初始化为`NULL`或者在确保地址合法性的情况下进行赋值。
指针和数组
数组变量接收数组接收到的是值(普通变量),指针的值(指针)
函数参数表中的数组实际上就是指针。
以下四种函数原型是等价的:
int sum(int *ar,int n);
int sum(int *,int);
int sum(int ar[],int n);
int sum(int [],int);
数组变量是特殊的指针
数组变量本身表达地址
int a[10];
int *p=a;//无需用&取地址
但是数组的单元表达的是变量,需要用&取地址,a==&a[0]
[]运算符可以对数组做,也可以对指针做:p[0]<==>*p
数组变量是const的指针,所以不能被赋值
指针与const
指针是const
表示一旦得到了某个变量的地址,不能再指向其他变量
int * const q = &i;//q是const
*q=26;//ok
q++;//error
比如上面的代码,q只能指向i的事实不能被改变,指针不能指向别人,指针不能被修改
所指是const
表示不能通过这个指针去修改那个变量(并不能使那个变量成为const)
const int *p=&i;
*p=26;//error(*p是const)
i=26;//ok
p=&j;//ok
i和p可以变,i可以被赋予其他值,p可以指向其他地址,但是通过p去修改i就不可以(*p是个常量),变量不能通过该指针改变
总结:const在前,不能改值;const在后,不能改地址
转换:总是可以把一个非const的值转换成const的
void f(const int* x);
int a=15;
f(&a);//ok
const int b=a;
f(&b);//ok
b=a+1;//Error!
当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改
const数组
const int a []={1,2,3,4,5,6};
数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int,所以必须通过初始化进行赋值
如果要保护数组不被函数破坏(修改数组的值),可以设置参数为const
int sum(const int a[], int length)
指针运算
char ac[] = { 0,1,2,3 };char* p = ac;printf("p =%p\n", p);printf("p+1=%p\n", p+1);printf("*(p+1) =%d\n", *(p+1));char ai[] = { 0,1,2,3 };char* q = ai;printf("q =%p\n", q);printf("q+1 =%p\n", q+1);printf("*(q+1) =%d\n", *(q+1));
输出:
p =0000008CB1AFFA44
p+1=0000008CB1AFFA45
*(p+1) =1
q =0000008CB1AFFA84
q+1 =0000008CB1AFFA85
*(q+1) =1
上面代码中,指针加1表示让指针指向下一个变量。如果指针不是一片连续的分配空间,如数组,则这种运算没有意义。
用指针做什么:
- 需要传入较大的数据时用参数
- 传入数组后对数组做操作
- 函数返回不止一个结果
- 需要用函数来修改不止一个变量
- 动态申请的内存
动态内存分配
在程序运行期间根据实际需要来分配和释放内存空间的一种机制。
现在根据用户输入的元素数量动态分配内存来存储一个整数数组,然后从用户获取数组元素的值
#include<stdio.h>
#include<stdlib.h>
int main() {int number;int* a;int i;printf("输入数量:");scanf("%d", &number);a = (int*)malloc(number * sizeof(int));for (i = 0; i < number; i++) {scanf("%d", &a[i]);}for (i = number - 1; i>=0; i++) {printf("%d ", a[i]);}free(a);return 0;
}
相关文章:
C语言二刷指针篇
&取得变量的地址 printf("%p\n", &a); printf("%p\n", a); printf("%p\n", &a[0]); printf("%p\n", &a[1]); 前三个输出相同,a[0]和a[1]之间相差4 指针就是保存地址的变量,指针里放的是别的…...
LeetCode题练习与总结:回文对--336
一、题目描述 给定一个由唯一字符串构成的 0 索引 数组 words 。 回文对 是一对整数 (i, j) ,满足以下条件: 0 < i, j < words.length,i ! j ,并且words[i] words[j](两个字符串的连接)是一个回文…...
CesiumJS 案例 P7:添加指定长宽的图片图层(原点分别为图片图层的中心点、左上角顶点、右上角顶点、左下角顶点、右下角顶点)
CesiumJS CesiumJS API:https://cesium.com/learn/cesiumjs/ref-doc/index.html CesiumJS 是一个开源的 JavaScript 库,它用于在网页中创建和控制 3D 地球仪(地图) 一、添加指定长宽的图片图层(原点为图片图层的中心…...
Redis 主从同步 问题
前言 相关系列 《Redis & 目录》(持续更新)《Redis & 主从同步 & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Redis & 主从同步 & 总结》(学习总结/最新最准/持续更新)《Redis &a…...
【SQL Server】探讨 IN 和 EXISTS之间的区别
前言 在使用 SQL 查询相关表数据时,通常需要根据另一个表中的值来筛选数据。而 IN 与 EXISTS 子句都是用于此场景的常用方式,但使用时两者存在工作方式不同。它们使用上的选择会显著影响查询的性能,尤其是在大型数据集中。本文我们一起探讨 IN 和 EXISTS 之间的区别、使用与…...
清理pip和conda缓存
当用户目录没有空间时,可清理pip和conda缓存 清理conda缓存: conda clean --all清理pip缓存: pip cache purgeNote: 可以利用软链接,将用户目录下的文件链接到其他位置 首先移动文件或文件夹到其他位置 mv ~/test /…...
git rebase和merge的区别
Git merge和Git rebase是两种不同的合并策略,它们在处理分支合并时有各自的优点和缺点。 Git fetch git fetch 命令用于从远程仓库获取最新的更改,但不会自动合并这些更改到你的本地分支。它会下载远程仓库的所有分支和标签,并更新你的本地…...

【elkb】linux麒麟v10安装ELKB 8.8.X版本(ARM架构)
下载软件 相关版本信息 elasticsearch:8.8.1kibana:8.8.1logstash:8.8.1filebeat:8.8.1 下载地址 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.8.1-linux-aarch64.tar.gzhttps://artifacts.elastic…...
bluez hid host介绍,连接键盘/鼠标/手柄不是梦,安排
零. 前言 由于Bluez的介绍文档有限,以及对Linux 系统/驱动概念、D-Bus 通信和蓝牙协议都有要求,加上网络上其实没有一个完整的介绍Bluez系列的文档,所以不管是蓝牙初学者还是蓝牙从业人员,都有不小的难度,学习曲线也相对较陡,所以我有了这个想法,专门对Bluez做一个系统…...
GPT打数模——电商品类货量预测及品类分仓规划
背景 电商企业在各区域的商品存储主要由多个仓库组成的仓群承担。其中存储的商品主要按照属性(品类、件型等)进行划分和打标,便于进行库存管理。图 1 是一个简化的示意图,商品品类各异,件数众多,必须将这些…...

华为OD机试 - 螺旋数字矩阵 - 矩阵(Python/JS/C/C++ 2024 D卷 100分)
华为OD机试 2024E卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试真题(Python/JS/C/C)》。 刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,…...

分类预测 | GCN图卷积神经网络多特征分类预测(MATLAB)
分类预测 | GCN图卷积神经网络多特征分类预测(MATLAB) 目录 分类预测 | GCN图卷积神经网络多特征分类预测(MATLAB)分类效果基本介绍程序设计参考资料分类效果 基本介绍 GCN图卷积神经网络多特征分类预测(MATLAB) 在图卷积神经网络(GCN)中,多特征分类...

FPGA搭建PCIE3.0通信架构简单读写测试,基于XDMA中断模式,提供3套工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案本博客方案的PCIE2.0版本 3、PCIE基础知识4、工程详细设计方案工程设计原理框图XDMA配置及使用XDMA中断模块数据缓存架构用户逻辑Windows版本XDMA驱动安装Linux版本XDMA驱动安装测试应用程序工程源码架构PCIE上板…...

App相关技术以及打包
平时小伙伴们自己的博客网站只能在浏览器打开,但是有时候你想要制作自己独立个人博客app,宣传并推广自己的app,打造个人ip。如何把自己的web博客网站打包成安卓app? 1.开发App的相关技术使⽤ ⽬前市⾯上的移动互联开发技术主要分…...

【unity】【游戏开发】Unity代码不给提示怎么办?
【现象】 Unity用着用着忽然VS脚本不给提示了。 【分析】 重启Unity无效 重启VS无效 重装VS无效 感觉应该是项目设置问题 【最终方法】 打开Edit->Preferences。 如果是这个画面就把Script Editor改成自己的VS编辑器。 变成下面这个样子,点击Regenerate Pr…...
Kubernetes固定Pod IP和Mac地址
方案1: 在 Calico GitHub Issues#5196 问题的 commits#6249 提交中,引入新的 Pod 注释cni.projectcalico.org/hwAddr,用于将指定的 MAC 地址分配给容器端 Veth 接口。 将Calico升级至v3.24.1或以上版本,使用如下注解轻松设置Pod…...
计算机组成原理之数据的对齐和大/小端存放方式、计算机中数据对齐的具体方式有哪些
1、计算机组成原理之数据的对齐和大/小端存放方式 数据对齐 数据对齐是处理器为了提高处理性能而对存取数据的起始地址所提出的一种要求。 系统一次性读取内存中数据的大小是固定的,例如字长为32位的操作系统,默认的一次读取4字节内容。因此ÿ…...

【学术论文投稿】Windows11开发指南:打造卓越应用的必备攻略
【IEEE出版南方科技大学】第十一届电气工程与自动化国际会议(IFEEA 2024)_艾思科蓝_学术一站式服务平台 更多学术会议论文投稿请看:https://ais.cn/u/nuyAF3 目录 引言 一、Windows11开发环境搭建 二、Windows11关键新特性 三、Windows11设计指南 …...

【毕业论文+源码】基于SSM(Spring + Spring MVC + MyBatis)的房屋租赁系统
创建一个基于SSM(Spring Spring MVC MyBatis)框架的房屋租赁系统是一个涉及多个步骤的过程。这个过程包括但不限于需求分析、数据库设计、前端界面设计以及后端逻辑实现等。 1. 需求分析 首先,明确你的房屋租赁系统的功能需求。例如&…...
【golang】解析 JSON到指定结构体
1.解析[1,2,3,4]数组类型的json package mainimport ("encoding/json""fmt" )func main() {// JSON 数据jsonData : [1, 2, 3, 4]// 定义一个切片来接收解析后的数据var numbers []int// 解析 JSON 数据到切片err : json.Unmarshal([]byte(jsonData), &am…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...