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}; // 达成模拟二维数组的效果
通过短时倒谱(Cepstrogram)计算进行时-倒频分析研究(Matlab代码实现)内容概要:本文主要介绍了项关于短时倒谱(Cepstrogram)计算在时-倒频分析中的研究,并提供了相应的Matlab代码实现。通过短时倒谱分析方法,能够有效提取信号在时间与倒频率域的特征,适用于语音、机械振动、生物医学等领域的信号处理与故障诊断。文中阐述了倒谱分析的基本原理、短时倒谱的计算流程及其在实际工程中的应用价值,展示了如何利用Matlab进行时-倒频图的可视化与分析,帮助研究人员深入理解非平稳信号的周期性成分与谐波结构。; 适合人群:具备定信号处理基础,熟悉Matlab编程,从事电子信息、机械工程、生物医学或通信等相关领域科研工作的研究生、工程师及科研人员。; 使用场景及目标:①掌握倒谱分析与短时倒谱的基本理论及其与傅里叶变换的关系;②学习如何用Matlab实现Cepstrogram并应用于实际信号的周期性特征提取与故障诊断;③为语音识别、机械设备状态监测、振动信号分析等研究提供技术支持与方法参考; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,先理解倒谱的基本概念再逐步实现短时倒谱分析,注意参数设置如窗长、重叠率等对结果的影响,同时可将该方法与其他时频分析方法(如STFT、小波变换)进行对比,以提升对信号特征的理解能力。
先看效果: https://pan.quark.cn/s/aceef06006d4 OJBetter OJBetter 是个 Tampermonkey 脚本项目,旨在提升你在各个在线评测系统(Online Judge, OJ)网站的使用体验。 通过添加多项实用功能,改善网站界面和用户交互,使你的编程竞赛之旅更加高效、便捷。 ----- 简体中文 ----- 安装 主要功能 安装脚本,你可以获得: 黑暗模式支持:为网站添加黑暗模式,夜晚刷题不伤眼。 网站本地化:将网站的主要文本替换成你选择的语言。 题目翻译:键翻译题目为目标语言,同时确保不破坏 LaTeX 公式。 Clist Rating 分数:显示题目的 Clist Rating 分数数据。 快捷跳转:键跳转到该题在洛谷、VJudge 的对应页面。 代码编辑器:在题目页下方集成 Monaco 代码编辑器,支持自动保存、快捷提交、在线测试运行等功能。 些其他小功能…… [!NOTE] 点击 网页右上角 的 按钮,即可打开设置面板, 绝大部分功能均提供了帮助文本,鼠标悬浮在 ”? 图标“ 上即可查看。 使用文档 了解更多详细信息和使用指南,请访问 Wiki 页面。 如何贡献 如果你有任何想法或功能请求,欢迎通过 Pull Requests 或 Issues 与我们分享。 改善翻译质量 项目的非中文版本主要通过机器翻译(Deepl & Google)完成,托管在 Crowdin 上。 如果你愿意帮助改进翻译,使其更准确、自然,请访问 Crowdin 项目页面 贡献你的力量。 支持其他OJ? 由于作者精力有限,并不会维护太多的类似脚本, 如果你有兴趣将此脚本适配到其他在线评测系统,非常欢迎,你只需要遵守 GP...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackispy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值