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

day13-C语言-指针

用途:高效的访问数据 , 传递参数。
特征:
高效,简洁 (相对于普通变量而言)。
指针可以直接访问物理内存,或者直接操作硬件。(单片机开发)。
概念:
内存, 存储运行时的数据。
内存地址: 计算机需要对物理内存进行管理。因为内存空间大,给每个存储单元(1byte)分配一个编号。
这个标号就要内存地址。线性,连续的。
指针: 就是指针变量。专门用来存储内存地址的变量。 在32bit ,任意类型的指针 4byte (0-
0xffffffff)。 64bit ,任意类型的指针 8byte.(0-0xffffffffffffffff) . 指针的类型是 多种多样。 int * (整
形的),char* (字符指针),double*(浮点类型指针)。任意类型的指针大小都是一致。 用指针可以表示
任意的数据。
通过变量名访问内存,直接访问。 如果同指针方式访问,称为间接访问。
当定义变量后,变量名会和对应的内存空间,进行关联。变量名是内存的一个别名。
内存地址,是一个编号。 这个编号和 int类型 在c语言中,是不同的两中类型,支持的运算符,和操作,
是不同

相关的运算符
&,取地址运算符。 获得变量在内存空间中的地址编号。 单目运算符, 从右向左结合。
被操作对象,只能是变量(左值,赋值运算符中的左值)。 不能是常量,或这表达式。
*, 解引用运算符,通过内存地址 获得,变量的数据(内容)。
被操作的对象 ,必须是指针变量。

int a =20; &a; 指针类型 *&a; // 20 int 解引用操作,相当于 降级操作 指针的降级-》 变量类型。 解引用操作的过程 1. 找到指针中存储的地址 2. 根据指针的基类型 (int * --> 基类型 是int .) 的占用内存大小 3. 取出 从地址开始的地方+ 基类型的大小, 取出数据。 取地址操作和 解引用操作,互为反操作。


指针的定义
初始化
指针变量定义好后,一定要初始化。如果不初始化, 会存储随机地址。
野指针:定义后(非全局指针),未给初值的。 指针存储的地址,对应的变量,已经释放的。 不能读写
操作。
空指针: 指针变量定义好后,存储 0 地址的 指针。 NULL

int *p_i; // 定义了一个整形直指针 int* .只能存储整形变量的地址 char* p_c = 0 ; // 都是8 个字节。 空指针 double* p_d ; // 野指针 short* p_s = NULL; //空指针 ,逻辑上先指向0地址。 稍后在给一个合理的地


指针的访问数据
变量的访问 :
直接访问
间接访问

// 初始化 int i_a =20; p_i = &i_a; // 正常初始化 // &20; 只能是 变量 执行取址操作 // &(i_a +10); printf("a is addr %p\n",&i_a); printf("p_i is %p\n",p_i); printf("a is %d\n",i_a); // 直接访问 printf("指针访问,a is %d\n",*p_i); // 间接访问 i_a = 30;// 直接访问 printf("i_a = 30 ,a is %d\n",i_a); *p_i = 50;// 间接访问 printf("*p_i =50, a is %d\n",*p_i);

指针的算术运算
算术 运算(整形) + - * / % ++ --
指针的算术 运算 + - ,++ -- (一般对数组进行访问的时候,会使用 算术运算符)。

指针的加法 int a =20; // 0x2000 int int *p = &a; // 0x2000 &a-> int * printf("a is addr %p\n",&a); printf("p is addr %p\n",p); p=p+1; // p 中存储的地址值 变大。 p中原来的地址 + sizeof(基类型 ,4byte) 0xebbc 0xebc0 printf("p+1 is addr %p\n",p); #include <stdio.h> int main() { int a =20; // 0x2000 int int *p = &a; // 0x2000 &a-> int * printf("a is addr %p\n",&a); printf("p is addr %p\n",p); #if 0 // 减法 p=p-1; printf("p-1 is addr %p\n",p); 先获得p 指针中存储的地址, 和 sizeof(基类型)的大小 进行相减操作。 // p = p*2; // 乘法没有意义 // p = p/2; // 没有意义 // p = p%4; //没有意义 // 加法 先获得p 指针中存储的地址, 和 sizeof(基类型)的大小 进行相加操作。 p++; // p = p+1; printf("p+1 is addr %p\n",p); #endif // 先获得p 指针中存储的地址, 和 sizeof(基类型)的大小 进行相减操作。 p--; printf("p-1 is addr %p\n",p); int b = 20; int *pb = &b; //p+pb ; 两个指向不同变量的指针,进行相加,没有意义。 // p - pb; 两个指向不同变量的指针,进行相减,没有意义。 //如果这两个指针,指向数组的开头, 和数组的结尾。 int i_a[8]={0}; int * p_start = &i_a[0]; int *p_end = &i_a[7]; int ret= p_end - p_start ; //int* -int * 结果类型 int 有意义 相差了几个数据元素 。 (0x2000 -x201c) / sizeof(int) printf("ret is %d\n",ret); }

如果这两个指针,指向数组的开头,和数组的结尾。 相减操作

不同类型的指针的解引用操作

如果执行 * 解引用操作话 。 假设指针存储的地址是0x2000
char* ,取0x2000 开始的1个字节空间的数据
int* ,取0x2000 开始的4个字节空间的数据
short* ,取0x2000 开始的2个字节空间的数据
float* ,取0x2000 开始的4个字节空间的数据
double* ,取0x2000 开始的8个字节空间的数据
如果执行 ++ 。 假设指针存储的地址是0x2000
char* ,偏移量 1byte -> 0x2001
int* ,偏移量 4byte -> 0x2004
short* ,偏移量 2byte -> 0x2002
float* ,偏移量 4byte -> 0x2004
double* ,偏移量 8byte -> 0x2008

内存大小段
对于多字节(大于1字节以上的基本数据类型)的数据。在内存中数据存储字节序。
大小段存储方式,是由CPU 决定。 51单片机,网络设备,都使用大端方式储存数据。 AMD,intel,
ARM ,都是采取小端存储。
小端储存 , 数据的低位在内存的低地址,数据的高位在内存的高地址
大端储存 , 数据的低位在内存的高地址,数据的高位在内存的低地址

#include <stdio.h> int main() 指针的常见操作 指针变量,有两方面的意思。 一个指针指向的内容(数据值,一级) 指针变量本身存储的数据 (地址值) { int a = 0x12345678; // 强制类型转换 char* p = (char*)&a; // char* = int * // *p 从p指向的首地址开始,偏移量+1(byte) ,取出数据 //printf("val: 0x%x\n",*p); if( 0x78 == *p) { printf("小端存储\n"); } else { printf("大端存储\n"); } return 0; }

指针的常见操作

指针变量,有两方面的意思。
一个指针指向的内容(数据值,一级)
指针变量本身存储的数据 (地址值)

#include <stdio.h> int main() { int a =10; int b = 0 ; int c =50; int *p = NULL; int *q = NULL; p = &a; // 对指针变量本身进行修改 p做 左值 // 对指针指向的数据 进行操作 b = *p ;// 通过地址获得地址中数据, 相当与是对 a变量的读取 *p = 20;// 把需要写入的数据,通过地址,写入对应的内存 ,对a 变量的写入 *p做 左值 p = &c; // p变量本身发生变化,与c变量关联 b = *p; // 对c变量读取操作 *p做 右值 *p = 10; //对 c变量的写入操作 q = p;// 把p指向的地址,赋值给q。p,q 指向同一个变量了c。 p做 右值 return 0; } 赋值运算符的左右值 p做 左值 对指针变量本身进行修改, 存储某个变量的地址 p做 右值 把p指向的地址,赋值给另外一个指针。p,另一个 指向同一个变量了。 *p做 左值 向指针指向的变量 写入数据 *p做 右值 读出向指针指向的变量的数据

指针作为参数 ,传参

函数传递参数
1. 值传递, 在主调函数中,实参,在被调函数中,形参。 形参可以读出实参的数据。但是不能修改
实参的值。
2. 地址传递。 在主调函数中,实参,在被调函数中,形参。 形参可以通过间接访问的方式,读写实
参的数据。实参和形参,都是指针。这两个指针中存储的地址值,同一个变量的地址。
函数使用指针作为参数
1. 第一种情况,需要形参修改实参的情况。需要被调函数修改主调函数中数据的值。
2. 函数的返回值只有一个。 在被调函数中,需要返回多个数据的话,就需要传递值指针。因为在被调
函数中可以修改主调函数的参数的值

void swap2(int * pa,int *pb) //地址传递 { int t = *pa; *pa = *pb; *pb =t; } int main() { int a =1; int b =2; //swap(a,b); swap2(&a,&b); printf("a is %d,b is %d\n",a,b); // 指针可以指向 任意0-4G地址 。但是不一定能读写,内存有保护机制 // (int*)0x2000 强制类型转换, 把2000 不当数字看,当地址看 int * p = (int*)0x2000; }

指针和数组的关系
1. 数组名是一个指向数组第一元素的指针常量(指针本身的值,不能发生变化。 指针是保存地址的变
量,指针保存的地址,不能发生变化)。
2. 数组名的类型 ,int a[] ; 类型 int [] ;int [ ] ≈ int * ;
int [ ] ≈ int * ; c语言中,兼容类型。大部分可以相互替换,但是有例外。
不同点:
sizeof() int* --> 8byte int a[20] - > 20*sizeof(int) 80byte
在执行 取地址操作
int*p -> & -> int **(二级指针,地址的地址)
int a[10] -> & -> int (*p)[10] (数组指针)
int a[10] ; 对于数组名a 来说,可以把他想成一个指针变量 。 本质, a 是数组中第一个元素地址的别名。

一维数组做参数

// int fill_array(int a[],int size) int fill_array(int *a, int size) { int i = 0; // for(i=0;i<size;i++) // { // a[i] = rand()%50; // } for (i = 0; i < size; i++) { *(a + i) = rand() % 50; } return 0; }

一维字符数组做参数

//void show_str(char a[]) void show_str(char *a) { int i = 0 ; // while('\0'!=a[i]) // { // printf("%c",a[i]); // i++; // } // printf("\n"); // while('\0'!=*(a+i) ) // { // printf("%c",*(a+i)); // i++; // } // printf("\n"); while('\0'!=*a) { printf("%c",*(a++)); } printf("\n"); }
http://www.jsqmd.com/news/805725/

相关文章:

  • 开源OmenSuperHub:解决惠普OMEN笔记本性能限制的完整技术方案
  • 合肥元森倍健:营养榧塑膳食/香榧产地/香榧价值/香榧作用/香榧功效/香榧瘦身产品/天然榧塑膳食/天然膳食/安徽香榧种植园/选择指南 - 优质品牌商家
  • 第八篇:Spring与微服务——从SpringBoot到SpringCloud的演进
  • 专业Word文档自动化生成:从模板引擎到批量处理实战
  • 从Google Glass拆解看硬件设计:芯片选型、成本控制与可穿戴设备挑战
  • 2026年4月射洪优质装饰公司推荐指南:射洪精装修、射洪装饰公司、射洪家装、射洪装饰、射洪整装、射洪装修公司、射洪装修选择指南 - 优质品牌商家
  • 25mm×35mm的照片像素多少怎么调整?照片调尺寸方法
  • 供应链数字化转型:从线性链条到智能网络的演进与实践
  • 网盘直链解析工具完整指南:技术实现与高效下载策略
  • MCP协议实战:构建AI智能体任务管理服务器与二次开发指南
  • 快速排序的递归与非递归实现
  • 开发者必备:命令行优先的备忘录与代码片段管理工具Mnemon
  • 2026年高强级反光膜全攻略:三类反光膜、二类反光膜、五类反光膜、交通标志杆件、人防标牌、反光交通标牌、反光膜加工选择指南 - 优质品牌商家
  • 手把手带你拿下ElevenLabs Creator认证:从环境配置、语音样本提交到模型定制部署的完整流水线(含GitHub可运行脚本)
  • 2026年5月自贡建筑装饰选材指南:为何任鸟飞成为发泡陶瓷雕花口碑之选? - 2026年企业推荐榜
  • ARM MPMC静态内存控制器架构与寄存器配置详解
  • 2026Q2线上百货加盟权威选择:前置仓加盟/投资即使零售平台/投资线上百货超市/投资网上超市/投资网络超市/本低仓加盟/选择指南 - 优质品牌商家
  • 未来已来:AI驱动的数据湖仓
  • 基于OpenTelemetry的Gemini CLI本地数据驾驶舱部署与实战指南
  • 2026现阶段西安防水堵漏公司深度**:远大加固为何成为行业优选? - 2026年企业推荐榜
  • 基于MCP协议的AssistAI:深度集成Eclipse的AI编程助手实战指南
  • 长沙定制开发本地生活APP打造城市便民消费场景
  • 2篇3章3节:Trae 的高效小说创作与文件管理实操
  • “找档难、找档慢”困扰工作?档案宝智能检索功能,让档案查询秒响应
  • DeepSeek总结的pg_clickhouse v0.3.0的新特性
  • 基于 ESP32-S3 的四博 AI 墨水屏智能音箱方案:CozyLife、Find My、Google 防丢与 MCP 工具控制
  • AMD Ryzen调试神器:SMU Debug Tool终极指南,轻松掌控CPU性能
  • 2026年长沙名表珠宝抵押机构TOP推荐:长沙高档礼品回收、长沙K金回收、长沙包包鉴定、长沙名包回收、长沙名包抵押选择指南 - 优质品牌商家
  • 2026年苏州兼职会计代账选型:苏州兼职会计代账、苏州外贸公司代理记账、苏州注册公司地址挂靠、苏州注册园区地址挂靠选择指南 - 优质品牌商家
  • 黎阳之光:视频孪生硬核赋能,共启数字孪生水利监测新征程