ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

C语言指针(1):编程世界的超级核武器,你敢来驾驭吗?

C语言指针(1):编程世界的超级核武器,你敢来驾驭吗?

引言

在C语言的世界里,指针堪称是其精华与难点所在。许多人说,没学指针就等于没学C语言,这话一点也不夸张。掌握了指针,能让我们对C语言的运用达到一个新的高度,极大地提升编程的灵活性和效率。所以完全可以说指针是编程世界的超级核武器。

1.指针的基本概念

指针可以说就是地址。计算机中的数据都存放在内存里,不同类型的数据占用的字节数各不相同。比如, int 类型通常占用 4 个字节,而 char 类型仅占用 1 个字节。为了能够准确地访问这些数据,每个字节都会被赋予一个唯一的编号,就如同门牌号一样,这个编号就是内存地址,也被称作指针。

1.1 这⾥就得学习⼀个操作符(&)-取地址操作符

#include <stdio.h> int main() { int a = 10; &a;//取出a的地址 printf("%p\n", &a); return 0; }
按照我画图的例⼦,会打印处理:006FFD70
&a取出的是a所占4个字节中地址较⼩的字节的地
址。

1.2 指针变量和解引⽤操作符(*)

指针变量就是存放地址(指针)的变量,而解引用操作符就是访问指针变量里面存放的地址。

这⾥pa左边写的是int*,*是在说明pa是指针变量,⽽前⾯的int是在说明pa指向的是整型(int) 类型的对象。

在指针类型中有⼀种特殊的类型是void *类型的,可以理解为⽆具体类型的指针(或者叫泛型指 针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void*类型的指针不能直接进行指针的+-整数和解引⽤的运算。

1.3 强制类型转换

当指针指向类型与原参数的类型不同时,可以使用强制类型转换。如图所示

di

图中&n是指向整型(int)的地址(指针),(char*)&n是将&n转换成指向字符型(char)的地址(指针)。

1.4 const修饰指针变量

const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。

const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。

2.指针的运算

指针的基本运算有三种,分别是:
•
指针+- 整数
•
指针-指针
•
指针的关系运算

2.1指针+- 整数

2.2指针-指针

2.3指针的关系运算

3. 指针与数组

数组和指针有着密切的联系。数组名在很多情况下会被转换为指向数组首元素的指针。例如,定义一个数组 int arr[] = {1, 2, 3, 4, 5}; , arr 可以看作是指向 arr[0] 的指针。(sizeof 运算符和 & 运算符除外)

sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节。

&(数组名),这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)。

4. 指针与函数

函数在内存中也有对应的地址,我们可以定义指针变量来存放函数的地址,这种指针变量就是函数指针。函数指针的定义方式为: 函数返回值类型 (* 指针变量名) (函数参数列表); 。例如:

#include <stdio.h> int add(int a, int b) { return a + b; } int main() { int (*p)(int, int); // 定义一个函数指针 p = add; // 函数指针指向 add 函数 int result = p(3, 4); // 通过函数指针调用函数 printf("%d\n", result); return 0; }


函数指针可以用于实现回调函数,提高程序的灵活性和可扩展性。
指针作为函数参数
指针可以作为函数的参数传递,这样可以在函数内部修改实参的值。例如:

#include <stdio.h> void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main() { int x = 3, y = 4; swap(&x, &y); printf("x = %d, y = %d\n", x, y); return 0; }


5. 指针的高级应用

5.1 二级指针是指向指针的指针

例如:

#include <stdio.h> int main() { int num = 10; int *ptr = &num; int **pptr = &ptr; printf("%d\n", **pptr); // 通过二级指针访问 num 的值 return 0; }

二级指针在处理动态二维数组等场景中非常有用。

*5.2 野指针及其规避

野指针是指向非法内存地址的指针。野指针的成因主要有以下几种:
1. 指针未初始化:定义指针变量时没有给它赋初值。

#include <stdio.h> int main() { int *p;//局部变量指针未初始化,默认为随机值 *p = 20; return 0; }

2. 指针指向的内存被释放:指针所指向的内存被释放后,指针没有被置为 NULL 。
3. 指针越界访问:指针访问了数组以外的内存。

#include <stdio.h> int main() { int arr[10] = {0}; int *p = &arr[0]; int i = 0; for(i=0; i<=11; i++) { //当指针指向的范围超出数组arr的范围时,p就是野指针 *(p++) = i; } return 0; }

为了规避野指针,我们可以采取以下措施:
1. 指针定义时初始化为 NULL 。
2. 释放指针指向的内存后,将指针置为 NULL 。
3. 确保指针访问不越界。

6. 总结

C语言指针是一个强大而复杂的工具,它涉及到内存管理、数据访问、函数调用等多个方面。通过深入学习指针的基本概念、类型、运算以及与数组、函数的结合使用,我们能够编写出更加高效、灵活的C语言程序。同时,要注意避免野指针等问题,确保程序的稳定性和安全性。希望通过本文的介绍,能让你对C语言指针有更深入的理解和掌握。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进