14. C语言 指针(深入理解)

news/2025/1/15 0:11:54/

本章目录:

    • 前言:
      • 什么是指针?
    • 内存与地址:指针的基础
    • 指针的声明与使用
      • 指针变量的声明
      • 指针与地址的关系
    • 空指针与野指针
      • 空指针(NULL Pointer)
      • 野指针(Dangling Pointer)
    • 指针进阶:从数组到函数
      • 指针与数组
      • 指针数组
      • 指向指针的指针
      • 函数指针
    • 指针的算术运算
    • 常见错误与调试技巧
    • 总结


前言:

在 C 语言中,指针是一种存储变量地址的变量。它是理解计算机内存布局、动态内存分配和函数调用背后机制的重要工具。指针不仅能提高程序的灵活性,还能显著提升程序的性能。


什么是指针?

简单来说,指针就是一个变量,其值是另一个变量在内存中的地址。例如:

int a = 10; // 变量 a 的值为 10
int *p = &a; // 指针 p 存储的是变量 a 的地址

在这里:

  • int *p; 定义了一个整型指针变量 p
  • &a 获取变量 a 的内存地址。
  • p 存储的正是变量 a 的地址。

通过指针 p,我们可以访问 a 的值,使用解引用操作符 *

printf("Value of a: %d\n", *p); // 输出 a 的值

内存与地址:指针的基础

理解指针之前,先认识内存地址的意义:

  • 内存可以看作由一系列连续编号的单元组成。
  • 每个变量都存储在特定的内存单元中,& 操作符可获取变量的地址。

示例代码:

#include <stdio.h>int main() {int var = 20;  // 定义一个整型变量int *ip;       // 定义一个整型指针ip = &var;     // 获取 var 的地址并赋值给 ipprintf("Address of var: %p\n", &var);printf("Address stored in ip: %p\n", ip);printf("Value of *ip: %d\n", *ip);return 0;
}

运行结果:

Address of var: 0x7ffeeaae08d8
Address stored in ip: 0x7ffeeaae08d8
Value of *ip: 20

指针的声明与使用

指针变量的声明

指针变量需要声明其类型,以确保指针指向的内存区域正确解释其内容。语法如下:

type *var_name;

示例:

  • int *ip; —— 整型指针
  • float *fp; —— 浮点型指针
  • char *cp; —— 字符型指针

指针与地址的关系

在指针变量中存储地址后,可以通过 * 操作符解引用,访问地址对应的值:

int a = 100;
int *p = &a;
printf("Value of a: %d\n", *p); // 解引用获取 a 的值

注意:

  1. p 是一个指针,存储的是地址。
  2. *p 是指针指向地址中的值。

空指针与野指针

空指针(NULL Pointer)

空指针是一种特殊的指针,表示该指针不指向任何有效的内存地址。初始化指针为 NULL 是一种良好的编程习惯:

int *ptr = NULL;
if (ptr) {printf("Pointer is not NULL\n");
} else {printf("Pointer is NULL\n");
}
  • NULL 常用于检查指针是否被初始化或是否有效。
  • 在多数系统中,地址 0 是保留地址,不可访问。

野指针(Dangling Pointer)

未初始化的指针称为野指针。使用野指针可能导致程序行为未定义,因此,指针在创建后必须初始化:

int *p;      // 野指针
int a = 10;
p = &a;      // 初始化

指针进阶:从数组到函数

指针与数组

数组的名称是一个常量指针,指向数组的起始地址。通过指针可以遍历数组:

int arr[] = {1, 2, 3, 4};
int *p = arr;for (int i = 0; i < 4; i++) {printf("Value at index %d: %d\n", i, *(p + i));
}

指针数组

指针数组是存储指针的数组。例如,一个存储字符串的数组可以定义为指针数组:

char *strings[] = {"Hello", "World", "C Language"};
for (int i = 0; i < 3; i++) {printf("%s\n", strings[i]);
}

指向指针的指针

C 语言允许使用多级指针。二级指针存储的是一级指针的地址:

int a = 10;
int *p = &a;
int **pp = &p;printf("Value of a: %d\n", **pp);

函数指针

函数也有地址,可以通过函数指针调用函数:

#include <stdio.h>void greet() {printf("Hello, World!\n");
}int main() {void (*func_ptr)() = greet; // 定义一个函数指针func_ptr();                // 通过函数指针调用函数return 0;
}

指针的算术运算

指针支持基本算术运算,例如递增(++)、递减(--)和加减(+-)。运算基于指针的类型大小:

int arr[] = {10, 20, 30};
int *p = arr;printf("First element: %d\n", *p);
p++; // 移动到下一个元素
printf("Second element: %d\n", *p);

常见错误与调试技巧

  1. 未初始化的指针:始终将指针初始化为 NULL 或有效地址。
  2. 访问释放的内存:避免使用已经 free 的指针。
  3. 指针越界:确保指针操作不超过分配的内存范围。

调试技巧

  • 使用调试器(如 gdb)检查指针的值和地址。
  • 打印指针的值及其解引用结果,快速定位问题。

总结

指针是 C 语言的核心,掌握指针可以帮助你更深入理解底层操作。通过指针可以高效管理内存、优化代码,并实现许多高级功能。

推荐练习:

  1. 定义一个指针,操作基本数据类型和数组。
  2. 实现一个简单的动态内存分配程序。
  3. 使用函数指针实现回调机制。

学习指针虽有挑战,但一旦掌握,你将在 C 编程中如鱼得水!



http://www.ppmy.cn/news/1563174.html

相关文章

H266/VVC 帧内预测中 ISP 技术

帧内子划分 ISP ISP 技术是在 JVET-2002-v3 提案中详细介绍其原理&#xff0c;在 VTM8 中完整展示算法。ISP是线基内预测&#xff08;LIP&#xff09;模式的更新版本&#xff0c;它改善了原始方法在编码增益和复杂度之间的权衡&#xff0c;ISP 算法的核心原理就是利用较近的像…

centos systemd方式配置jar开机自启

将后端服务&#xff08;一个 Java 应用程序&#xff09;注册为 CentOS 上的 systemd 服务&#xff0c;可以让你方便地管理其启动、停止和重启。以下是详细步骤&#xff1a; 创建 systemd 服务单元文件 创建一个 systemd 服务单元文件&#xff0c;例如 /etc/systemd/system/de…

基于php的web系统漏洞攻击靶场设计与实践

web系统漏洞攻击靶场 摘 要 互联网极速发展的同时&#xff0c;也会带来一些安全性的风险&#xff0c;一些不为人知的安全问题也逐渐暴露出来。近年来&#xff0c;媒体不断披露了许多网络安全事故&#xff0c;许多网络应用程序被黑客攻击&#xff0c;导致内部数据外泄&#xf…

深度学习——pytorch基础入门

一、张量 在PyTorch中&#xff0c;张量是PyTorch中最基本的数据结构。张量可以看作是一个多维数组&#xff0c;可以在GPU上加速运算。PyTorch的张量和Numpy的数组非常类似&#xff0c;但是与Numpy不同的是&#xff0c;PyTorch的张量可以自动地在GPU上进行加速计算。 PyTorch中的…

数据结构与算法之栈: LeetCode 71. 简化路径 (Ts版)

简化路径 https://leetcode.cn/problems/simplify-path/description/ 描述 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 ‘/’ 开头&#xff09;&#xff0c;请你将其转化为 更加简洁的规范路径 在 Unix 风格的文件系统中…

Center Loss 和 ArcFace Loss 笔记

一、Center Loss 1. 定义 Center Loss 旨在最小化类内特征的离散程度&#xff0c;通过约束样本特征与其类别中心之间的距离&#xff0c;提高类内特征的聚合性。 2. 公式 对于样本 xi​ 和其类别yi​&#xff0c;Center Loss 的公式为&#xff1a; xi​: 当前样本的特征向量&…

利用Bi-LSTM实现基于光谱数据对数值进行预测-实战示例

0前言&简介&#xff1a; 本文为《RNN之&#xff1a;LSTM 长短期记忆模型-结构-理论详解-及实战&#xff08;Matlab向&#xff09;》的拓展示例&#xff0c;对于初学者而言&#xff0c;还请先阅读原文&#xff0c;增强理解。 本示例采用了长度为807&#xff0c;样本数为12…

渐变头像合成网站PHP源码

源码介绍 渐变头像合成网站PHP源码&#xff0c;操作简单便捷&#xff0c;用户只需上传自己的头像&#xff0c;选择喜欢的头像框&#xff0c;点击一键合成即可生成专属定制头像。网站提供了167种不同风格的头像框供选择&#xff0c;用户也可以自己添加素材。生成后的头像可以直…