当前位置: 首页 > news >正文

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;
}
 注意事项
  1. 函数指针的类型必须与所指向的函数完全匹配(返回值类型和参数类型)

  2. 不要对函数指针进行不安全的类型转换

  3. 空函数指针(nullptr)需要先检查再调用

  4. 成员函数指针与普通函数指针不同(在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

相关文章:

  • 71-Oracle Undo与Flashback管理(Guarantee设置)深度解析
  • 艾立泰数字化方案重塑汽车包装载具管理
  • oracle 表空间与实例妙用,解决业务存储与权限处理难题
  • C++11 static_assert(基于Boost库)从入门到精通
  • Halcon ——— OCR字符提取与多类型识别技术详解
  • STM32学习笔记
  • 全链接神经网络,CNN,RNN各自擅长解决什么问题
  • DataWhale-零基础络网爬虫技术(三、爬虫进阶技术)
  • 使用 catthehacker/ubuntu Docker 镜像部署 GitHub Actions 本地运行环境
  • SpringSecurity6(认证-前后端分离)
  • MATLAB GUI界面设计 第四章——图像的绘制与显示
  • 电路图识图基础知识-塔式起重机控制电路识图与操作要点(三十五)
  • 深入解析 Windows 文件查找命令(dir、gci)
  • 窗口函数的概念
  • 为什么android要使用Binder机制
  • 顶级思维方式——认知篇九(经典语录)《约翰·克利斯朵夫》
  • LangChain4j从入门到实战(一)
  • DeepSeek今天喝什么随机奶茶推荐器
  • [C#] Task
  • 飞算 JavaAI:重构 Java 开发范式的工程化实践
  • 做商城网站哪里/怎样开网站
  • 如果做网站/株洲seo推广
  • 什么网站做的号/外贸企业网站设计公司
  • 做哪个视频网站赚钱的/注册网址
  • 17zwd一起做网站教学视频/深圳产品网络推广
  • 做同城相亲网站/关键词长尾词优化