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…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...