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

C语言进阶:深入探讨指针(一)

我们知道,在C语言中,指针是用于存储内存地址的变量。从底层看,任何被定义的实体(如变量、函数、数组、字符串等)在程序运行时都会占用一块确定的内存空间,就像酒店房间一样,有唯一编号,这些内存块也通过唯一的地址来标识。编译器/运行时系统会为这些实体分配内存,而指针的作用就是记录这些地址,从而实现精准访问。

一、简单的指针

示例:

int a = 8;
// 定义一个整型指针并赋值
int *p = &a;  // a 必须是一个整型变量// 定义一个浮点型指针
float a = 2.5f;
int *p = &a; // a是一个浮点型变量

这类指针相对简单直观,容易理解。

假设:a是一个整型变量,那么指向它的指针类型就是 int *。同理:

  • int * ———— 一般整型指针,指向int类型数据
  • float * ———— 单精度浮点型指针,指向float类型数据
  • char * ———— 字符类型指针,指向字符类型数据
  • unsigned int * ———— 无符号整型类型指针,指向无符号整型数据

其指向结构示意图如下:

如上图所示,指针 p 存储了变量 a 的内存地址(假设为0x44ff0066)。由于 p 指向 a 所在的内存空间,我们可以通过解引用指针p(即 *p)来间接访问或修改变量 a 的值。例如:

int a = 10;
int *p = &a;
*p = 50;

二、多级指针

从指针的定义出发,我们可以进一步思考:​​指针本身也是一个变量​​,既然它能存储其他变量的内存地址,那么​​指针自身的内存地址是否也存在?​​ 答案是肯定的——​​指针变量同样存储在内存中,因此它也有自己的内存地址​​。

既然指针变量也有地址,那么​​我们就可以定义另一个指针(即“指针的指针”)来存储这个地址​​。

例如:

int a = 10;
int *p = &a; // 一级指针
int **p1 = &p; // 二级指针
int ***p2 = &p1; // 三级指针
int ****p3 = &p2; // 四级指针
// 你可以无限套娃

这样形成 p3 ——> p2 ——> p1 ——> p ——> a 的4级间接访问

三、数组中指针的移动

在 C 中,​​指针存储的是内存地址(通常为十六进制数值)​​,而指针运算的本质是 ​​地址的算术偏移​​。其核心规则是:​​指针 ± 整数 = 原地址 ± (整数 × 数据类型字节数)​

3.1、运算的意义

  • 合法运算:如 int* p加 1,实际地址会 ​​向后偏移 4 字节​​(假设 int占 4 字节),指向下一个整数单元。  
  • 非法运算:类似 date + date(日期相加无意义),指针间的直接相加(如 p + q)也无意义,编译器可能报错

因此只有:同一数据类型且指向同一内存区域​​ 的指针才能安全运算。

代码示例:

char arr[11] = {65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75}; 
// 变量arr 就是一个指针它存储的是首元素的地址,即65的地址char* p = arr;    // p 指向数组首地址
p++;             // 地址 +1 → 指向 arr[1]
p -= 2;          // 地址 -2 → 指向 arr[-1](危险!越界访问)

其示意内存图如下所示:

指针减去指针,它可以得到两个相同类型指针之间的距离(元素个数)。类似于日期减去日期可以的到两个日期之间相差的天数。例如:

int* q = &arr[3]; // 假设arr是一个整型数组
ptrdiff_t dist = q - p; // 结果为 2(非字节差)

3.2、指针运算注意事项

void * 类型的指针不能直接进行运算,因为计算机不知到它指向的数据是什么类型,就无法精确得知需要偏移几个字节
需要避免越界情况。

例如:

int arr[3] = {1,2,3};
int *p = arr;
p = p - 1; // 可以计算,但是越界了

上述代码就是一个错误示例,如果这时对 *p 进行解引用操作,是非常危险的。因为你不知到 p 的指向哪里,具体有以下三种情况:

  •  未分配的内存  
  •  其他变量或数据(但你不应该随意访问)  
  •  操作系统保留区域(访问它可能会导致崩溃)
需要避免出现野指针(​​没有被正确初始化​​ 或者 ​​指向了无效内存区域 的指针)

四、指针数组

顾名思义,指针数组是一个用来存储内存地址的数组。

例如:

int a = 0; int b = 0;
int *parr[2] = {&a, &b}; // 指针数组的定义和初始化 

最为典型的是它经常用来存储多个字符串:

#include <stdio.h>int main() {char *names[] = {  // 指针数组,每个元素是 char *"Alice","Bob","Charlie"};int num = sizeof(names) / sizeof(names[0]); // 数组的长度 即 数组大小 / 每个元素的大小for (int i = 0; i < num; i++) {printf("Name %d: %s\n", i + 1, names[i]);}return 0;
}

此外,通过它我们可以模拟二维数组:

int arr[5] = {1,2,3,4,5};
int arr1[5] = {2,4,6,8,10};
int *p_arr[2] = {arr, arr1}; // 达成模拟二维数组的效果
http://www.dtcms.com/a/537407.html

相关文章:

  • 网站备案 信息wordpress支付接口同步回调
  • 当 AI 开始书写历史:我们如何用 Gateone.ai 把“历史人物时间线”从学术幻想变成 SaaS 产品
  • 如何推广企业网站杭州物联网前十名公司
  • SQL Server
  • state machine diagrams用于需求分析阶段还是设计阶段
  • 【穿越Effective C++】Scott Meyers的《Effective C++》逻辑框架概要汇总--各条款是什么?为什么?怎么做?
  • 易旅游网站建设wap网站开发和自适应
  • 免费iOS加固方案指南
  • 登封快乐送餐在那个网站做的广告wordpress版本对应php版本
  • 云南网站建设一度科技网站团购活动页面怎么做
  • 电动自行车为何限速25公里每小时?——安全、法规与技术的平衡之道
  • 怎样用vs2017做网站长沙做网站要多少钱
  • 怎么学建设网站盐城企业建设网站
  • 长沙百度做网站多少钱wordpress页面模板目录文件
  • VLFM视觉语言基础模型使用指南
  • 口碑好的番禺网站建设开饰品店网站建设预算
  • 网站 设计 分辨率wordpress+制作首页模板下载
  • 手写 Vuex4 源码(下)
  • 《HTTPS 的灵魂:加密、认证与数字证书》
  • 电商网站产品模块手机网站推荐几个
  • 考研408——机组OS
  • 公司网站策划书seo站内优化
  • 网站优化计划书金坛建设局招标网站
  • 网站语言包是什么网站建设教育机构
  • 蓝色中网站常德网站建设公司
  • 基于MATLAB的图像处理程序
  • vs2017 网站开发环境有做soho网站的吗
  • Qt笔记:qt5.15.2自行编译qtscript
  • 重庆本地网站有哪些广东省住房和城乡建设厅官网查证
  • 【MySQL体系】第8篇:MySQL集群架构技术详解