目录
七 动态内存管理:malloc()、calloc()、realloc()与free()
一 简介
C语言指针是一种特殊变量,用于存储内存地址。它允许直接操作内存,提供了对数据及其所在位置的灵活控制。指针变量声明时需指定其指向的数据类型,如 int *p;
表示p
是一个指向整数的指针。通过使用解引用符 *
访问指针所指向的内存位置的值,如 *p
。取址运算符 &
获取变量的地址赋给指针,如 p = &x;
将变量x
的地址赋予p
。指针可以进行算术运算,基于数据类型调整偏移量,实现连续内存区域(如数组)的遍历。指针与数组紧密关联,数组名实质上是数组首元素的地址。此外,指针还可指向结构体、函数等。理解和恰当地使用指针是掌握C语言的核心技能之一。
二 指针的概念与声明
指针是C语言中的一个核心概念,它是一种特殊的变量,用于存储其他变量的内存地址。声明指针时,需指定其数据类型,表示它能存储对应类型变量的地址。声明格式为:
数据类型 *指针名;
其中,星号 (*
) 表明这是一个指针变量,数据类型
指定了指针所指向的变量类型。例如:
int *pi; // 声明一个指向整型变量的指针 pi
char *pc; // 声明一个指向字符型变量的指针 pc
三 指针变量的赋值与初始化
指针变量的赋值是将其设置为另一个变量或内存区域的地址。赋值通常使用取址运算符 &
来获取目标变量的地址:
int x = 10;
int *px = &x; // px 被初始化为整型变量 x 的地址
初始化与赋值类似,但通常在声明时完成,确保指针在使用前已有一个有效的地址:
int y = 20;
int *py = NULL; // 初始化为空指针(NULL 或 0),表示尚未指向任何地址
py = &y; // 后续赋值,使 py 指向 y
// 或者直接在声明时初始化
int *pz = &z;
四 指针与数组的关系
数组名在C语言中被视为指向数组首元素的指针常量。这意味着可以使用指针来遍历数组:
int arr[5] = {1, 2, 3, 4, 5};
int *parr = arr; // parr 等价于 &arr[0]
for (int i = 0; i < 5; ++i) {
printf("%d ", *parr); // 输出当前元素
parr++; // 移动到下一个元素
}
此外,数组作为函数参数时,实际上是传递数组的首地址,通过指针访问数组元素。例如:
void print_array(int *arr, int n) {
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
print_array(numbers, sizeof(numbers) / sizeof(numbers[0])); // 传递数组首地址及元素数量
}
五 指针与函数参数:传递数组、修改实参
通过指针,函数可以修改实参(即调用者提供的变量)的值。这对于普通变量和数组都很重要。对于数组,虽然不能直接作为参数传递整个数组,但可以通过传递数组首地址(即指针)来达到修改数组元素的目的:
void modify_array(int *arr, int n, int value) {
for (int i = 0; i < n; ++i) {
arr[i] *= value; // 修改数组元素
}
}
int main() {
int nums[] = {1, 2, 3, 4, 5};
modify_array(nums, 5, 2); // 通过指针修改数组元素,所有元素乘以2
}
六 指向指针的指针与多级指针
指向指针的指针(二级指针)存储的是另一个指针变量的地址。多级指针以此类推,可以用于处理复杂的内存结构,如动态多维数组、链表等。声明和使用示例:
int x;
int *px = &x; // 指针 px 存储变量 x 的地址
int **ppy = &px; // 指向指针的指针 ppy 存储指针 px 的地址
// 使用多级指针访问值
*x = 10;
**ppy = 20; // 等同于 *px = 20; 和 x = 20;
// 多级指针在处理动态二维数组时很有用
int (*arr)[5]; // 声明一个指向长度为5的一维数组的指针
arr = malloc(sizeof(*arr) * 3); // 分配动态二维数组(3行,每行5列)
// 使用二级指针访问数组元素
*(arr + 1)[2] = 42; // 设置 arr[1][2] = 42
七 动态内存管理:malloc()
、calloc()
、realloc()
与free()
动态内存管理是C语言中通过指针操作的重要部分。以下是一些关键函数的简要说明:
-
void* malloc(size_t size)
: 分配size
字节的未初始化内存,返回指向这块内存的指针。若分配失败,返回NULL
。 -
void* calloc(size_t num, size_t size)
: 分配num
个大小为size
字节的连续内存块,并将所有字节初始化为零。返回指向首块内存的指针。同样,分配失败时返回NULL
。 -
void* realloc(void* ptr, size_t new_size)
: 改变已分配内存区域的大小。ptr
是先前通过malloc
、calloc
或realloc
分配的内存区域的起始地址。new_size
是新大小。如果成功,返回指向新(可能已移动)内存区域的指针;否则返回NULL
。若ptr
为NULL
,行为类似于malloc(new_size)
。 -
void free(void* ptr)
: 释放由malloc
、calloc
或realloc
分配的内存区域。传入ptr
为待释放内存的起始地址。使用后未释放的内存会导致内存泄漏。
示例:
int *dynamic_array = malloc(10 * sizeof(int)); // 分配10个整数的空间
if (dynamic_array == NULL) {
// 处理错误
}
// 使用动态数组...
dynamic_array[5] = 123;
// 不再需要时释放内存
free(dynamic_array);
dynamic_array = NULL; // 避免悬挂指针