c语言指针
一、指针的基本概念
指针本质上是一种变量,其存储的数值是内存地址。通过指针,能够对该内存地址里存储的数据进行间接访问。
int num = 42; // 定义一个整型变量
int *ptr; // 定义一个指向整型的指针
ptr = # // 将num的地址赋给ptr
printf("%p\n", ptr); // 输出ptr存储的地址
printf("%d\n", *ptr); // 解引用,输出42
二、指针的声明与初始化
指针在声明时,需要明确其指向数据的类型,并且要借助取地址运算符&来进行初始化。
int a = 10;
int *p = &a; // 正确:初始化指针p
int *q; // 未初始化的指针(野指针)
q = &a; // 正确:后续赋值
三、指针的解引用
运用解引用运算符*,可以获取指针所指向内存地址中的值。
int x = 20;
int *px = &x;
*px = 50; // 修改x的值为50
printf("%d\n", x); // 输出50
四、指针运算
指针支持的运算操作包括递增++、递减--以及加减法。
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // 指向数组首元素
ptr++; // 指向下一个元素(地址+4字节)
printf("%d\n", *ptr); // 输出2
五、指针与数组
在 C 语言中,数组名可被看作是指向数组首元素的常量指针。
int arr[3] = {10, 20, 30};
printf("%d\n", *arr); // 输出10
printf("%d\n", arr[1]); // 等价于*(arr + 1)
六、指针与函数
借助指针作为函数参数,能够实现对实参的修改,也就是所谓的 "传址调用"。
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
swap(&x, &y); // 交换x和y的值
printf("%d %d\n", x, y); // 输出10 5
return 0;
}
七、多级指针
多级指针指的是指针的指针,通过它可以间接访问更深层次的数据。
int num = 100;
int *p = #
int **pp = &p; // 二级指针
printf("%d\n", **pp); // 输出100
八、动态内存分配
在 C 语言中,可以利用malloc、calloc、realloc和free函数来对堆内存进行管理。
int *ptr = (int *)malloc(sizeof(int)); // 分配4字节内存
if (ptr != NULL) {
*ptr = 200;
free(ptr); // 释放内存,防止内存泄漏
}
九、指针与字符串
字符串常量实际上是指向字符数组的指针。
char *str = "Hello"; // 指向字符串常量的指针
printf("%c\n", *str); // 输出'H'
printf("%s\n", str); // 输出"Hello"
十、函数指针
函数指针能够存储函数的地址,进而实现函数的动态调用。
int add(int a, int b) { return a + b; }
int (*func_ptr)(int, int) = add; // 函数指针
printf("%d\n", func_ptr(3, 4)); // 输出7
十一、指针数组(Array of Pointers)
指针数组属于数组,它的每个元素都是指针。其定义格式为:type *array_name[size];
int a = 10, b = 20, c = 30;
int *ptr_arr[3] = {&a, &b, &c}; // 指针数组
printf("%d\n", *ptr_arr[0]); // 输出10
典型应用场景:
处理字符串数组:
char *fruits[3] = {"Apple", "Banana", "Cherry"};
printf("%s\n", fruits[1]); // 输出"Banana"
int *arr[5];
for(int i=0; i<5; i++) {
arr[i] = (int *)malloc(sizeof(int));
*arr[i] = i*10;
}
十二、数组指针(Pointer to an Array)
数组指针是一种指针,它指向的是整个数组。其定义格式为:type (*pointer_name)[size];
int arr[5] = {1,2,3,4,5};
int (*ptr)[5] = &arr; // 数组指针
printf("%d\n", (*ptr)[2]); // 输出3
关键要点:
- 数组指针的步长为整个数组的大小:
printf("%p\n", ptr); // 数组首地址
printf("%p\n", ptr+1); // 地址+20字节(假设int占4字节)
- 二维数组和数组指针:
int matrix[3][4];
int (*ptr)[4] = matrix; // 指向包含4个int的数组
ptr++; // 指向下一行
十三、指针数组 vs 数组指针
| 特征 | 指针数组 | 数组指针 |
|---|---|---|
| 本质 | 数组 | 指针 |
| 定义 | int *arr[5]; | int (*ptr)[5]; |
| 元素类型 | 指针 | 整个数组 |
| 用途 | 存储多个指针 | 指向多维数组 |
| 地址运算 | 元素地址间隔为指针大小 | 地址间隔为整个数组大小 |
十四、复杂声明解析(使用右左法则)
int *(*arr[5])(int); // 声明一个包含5个元素的数组
// 每个元素是指向函数的指针
// 该函数接受int参数并返回int*
解析步骤:
arr与[5]结合 →arr是数组*arr[5]→ 数组元素是指针(*arr[5])(int)→ 指针指向函数int *(*arr[5])(int)→ 函数返回 int*
十五、指针使用的注意事项
- 野指针:未初始化的指针可能会指向随机地址,使用前必须进行初始化。
- 内存泄漏:动态分配的内存使用完毕后,一定要用
free释放。 - 越界访问:对指针进行加减运算时,要确保其指向的是有效内存区域。
- 空指针:可以将指针赋值为
NULL,以此来表示其不指向任何对象。
十六、常见错误示例
int *p;
*p = 10; // 错误:野指针解引用
int arr[3];
arr++; // 错误:数组名是常量指针,不能修改

浙公网安备 33010602011771号