C语言——指针基础知识

news/2025/2/19 4:33:50/

引言

指针(Pointer)是 C 语言中最核心、最强大的特性之一,也是许多初学者的“拦路虎”。它直接操作内存地址的能力,赋予了 C 语言高效灵活的特性,但也带来了潜在的风险。理解指针的底层逻辑和正确使用方式,是掌握 C 语言的关键一步。本文将以通俗易懂的方式,结合代码示例,系统讲解指针的基础概念、运算规则、常见应用场景及避坑指南。


一、指针是什么?

1. 内存地址与指针变量

  • 内存地址:计算机内存被划分为连续的存储单元,每个单元有唯一的地址(如 0x7ffd42a8)。

  • 指针变量:专门用于存储内存地址的变量。

int num = 10;      // 定义一个整型变量
int *p = #     // p 是指向 num 的指针变量

2. 指针的声明与初始化

语法含义示例
数据类型 *指针名;声明一个指针变量int *p;
指针名 = &变量;将变量地址赋值给指针p = #
*指针名解引用(访问指针指向的内存值)printf("%d", *p);

二、指针的运算

1. 指针的算术运算

指针的加减操作以数据类型大小为单位移动地址。

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;       // p 指向数组首元素printf("%d\n", *p);       // 输出 1
printf("%d\n", *(p + 2)); // 输出 3(p 向后移动 2 个 int 长度,即 8 字节)

2. 指针与数组的关系

数组名本质是数组首元素的地址,指针可替代数组下标访问元素:

// 通过指针遍历数组
int arr[3] = {10, 20, 30};
int *p = arr;
for (int i = 0; i < 3; i++) {printf("%d ", *(p + i));  // 输出 10 20 30
}

 

三、指针的应用场景

1. 动态内存分配

使用 malloc 和 free 管理堆内存:

int *arr = (int *)malloc(5 * sizeof(int)); // 分配5个int的内存
if (arr != NULL) {for (int i = 0; i < 5; i++) {arr[i] = i + 1;  // 初始化数组}free(arr);  // 释放内存arr = NULL; // 避免野指针
}

2. 函数参数传递

通过指针实现函数内修改外部变量(值传递 vs 地址传递):

// 错误示例:值传递无法修改外部变量
void swap(int a, int b) {int temp = a;a = b;b = temp;
}// 正确示例:通过指针传递
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 5, y = 10;swap(&x, &y);  // x=10, y=5return 0;
}

3. 指针与字符串

C 语言中字符串以字符数组形式存储,可通过指针操作:

char str[] = "Hello";
char *p = str;
while (*p != '\0') {printf("%c ", *p);  // 输出 H e l l op++;
}

四、指针的常见错误与避坑指南

1. 野指针(Dangling Pointer)

指向已释放内存的指针:

int *p;
{int num = 100;p = &num;  // p 指向局部变量 num
}              // num 超出作用域被释放
*p = 200;      // 错误!操作非法内存

解决方法

  • 指针初始化时赋值为 NULL

  • 释放内存后立即将指针置为 NULL

2. 内存泄漏

未释放动态分配的内存:

void func() {int *p = malloc(100 * sizeof(int));// 忘记调用 free(p)
}

解决方法

  • 确保每个 malloc 对应一个 free

  • 使用工具(如 Valgrind)检测内存泄漏。

3. 空指针解引用

int *p = NULL;
printf("%d", *p);  // 程序崩溃!

解决方法

通过不断练习和调试,指针将成为你编写高效 C 代码的利器。


参考资料

如果你对指针的某个概念仍有疑问,欢迎在评论区留言讨论!


  • 操作指针前检查是否为 NULL

    if (p != NULL) {*p = 100;
    }

    五、总结

    指针是 C 语言的灵魂,它直接操作内存的能力带来了极高的灵活性和效率,但也需要开发者谨慎使用。理解以下核心要点是关键:

  • 指针存储的是内存地址,通过 * 解引用访问数据。

  • 指针运算以数据类型大小为单位。

  • 动态内存分配后必须手动释放。

  • 避免野指针和空指针解引用。

  • 《C Primer Plus》 - Stephen Prata

  • 《C和指针》 - Kenneth A.Reek

  • GeeksforGeeks: Pointers in C


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

相关文章

图形渲染(一)——Skia、OpenGL、Mesa 和 Vulkan简介

1.Skia —— 2D 图形库 Skia 是一个 2D 图形库&#xff0c;它的作用是为开发者提供一个高层次的绘图接口&#xff0c;方便他们进行 2D 图形渲染&#xff08;比如绘制文本、形状、图像等&#xff09;。Skia 本身不直接管理 GPU 或进行底层的渲染工作&#xff0c;而是通过 底层图…

【Elasticsearch】字符过滤器Character Filters

在 Elasticsearch 中&#xff0c;字符过滤器&#xff08;Character Filters&#xff09;是文本分析器的重要组成部分&#xff0c;用于在分词之前对原始文本进行预处理。它们可以对字符流进行转换&#xff0c;例如添加、删除或更改字符。Elasticsearch 提供了三种内置的字符过滤…

基于大数据的汽车之家汽车数据分析系统的设计与实现

【FLask】基于大数据的汽车之家汽车数据分析系统的设计与实现&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 随着汽车市场的快速发展和消费者需求的日益多样化&#xff0c;汽车数据已成为汽车…

【抽象代数】1.2. 半群与群

群的定义 群非空集合二元运算性质 定义1. 设 为一个非空集合&#xff0c;上有二元运算&#xff0c;满足结合律&#xff0c;则称或为一个半群。 定义2. 设 为半群&#xff0c;若元素 满足 &#xff0c;则称 为 的左幺元&#xff08;右幺元&#xff1a;&#xff09;&#…

Ubuntu 20 掉显卡驱动的解决办法

目录 问题背景解决办法Step1&#xff1a;首先查看当前linux内核Step2&#xff1a;重启Step3&#xff1a;进入ubuntu advanced &#xff08;即高级选项&#xff09;Step4&#xff1a;查看有哪些linux内核Step5&#xff1a;如果滚回老板kernel还是没有驱动&#xff0c;就找到驱动…

抖音碰碰卡:碰一碰发视频,系统部署分享!

源码搭建步骤&#xff1a; 服务器需求确认&#xff1a;依据预计的用户量和系统负载&#xff0c;选定适宜的服务器配置。环境搭建&#xff1a;在服务器上安装必要的操作系统、数据库及依赖库&#xff0c;包括如Linux、MySQL、Nginx等。源代码获取&#xff1a;从抖音官方开发者平…

RocketMQ与kafka如何解决消息丢失问题?

0 前言 消息丢失基本是分布式MQ中需要解决问题&#xff0c;消息丢失时保证数据可靠性的范畴。如何保证消息不丢失程序员面试中几乎不可避免的问题。本文主要说明RocketMQ和Kafka在解决消息丢失问题时&#xff0c;在生产者、Broker和消费者之间如何解决消息丢失问题。 1.Rocket…

华象新闻|2月20日前谨慎升级PostgreSQL版本

计划于2025年2月20日进行非周期性发布 PostgreSQL全球开发团队计划于2025年2月20日进行一次非周期性发布&#xff0c;以解决2025年2月13日更新版本中引入的一个回归问题。2月13日的更新版本包括了17.3、16.7、15.11、14.16和13.19版本。作为此次发布的一部分&#xff0c;我们将…