DAY12 一维字符型数组、指针函数与函数指针详解
1. 一维字符型数组一维字符型数组是C/C中用于存储字符串的基本数据结构。它本质上是一个字符类型的数组每个元素存储一个字符以空字符\0作为字符串的结束标志。1.1 声明与初始化字符数组的声明方式与其他数组类似// 声明一个能存储10个字符的数组实际可存储9个字符1个\0 char str1[10]; // 声明并初始化 char str2[] Hello; // 自动计算大小包含\0 char str3[6] {H, e, l, l, o, \0}; char str4[10] World; // 剩余元素自动填充\01.2 常用操作字符数组的常见操作包括输入输出、复制、连接、比较等#include stdio.h #include string.h int main() { char str1[20] Hello; char str2[20] World; char str3[40]; // 字符串长度 printf(str1长度: %lu\n, strlen(str1)); // 字符串复制 strcpy(str3, str1); printf(复制后str3: %s\n, str3); // 字符串连接 strcat(str3, ); strcat(str3, str2); printf(连接后str3: %s\n, str3); // 字符串比较 if (strcmp(str1, str2) 0) { printf(字符串相等\n); } else { printf(字符串不相等\n); } return 0; }1.3 注意事项字符数组的大小必须足够容纳字符串内容加上结束符\0使用strcpy等函数时要注意目标数组的容量避免缓冲区溢出字符数组名表示数组首地址可以用于指针操作2. 指针函数指针函数是指返回值为指针类型的函数。这类函数通常用于返回动态分配的内存地址、数组首地址或字符串地址。2.1 基本语法// 返回整型指针的函数 int* getIntPointer(int value) { int* ptr (int*)malloc(sizeof(int)); if (ptr ! NULL) { *ptr value; } return ptr; } // 返回字符指针的函数常用于返回字符串 char* getGreeting() { // 注意不要返回局部变量的地址 static char greeting[] Hello, World!; return greeting; }2.2 实用示例#include stdio.h #include stdlib.h #include string.h // 返回动态分配的字符串 char* createString(const char* source) { if (source NULL) return NULL; char* newStr (char*)malloc(strlen(source) 1); if (newStr ! NULL) { strcpy(newStr, source); } return newStr; } // 返回数组中最大元素的地址 int* findMax(int arr[], int size) { if (size 0) return NULL; int* maxPtr arr[0]; for (int i 1; i size; i) { if (arr[i] *maxPtr) { maxPtr arr[i]; } } return maxPtr; } int main() { // 使用指针函数 char* str createString(Pointer Function); if (str ! NULL) { printf(创建的字符串: %s\n, str); free(str); } int numbers[] {3, 7, 2, 9, 5}; int* maxPtr findMax(numbers, 5); if (maxPtr ! NULL) { printf(最大值: %d (地址: %p)\n, *maxPtr, (void*)maxPtr); } return 0; }2.3 注意事项不要返回局部变量的地址函数结束后局部变量被销毁返回动态分配的内存时调用者需要负责释放确保返回的指针指向有效的内存区域3. 函数指针函数指针是指向函数的指针变量。通过函数指针可以实现回调函数、函数表、动态函数调用等高级功能。3.1 声明与初始化// 函数原型 int add(int a, int b) { return a b; } int subtract(int a, int b) { return a - b; } // 函数指针声明 int (*funcPtr)(int, int); // 指向返回int接受两个int参数的函数 // 函数指针初始化 funcPtr add; // 指向add函数 funcPtr subtract; // 也可以使用取地址运算符3.2 使用方式#include stdio.h // 定义几个数学运算函数 int multiply(int a, int b) { return a * b; } int divide(int a, int b) { if (b ! 0) return a / b; return 0; } // 使用函数指针作为参数回调函数 void calculate(int a, int b, int (*operation)(int, int)) { int result operation(a, b); printf(%d 和 %d 的运算结果: %d\n, a, b, result); } // 函数指针数组 int main() { // 单个函数指针的使用 int (*operation)(int, int); operation add; printf(10 5 %d\n, operation(10, 5)); operation multiply; printf(10 * 5 %d\n, operation(10, 5)); // 回调函数示例 calculate(20, 4, divide); calculate(20, 4, subtract); // 函数指针数组 int (operations[4])(int, int) {add, subtract, multiply, divide}; char opNames[] {加法, 减法, 乘法, 除法}; for (int i 0; i 4; i) { printf(%s: %d\n, opNames[i], operations[i](12, 3)); } return 0; }3.3 高级应用#include stdio.h #include stdlib.h // 定义函数指针类型 typedef int (*Comparator)(int, int); // 比较函数 int ascending(int a, int b) { return a - b; } int descending(int a, int b) { return b - a; } // 使用函数指针的排序函数 void bubbleSort(int arr[], int size, Comparator compare) { for (int i 0; i size - 1; i) { for (int j 0; j size - i - 1; j) { if (compare(arr[j], arr[j 1]) 0) { // 交换 int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } } void printArray(int arr[], int size) { for (int i 0; i size; i) { printf(%d , arr[i]); } printf(\n); } int main() { int numbers[] {64, 34, 25, 12, 22, 11, 90}; int size sizeof(numbers) / sizeof(numbers[0]); printf(原始数组: ); printArray(numbers, size); // 升序排序 bubbleSort(numbers, size, ascending); printf(升序排序: ); printArray(numbers, size); // 降序排序 bubbleSort(numbers, size, descending); printf(降序排序: ); printArray(numbers, size); return 0; }3.4 注意事项函数指针的类型必须与所指函数的返回类型和参数类型完全匹配使用typedef可以简化复杂的函数指针声明函数指针可以大大提高代码的灵活性和可扩展性4. 综合应用示例下面是一个结合字符数组、指针函数和函数指针的完整示例#include stdio.h #include stdlib.h #include string.h #include ctype.h // 函数指针类型字符串处理函数 typedef char* (StringProcessor)(char); // 指针函数转换为大写 char* toUpperCase(char* str) { if (str NULL) return NULL; static char result[100]; // 使用静态数组避免返回局部变量地址 strcpy(result, str); for (int i 0; result[i] ! \0; i) { result[i] toupper(result[i]); } return result; } // 指针函数转换为小写 char* toLowerCase(char* str) { if (str NULL) return NULL; static char result[100]; strcpy(result, str); for (int i 0; result[i] ! \0; i) { result[i] tolower(result[i]); } return result; } // 指针函数反转字符串 char* reverseString(char* str) { if (str NULL) return NULL; static char result[100]; int len strlen(str); for (int i 0; i len; i) { result[i] str[len - 1 - i]; } result[len] \0; return result; } // 使用函数指针处理字符串数组 void processStringArray(char* strings[], int count, StringProcessor processor) { printf(处理结果:\n); for (int i 0; i count; i) { char* result processor(strings[i]); printf( 原始: %s - 结果: %s\n, strings[i], result); } } int main() { // 字符数组示例 char str1[] Hello; char str2[] World; char str3[] Programming; char* stringArray[] {str1, str2, str3}; int arraySize sizeof(stringArray) / sizeof(stringArray[0]); // 函数指针数组 StringProcessor processors[] {toUpperCase, toLowerCase, reverseString}; char* processorNames[] {大写转换, 小写转换, 反转字符串}; // 使用不同的处理器处理字符串数组 for (int i 0; i 3; i) { printf(\n %s \n, processorNames[i]); processStringArray(stringArray, arraySize, processors[i]); } // 动态分配字符串示例 char* dynamicStr (char*)malloc(50 * sizeof(char)); if (dynamicStr ! NULL) { strcpy(dynamicStr, Dynamic Memory Allocation); printf(\n动态字符串: %s\n, dynamicStr); char* processed toUpperCase(dynamicStr); printf(处理后: %s\n, processed); free(dynamicStr); } return 0; }5. 总结今天学习的三个概念在C/C编程中非常重要5.1 一维字符型数组是存储字符串的基础数据结构以\0作为字符串结束标志需要特别注意缓冲区溢出问题5.2 指针函数返回指针类型的函数常用于返回字符串、动态分配的内存或数组地址注意不要返回局部变量的地址5.3 函数指针指向函数的指针变量可以实现回调机制和动态函数调用大大提高代码的灵活性和可复用性这三个概念经常结合使用特别是在需要处理字符串、实现回调机制或创建灵活的函数库时。掌握它们对于深入理解C/C的内存管理和函数调用机制至关重要。学习建议多写代码实践理解指针和内存的关系从简单示例开始逐步增加复杂度注意内存管理避免内存泄漏和非法访问理解函数指针在回调函数、事件处理等场景中的应用