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…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
