C指针总结复习(结合deepseek)
一、指针数组 (Array of Pointers)
一维数组
int main()
{int arr[5] = { 1, 2, 3, 4, 5 };int (*ptr)[5] = &arr;int* p = arr;// 访问元素方式printf("%d\n", p[2]); //输出3printf("%d\n", (*ptr)[2]); // 输出3printf("%d\n", ptr[0][2]); // 同上,输出3/*p 是一个 int* 类型的指针,指向数组的第一个元素p[2] 等价于 *(p + 2),通过指针算术访问第三个元素这是最常用的数组访问方式ptr 是一个指向整个数组的指针,类型是 int(*)[5]*ptr 解引用得到数组本身(arr)(*ptr)[2] 等价于 arr[2]ptr[0] 等价于 *(ptr + 0),即解引用得到数组本身ptr[0][2] 相当于先取数组,再取数组的第三个元素这种写法暗示 ptr 可以看作是指向二维数组的行指针*/return 0;
}
二维数组
int matrix[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
};// 数组指针指向包含4个int的数组
int (*ptr)[4] = matrix;// 访问元素
printf("%d\n", ptr[1][2]); // 输出7
printf("%d\n", (*(ptr + 1))[2]); // 同上,输出7
sizeof
操作符与指针、数组的关系 (64位下)
#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *ptr = arr;printf("sizeof(arr): %zu\n", sizeof(arr)); // 数组总大小printf("sizeof(ptr): %zu\n", sizeof(ptr)); // 指针大小printf("sizeof(&arr): %zu\n", sizeof(&arr)); // 指针大小printf("sizeof(*ptr): %zu\n", sizeof(*ptr)); // int大小printf("sizeof(arr[0]): %zu\n", sizeof(arr[0])); // 单个元素大小return 0;
}
sizeof(arr): 20 // 5个int × 4字节 = 20字节
sizeof(ptr): 8 // 指针在64位系统占8字节
sizeof(&arr): 8 // 数组指针也是指针
sizeof(*ptr): 4 // int类型大小
sizeof(arr[0]): 4 // int类型大小
二、函数指针
返回值类型 (*指针变量名)(参数类型列表);
int add(int a, int b)
{return a + b;
}
int main()
{//返回值类型 (*指针变量名)(参数类型列表);int (*funcPtr)(int, int); // 定义一个指向函数的指针,该函数接受两个int参数并返回intfuncPtr = add; // 或者 = &addint result = funcPtr(3, 4); // 等同于 add(3, 4)// 或者result = (*funcPtr)(3, 4); // 显式解引用printf("%d", result);//7return 0;
}
函数指针数组
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 main() {int (*operations[3])(int, int) = {add, sub, mul};for (int i = 0; i < 3; i++) {printf("%d\n", operations[i](10, 5));}// 输出:// 15 (10 + 5)// 5 (10 - 5)// 50 (10 * 5)return 0;
}
高级用法
typedef int (*MathFunc)(int, int);//将int(*)(int,int) 简化为 MathFunc类型int add(int a, int b) { return a + b; }int main()
{MathFunc func = add;//此时func就是int(*)(int,int)型指针printf("%d\n", func(2, 3)); // 输出5return 0;
}
回调函数
void processArray(int *arr, int size, int (*callback)(int)) {for (int i = 0; i < size; i++) {arr[i] = callback(arr[i]);}
}int square(int x) { return x * x; }
int increment(int x) { return x + 1; }int main() {int arr[] = {1, 2, 3, 4, 5};processArray(arr, 5, square);// arr现在是 [1, 4, 9, 16, 25]processArray(arr, 5, increment);// arr现在是 [2, 5, 10, 17, 26]return 0;
}
C++中的函数指针
C++中还可以使用函数对象和lambda表达式,但函数指针仍然有效:
#include <iostream>
using namespace std;int add(int a, int b) { return a + b; }int main() {int (*func)(int, int) = add;cout << func(3, 4) << endl; // 输出7// 使用auto更简洁auto func2 = add;cout << func2(5, 6) << endl; // 输出11return 0;
}
注意事项
-
函数指针的类型必须与所指向的函数完全匹配(返回值类型和参数类型)
-
不要对函数指针进行不安全的类型转换
-
空函数指针(nullptr)需要先检查再调用
-
成员函数指针与普通函数指针不同(在C++中)
三、const 和 指针
const
关键字与指针结合使用时,会产生多种不同的含义,这取决于 const
修饰的是指针本身还是指针所指向的数据。理解这些区别对于编写安全、可靠的C/C++代码至关重要。
1. 指向常量数据的指针 (Pointer to constant data)
const int *ptr; // 或 int const *ptr;
const int x = 10;
const int *ptr = &x;
// *ptr = 20; // 错误:不能修改常量数据
int y = 30;
ptr = &y; // 合法:可以改变指针指向
-
特点:指针可以修改(指向不同的地址),但不能通过指针修改所指向的数据
-
用途:保护数据不被意外修改
2. 常量指针 (Constant pointer)
int *const ptr;
int x = 10;
int *const ptr = &x;
*ptr = 20; // 合法:可以修改指向的数据
// ptr = &y; // 错误:不能改变指针本身
-
特点:指针本身是常量(不能指向其他地址),但可以通过指针修改所指向的数据
-
用途:确保指针始终指向特定内存位置
3. 指向常量数据的常量指针 (Constant pointer to constant data)
const int *const ptr;
const int x = 10;
const int *const ptr = &x;
// *ptr = 20; // 错误:不能修改数据
// ptr = &y; // 错误:不能修改指针
-
特点:指针不能修改,也不能通过指针修改数据
-
用途:完全保护数据和指针
四、库函数的实现
1、memcpy 实现
memcpy
用于从源内存地址复制n个字节到目标内存地址,不处理内存重叠情况。
void* my_memcpy(void* dest, const void* src, size_t n) {if (dest == NULL || src == NULL || n == 0) {return dest;}char* d = (char*)dest;const char* s = (const char*)src;// 逐字节复制for (size_t i = 0; i < n; i++) {d[i] = s[i];}return dest;
}
特点:
-
不检查内存重叠
-
简单高效的逐字节复制
-
返回目标指针以便链式调用
2. memmove 实现
memmove
也用于内存复制,但会正确处理源和目标内存重叠的情况。
void* my_memmove(void* dest, const void* src, size_t n) {if (dest == NULL || src == NULL || n == 0) {return dest;}char* d = (char*)dest;const char* s = (const char*)src;// 判断是否有重叠if (d > s && d < s + n) {// 从后向前复制以避免覆盖for (size_t i = n; i > 0; i--) {d[i-1] = s[i-1];}} else {// 无重叠或源在前,正常复制for (size_t i = 0; i < n; i++) {d[i] = s[i];}}return dest;
}
特点:
-
检测内存重叠情况
-
重叠时从后向前复制
-
非重叠时从前向后复制
-
同样返回目标指针
3. strstr 实现
char* my_strstr(const char* haystack, const char* needle) {if (haystack == NULL || needle == NULL || *needle == '\0') {return (char*)haystack;}for (; *haystack != '\0'; haystack++) {const char* h = haystack;const char* n = needle;while (*h != '\0' && *n != '\0' && *h == *n) {h++;n++;}if (*n == '\0') {return (char*)haystack;}}return NULL;
}
特点:
-
处理空指针和空子串的特殊情况
-
外层循环遍历主字符串
-
内层循环比较子串
-
返回首次匹配的位置指针或NULL