C 语言中指针的应用
C 语言最重要的特性之一是它通过指针的概念提供低级内存访问。指针是一个变量,用于存储内存中另一个变量的地址。
指针有很多应用,例如将数组和结构体类型传递给函数,以及动态内存分配等。在本章中,我们将讲解 C 语言中指针的一些重要应用。
访问数组元素
数组元素也可以通过指针访问。您需要声明并初始化一个指向数组的指针,并通过将指针变量递增1来访问每个元素。
指向数组的指针是其第0个元素的地址。当数组指针递增1时,它指向数组中的下一个元素。
示例
以下示例演示了如何借助指针遍历数组。
#include <stdio.h> int main(){ int arr[] = {1,2,3,4,5}; int *ptr = arr; for(int i = 0; i <= 4; i++){ printf("arr[%d]: %d ", i, *ptr); ptr++; } return 0; }
输出
运行代码并检查其输出 −
arr[0]: 1 arr[1]: 2 arr[2]: 3 arr[3]: 4 arr[4]: 5
动态分配内存
C 语言指针最重要的应用之一是动态地为变量声明内存。在很多情况下,静态内存分配无法解决问题,例如处理大尺寸数组、包含 n 个学生和员工的结构体等等。
因此,每当您需要动态分配内存时,指针都扮演着重要的角色。C 语言提供了一些动态分配和释放内存的函数。这些函数包括:
-
malloc() 函数
分配一个包含 num 个元素的数组,每个元素的大小为 size(以字节为单位)。 -
calloc() 函数
分配一个 num 字节数组,并使其保持未初始化状态。 -
realloc() 函数
重新分配内存,将其扩展到 newsize。
1. malloc() 函数
此函数定义在"stdlib.h"头文件中。它分配所需大小的内存块,并返回一个 void 指针。
void *malloc (size)
size 参数指的是内存块(以字节为单位)。要为指定的数据类型分配所需的内存,您需要使用类型转换运算符。例如,以下代码片段分配了存储 int 类型所需的内存。
int *ptr; ptr = (int * ) malloc (sizeof (int));
这里我们需要定义一个指向字符的指针,但不定义所需的内存大小,之后根据需要分配内存。
示例
在此示例中,我们使用 malloc() 函数分配所需的内存来存储字符串(而不是声明一个固定大小的 char 数组)-
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(){ char *name; name = (char *) malloc(strlen("TutorialsPoint")); strcpy(name, "TutorialsPoint"); if(name == NULL) { fprintf(stderr, "Error - unable to allocate required memory "); } else { printf("Name = %s ", name ); } }
输出
当编译并执行上述代码时,它会产生以下输出 -
Name = TutorialsPoint
2. calloc() 函数
C 库函数 "calloc"(代表连续分配)分配请求的内存并返回指向该内存的指针。
void *calloc(n, size);
其中 "n" 是待分配元素的数量,"size" 是每个元素的字节大小。
以下代码片段分配了存储 10 个整数类型所需的内存。
int *ptr; ptr = (int *) calloc(25, sizeof(int));
3. realloc() 函数
C 语言中的 realloc() 函数用于动态更改先前分配内存的分配。您可以通过调用 realloc() 函数来增加或减少已分配内存块的大小。
void *realloc(*ptr, size);
第一个参数"ptr"是指向先前使用malloc、calloc或realloc分配的内存块的指针,该内存块将被重新分配。
动态内存分配技术广泛应用于操作系统软件中使用的复杂线性和非线性数据结构,例如链表和树。
将参数作为引用传递
当通过引用调用函数时,传递的是实际参数变量的地址,而不是它们的值。
将指针传递给函数有两个优点 −
首先,它克服了按值传递的局限性。对被调用函数内部值的更改直接在指针中存储的地址上进行。因此,我们可以从一个作用域操作另一个作用域中的变量。
其次,它还克服了函数只能返回一个表达式的限制。通过传递指针,函数的执行效果直接在地址处进行。其次,如果我们返回数组或结构体变量的指针,则可以返回多个值。
示例
以下函数接收两个要交换值的变量的引用。
/* 函数定义用于交换值 */ int swap(int *x, int *y){ int z; z = *x; /* 将值保存在地址 x */ *x = *y; /* 将 y 放入 x */ *y = z; /* 将 z 放入 y */ return 0; }
示例
main() 函数有两个变量"a"和"b",它们的地址作为参数传递给 swap() 函数。
#include <stdio.h> int swap(int *x, int *y); int main(){ /* 局部变量定义 */ int a = 10; int b = 20; printf("Before swap, value of a : %d ", a); printf("Before swap, value of b : %d ", b); /* calling a function to swap the values */ swap(&a, &b); printf("After swap, value of a: %d ", a); printf("After swap, value of b: %d ", b); return 0; }
输出
执行时,它将产生以下输出 -
Before swap, value of a: 10 Before swap, value of b: 20 After swap, value of a: 20 After swap, value of b: 10
在此程序中,我们能够在函数作用域之外交换两个变量的值,并且克服了函数只能传递一个表达式的限制。
将数组传递给函数
让我们利用这些特性通过引用传递数组。在 main() 函数中,我们声明一个数组并将其地址传递给 max() 函数。
max() 函数使用指针遍历数组,并将数组中的最大数字返回给 main() 函数。
示例
请看以下示例 -
#include <stdio.h> int max(int *arr, int length); int main(){ int arr[] = {10, 34, 21, 78, 5}; int length = sizeof(arr)/sizeof(int); int maxnum = max(arr, length); printf("max: %d", maxnum); } int max(int *arr, int length){ int max = *arr; for (int i = 0; i < length; i++){ printf("arr[%d]: %d ", i, (*arr)); if ((*arr)>max) max = (*arr); arr++; } return max; }
输出
运行代码并检查其输出 −
arr[0]: 10 arr[1]: 34 arr[2]: 21 arr[3]: 78 arr[4]: 5 max: 78
max() 函数从 main() 函数中接收数组的地址,该地址存储在指针 "arr" 中。每次递增时,它都指向原始数组中的下一个元素。
函数返回多个值
在 C 语言中,函数只能有一个 return 语句,每次返回一个值。借助 C 指针,您可以通过将参数作为引用传递来从函数返回多个值。
示例
以下示例演示了如何借助 C 指针返回多个值。
#include <stdio.h> // 创建一个函数来计算 // 两个数的加法和减法 void funAddSub(int a, int b, int* add, int* sub) { *add = a + b; *sub = a - b; } int main() { int num1 = 10; int num2 = 3; // 存储结果的变量 int res1, res2; // 调用函数获取 add 和 sub 操作 // 通过传递 res1 和 res2 的地址 funAddSub(num1, num2, &res1, &res2); // 打印结果 printf("Addition is %d and subtraction is %d", res1, res2); return 0; }
输出
Addition is 13 and subtraction is 7