目录
- C 语言指针概述
- 指针的声明和初始化
- 声明指针
- 初始化指针
- 指针的操作
- 解引用操作
- 指针算术运算
- 指针的用途
- 动态内存分配
- 作为函数参数
- 指针与数组
- 数组名作为指针
- 通过指针访问数组元素
- 指针算术和数组
- 数组作为函数参数
- 指针数组和数组指针
- 指针数组
- 数组指针
- 函数指针
- 函数指针的定义和声明
- 函数指针的初始化和使用
- 函数指针作为函数参数(回调函数)
- 函数指针数组
- 动态内存分配
- 概念
- 动态内存分配函数
- malloc 函数
- calloc 函数
- realloc 函数
- free 函数
- 示例代码
- 注意事项
- 常见错误与规避
- 内存泄漏(Memory Leak)
- 空指针引用(Null Pointer Dereference)
- 重复释放内存(Double Free)
- 越界访问(Buffer Overflow)
- realloc 使用不当
C 语言指针概述
在 C 语言中,指针是一个非常重要且强大的概念。它是一个变量,其值为另一个变量的地址,即内存位置的直接地址。可以把指针想象成一个特殊的变量,它存储的不是普通的数据,而是内存中某个变量的地址。通过指针,我们可以直接访问和操作该内存地址上存储的数据。
指针的声明和初始化
声明指针
在 C 语言中,声明指针的一般语法如下:
数据类型 *指针变量名;
其中,数据类型 表示该指针所指向的变量的数据类型,* 是指针声明符,用于表明这是一个指针变量。例如:
int *p; // 声明一个指向整型变量的指针p
float *q; // 声明一个指向浮点型变量的指针q
初始化指针
指针可以在声明时进行初始化,也可以在声明后再赋值。指针初始化时,需要将一个变量的地址赋给它。使用 & 运算符可以获取变量的地址。示例如下:
#include <stdio.h>int main() {int num = 10;int *p = # // 声明并初始化指针p,使其指向变量numprintf("变量num的地址: %p\n", &num);printf("指针p存储的地址: %p\n", p);return 0;
}
在上述代码中,&num 表示变量 num 的地址,将其赋给指针 p,这样 p 就指向了 num。
指针的操作
解引用操作
通过指针访问其所指向的变量的值,需要使用 * 运算符,这称为解引用操作。示例如下:
#include <stdio.h>int main() {int num = 10;int *p = #printf("变量num的值: %d\n", num);printf("通过指针p访问num的值: %d\n", *p);*p = 20; // 通过指针p修改num的值printf("修改后变量num的值: %d\n", num);return 0;
}
在上述代码中,*p 表示指针 p 所指向的变量的值,通过 *p = 20; 可以修改 num 的值。
指针算术运算
指针可以进行一些算术运算,如加法、减法等。指针算术运算的结果取决于指针所指向的数据类型的大小。示例如下:
#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *p = arr; // 指针p指向数组arr的首元素printf("p指向的元素的值: %d\n", *p);p++; // 指针p向后移动一个位置printf("p移动后指向的元素的值: %d\n", *p);return 0;
}
在上述代码中,p++ 使指针 p 向后移动一个 int 类型的位置,即移动了 sizeof(int) 个字节。
指针的用途
动态内存分配
C 语言提供了一些函数(如 malloc、calloc、realloc 等)用于动态分配内存,这些函数返回的是一个指针,通过指针可以访问和管理动态分配的内存。示例如下:
#include <stdio.h>
#include <stdlib.h>int main() {int *p = (int *)malloc(sizeof(int)); // 动态分配一个int类型的内存空间if (p == NULL) {printf("内存分配失败\n");return 1;}*p = 10;printf("动态分配内存中存储的值: %d\n", *p);free(p); // 释放动态分配的内存return 0;
}
作为函数参数
指针可以作为函数参数,通过指针传递参数可以在函数内部修改实参的值。示例如下:
#include <stdio.h>void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 10, y = 20;printf("交换前: x = %d, y = %d\n", x, y);swap(&x, &y);printf("交换后: x = %d, y = %d\n", x, y);return 0;
}
在上述代码中,swap 函数接受两个指针作为参数,通过指针可以交换 x 和 y 的值。
指针与数组
在 C 语言中,指针和数组有着密切的联系。
数组名作为指针
在 C 语言里,数组名在大多数表达式中会被隐式转换为指向数组首元素的指针。也就是说,数组名代表了数组首元素的地址。
示例代码:
#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};// 打印数组首元素的地址printf("数组首元素的地址(使用&arr[0]): %p\n", &arr[0]);// 打印数组名代表的地址printf("数组名代表的地址: %p\n", arr);return 0;
}
在上述代码中,&arr[0] 是获取数组 arr 首元素的地址,而 arr 本身在这个表达式中也被解释为指向数组首元素的指针,所以它们的值是相同的。
通过指针访问数组元素
由于数组名可以当作指针使用,因此可以借助指针来访问数组中的元素。
示例代码:
#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *p = arr; // 指针p指向数组arr的首元素for (int i = 0; i < 5; i++) {// 通过指针访问数组元素printf("arr[%d] = %d\n", i, *(p + i));}return 0;
}
- <