以下是为您补全并优化的博客内容,包含了字符指针、数组指针和函数指针的详细解释、代码示例及其使用注意事项。
文章目录
-
- @[TOC](文章目录)
- 一、字符指针变量
-
- 1. 基本概念与存储
-
- 代码示例:
- 2. 可写字符串的实现
- 二、数组指针变量
-
- 1. 基本概念
-
- 代码示例:
- 2. 与指针数组的区别
- 三、函数指针变量
-
- 1. 基本定义与使用
-
- 代码示例:
- 2. 使用 `typedef` 简化
-
- 代码示例:
- 3. 回调函数
-
- 代码示例(qsort 回调):
- 四、总结
- @[TOC](文章目录)
- 1. 基本概念与存储
-
- 代码示例:
- 2. 可写字符串的实现
- 1. 基本概念
-
- 代码示例:
- 2. 与指针数组的区别
- 1. 基本定义与使用
-
- 代码示例:
- 2. 使用 `typedef` 简化
-
- 代码示例:
- 3. 回调函数
-
- 代码示例(qsort 回调):
一、字符指针变量
字符指针变量是指向字符(char)或字符数组(即字符串)的指针。在 C 语言中,字符串字面量(如 "Hello world.")是一种特殊的字符数组,其本质是以 '\\0' 结尾的字符序列。
1. 基本概念与存储
在 C 语言中,字符串字面量(String Literal)通常存储在只读的常量区(Data Segment)中。这意味着它们在程序运行期间通常是不可修改的。如果尝试修改它们,会导致运行时错误(Segmentation Fault)。
代码示例:
int main()
{
// 错误示例:尝试修改只读字符串字面量
const char* pstr = "Hello world.";
// pstr[0] = 'h'; // 运行时错误:不可写
// 正确示例:指向字符串字面量的指针
const char* pstr2 = "Hello world.";
printf("%s\\n", pstr2);
return 0;
}
注意:这里的 const char* 声明的是一个指向常量字符的指针,意味着指针指向的内容不可修改,但指针本身(即存储的地址)是可以改变的[[1]][[2]][[3]]。
2. 可写字符串的实现
如果你希望通过指针来修改字符串的内容,有两种常见方式:
使用字符数组:
int main()
{
char str[] = "Hello world."; // 将字符串字面量复制到数组中
str[0] = 'h'; // 合法:修改数组内容
printf("%s\\n", str);
return 0;
}
解释: char str[] = "Hello world."; 实际上是将字符串字面量的内容复制了一份到栈上的数组 str 中,这个数组是可写的[[4]][[5]]。
使用 malloc 动态分配内存:
#include <stdlib.h>
#include <string.h>
int main()
{
char *p = malloc(13);
strcpy(p, "Hello world.");
p[0] = 'h'; // 合法
free(p);
return 0;
}
解释: 动态分配的内存默认是可写的,前提是你自行分配了足够的空间来存储字符串。
二、数组指针变量
数组指针变量是一种特殊的指针变量,它存放的是整个数组的地址。它与普通指针的主要区别在于“指向的对象类型”不同。
1. 基本概念
数组指针变量指向的是一个完整的数组,而不是数组的第一个元素。它的定义方式通常是 type (*ptr)[size],其中 type 是数组元素的类型,size 是数组的长度。
代码示例:
int main()
{
int arr[10]; // 声明一个包含 10 个整数的数组
int (*p)[10]; // 声明一个指向包含 10 个整数的数组的指针
p = &arr; // 这里取的是数组的地址,而不是数组首元素的地址
(*p)[0] = 1; // 通过数组指针访问数组元素
return 0;
}
注意:p = arr; 是错误的,arr 会退化为指向首元素的指针(类型是 int*),而 p 的类型是 int (*)[10],两者类型不匹配[[6]][[7]]。
2. 与指针数组的区别
数组指针和指针数组是两个完全不同的概念,容易混淆。
| 数组指针 | type (*ptr)[size];指向一个完整的数组 | 用于处理二维数组、函数参数传递等场景 |
| 指针数组 | type *ptr[size];数组的每个元素都是一个指针 | 用于存储多个字符串的地址、函数指针等 |
示例:指针数组(字符串数组)
const char *mytalents[] = {"Coding", "Reading", "Music"}; // 指针数组
printf("%s\\n", mytalents[0]); // 输出 "Coding"
在这个例子中,mytalents 是一个指针数组,每个元素是指向字符串字面量的指针[[8]][[9]]。
三、函数指针变量
函数指针是指向函数的指针,允许你将函数作为参数传递给其他函数,或在运行时动态决定调用哪个函数。这在实现回调函数(Callback)和多态性时非常有用。
1. 基本定义与使用
函数指针的定义语法相对复杂,核心在于正确区分“返回类型”和“参数列表”。
代码示例:
#include <stdio.h>
// 定义一个普通函数
int add(int a, int b) {
return a + b;
}
// 定义函数指针变量
int (*func_ptr)(int, int) = add; // func_ptr 指向 add 函数
int main() {
int result = func_ptr(5, 3); // 通过函数指针调用函数
printf("%d\\n", result); // 输出 8
return 0;
}
解释:int (*func_ptr)(int, int) 声明了一个指向返回 int、接受两个 int 参数的函数的指针[[10]][[11]][[12]]。
2. 使用 typedef 简化
由于函数指针的声明语法复杂,推荐使用 typedef 为其定义别名。
代码示例:
#include <stdio.h>
// 使用 typedef 定义函数指针类型
typedef int (*Operation)(int, int);
// 定义两个函数
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a – b; }
// 接受函数指针作为参数的函数
void calculate(Operation op, int x, int y) {
printf("%d\\n", op(x, y));
}
int main() {
calculate(add, 5, 3); // 输出 8
calculate(sub, 5, 3); // 输出 2
return 0;
}
使用 typedef 后,代码更加简洁易读[[13]][[14]]。
3. 回调函数
函数指针最常见的应用场景是回调函数,即将函数指针作为参数传递给另一个函数,在特定事件或条件满足时调用。
代码示例(qsort 回调):
#include <stdio.h>
#include <stdlib.h>
// 比较函数,用于 qsort
int compare(const void* a, const void* b) {
return (*(int*)a – *(int*)b);
}
int main() {
int arr[] = {5, 2, 9, 1, 5, 6};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare); // 将 compare 作为回调函数传入
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
在这个例子中,compare 函数的指针被传递给了 qsort,qsort 会在内部调用 compare 来确定元素的顺序[[15]][[16]]。
四、总结
指针是 C 语言中最强大但也最复杂的特性之一。了解指针的本质对于写出高效且安全的代码至关重要。
网硕互联帮助中心




评论前必须登录!
注册