目录
1. 字符指针变量:不仅仅是字符的地址
字符指针变量是指向字符类型数据的指针,通常用 char*
表示。我们来看一个简单的例子:
int main() {
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
在这个例子中,pc
是一个字符指针,指向字符变量 ch
的地址。通过 *pc
我们可以修改 ch
的值。
1.1 字符指针与字符串常量
字符指针的另一种常见用法是用于指向字符串常量。例如:
int main() {
const char* pstr = "hello bit.";
printf("%s\n", pstr);
return 0;
}
这里需要注意的是,pstr
并不是存储了整个字符串,而是存储了字符串 "hello bit."
的首字符 'h'
的地址。字符串常量在内存中是连续存储的,pstr
指向的是这个字符串的起始地址。
1.2 字符指针与字符数组的区别
我们来看一个经典的面试题:
#include <stdio.h>
int main() {
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char *str3 = "hello bit.";
const char *str4 = "hello bit.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
输出结果:
str1 and str2 are not same str3 and str4 are same
-
str1
和str2
是两个不同的字符数组,虽然内容相同,但它们存储在内存中的不同位置,因此str1
和str2
不相等。 str3
和str4
是两个字符指针,指向同一个字符串常量。C/C++ 会将相同的字符串常量存储在内存的同一位置,因此str3
和str4
相等
2. 数组指针变量:指向数组的指针
数组指针变量是指向数组的指针。与指针数组不同,数组指针变量本身是一个指针,指向一个数组。我们来看一个例子
int (*p)[10];
这里的 p
是一个数组指针,指向一个包含10个整型元素的数组。p
的类型是 int(*)[10]
,表示指向一个大小为10的整型数组的指针。
2.1 数组指针的初始化
数组指针变量用于存放数组的地址。我们可以通过以下方式初始化数组指针:
int arr[10] = {0};
int (*p)[10] = &arr;
这里 &arr
表示数组 arr
的地址,p
指向这个数组。
2.2 数组指针的使用
数组指针可以用于遍历二维数组。例如:
void printArray(int (*p)[5], int r, int c) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main() {
int arr[3][5] = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}};
printArray(arr, 3, 5);
return 0;
}
在这个例子中,p
是一个数组指针,指向一个包含5个整型元素的一维数组。通过 *(*(p + i) + j)
可以访问二维数组中的元素。
3. 二维数组传参的本质
在C语言中,二维数组的传参本质上是传递数组的地址。我们通常会将二维数组传递给函数,形参可以写成数组形式,也可以写成指针形式。例如:
void test(int a[3][5], int r, int c) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
printf("%d ", a[i][j]);
}
printf("\n");
}
}
或者使用指针形式:
void test(int (*p)[5], int r, int c) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
这两种方式都可以正确地传递二维数组,并且通过指针形式可以更清晰地理解二维数组的传参本质。
4. 函数指针变量:指向函数的指针
函数指针变量是指向函数的指针,它存储的是函数的地址。我们可以通过函数指针来调用函数。例如:
int Add(int x, int y) {
return x + y;
}
int main() {
int (*pf)(int, int) = Add;
printf("%d\n", (*pf)(2, 3)); // 输出 5
printf("%d\n", pf(3, 5)); // 输出 8
return 0;
}
在这个例子中,pf
是一个函数指针,指向 Add
函数。通过 pf
我们可以调用 Add
函数。
4.1 函数指针的类型
函数指针的类型由函数的返回类型和参数类型决定。例如,int (*pf)(int, int)
表示 pf
是一个指向返回类型为 int
,参数为两个 int
类型的函数的指针。
5. 函数指针数组:实现“转移表”
函数指针数组是一个数组,数组中的每个元素都是一个函数指针。我们可以通过函数指针数组来实现类似“转移表”的功能。例如:
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }
int main() {
int (*p[5])(int, int) = { 0, add, sub, mul, div };
int x, y, input = 1, ret = 0;
do {
printf("1:add 2:sub 3:mul 4:div 0:exit\n");
scanf("%d", &input);
if (input >= 1 && input <= 4) {
printf("输入操作数: ");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);
printf("ret = %d\n", ret);
}
} while (input);
return 0;
}
6. 总结
通过本篇博文,我们深入探讨了字符指针、数组指针、二维数组传参的本质、函数指针以及函数指针数组的使用。指针是C语言中非常强大的工具,理解指针的用法可以帮助我们编写更高效、更灵活的代码。希望本文的内容能够帮助你更好地理解指针的高级用法。