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

高阶C语言|探索指针的根源之目(进阶指针)

文章目录

      • 前言
      • 1. 字符指针(`char*`)
        • 1.1 字符串常量与指针
        • 1.2 字符指针的使用
      • 2. 数组指针与指针数组
        • 2.1 指针数组
        • 2.2 数组指针
      • 3. 数组与指针传参
        • 3.1 一维数组传参
        • 3.2 二维数组传参
      • 4. 函数指针(`function pointer`)
        • 4.1 函数指针的基本用法
        • 4.2 使用函数指针数组
      • 5. 指向函数指针数组的指针
      • 6. 回调函数(Callback Function)

💬 欢迎讨论:在阅读过程中有任何疑问,欢迎在评论区留言,我们一起交流学习!

👍 点赞、收藏与分享:如果你觉得这篇文章对你有帮助,记得点赞、收藏,并分享给更多对指针感兴趣的朋友!

在学习这篇文章之前,强烈建议先学习初阶指针哦~
传送门呈上~
初探C语言|一篇文章让你拿捏指针(初阶指针)

前言

C语言的指针被视为一项强大但复杂的工具,它允许程序直接操作内存,提高程序的灵活性和效率。虽然指针的基础用法很多人已经掌握,但更深入的理解能够帮助开发者解决更复杂的编程问题。本文将详细探讨C语言中一些进阶的指针概念,包括字符指针、数组指针、指针数组、函数指针、指向函数指针数组的指针等,并通过示例深入讲解它们的用法和应用场景。

1. 字符指针(char*

字符指针是指向单个字符或字符串的指针,它在处理字符串和字符数组时特别有用。在C语言中,字符串是一个字符数组,字符指针通常用于访问字符串的首地址。

1.1 字符串常量与指针

在C语言中,字符串本质上是字符的数组,并且以\0结尾,表示字符串的结束。字符指针指向的是数组的首元素。例如:

const char* pstr = "Hello, World!";

pstr是一个字符指针,指向常量字符串的首字符。需要注意的是,pstr存储的是字符串的内存地址,而不是字符串本身。

1.2 字符指针的使用

通过字符指针,我们可以访问字符串中的每个字符:

#include <stdio.h>

int main() {
    const char* pstr = "Hello, World!";
    while (*pstr != '\0') {
        printf("%c ", *pstr);
        pstr++;  // 指针自增,访问下一个字符
    }
    return 0;
}

输出:

H e l l o ,   W o r l d !

2. 数组指针与指针数组

在C语言中,数组与指针之间有紧密的关系。我们经常需要使用指针来处理数组。理解数组指针指针数组的区别对于编写高效的代码至关重要。

2.1 指针数组

指针数组是一个数组,其中每个元素都是指向某种数据类型的指针。通常,用指针数组来存储多个指向不同数据的指针。

int* arr[10];  // 定义了一个包含10个指针的数组

每个元素都是一个指向整数的指针,可以通过数组索引访问指针:

#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 30;
    int* arr[3] = {&a, &b, &c};
    
    for (int i = 0; i < 3; i++) {
        printf("Value at arr[%d]: %d\n", i, *arr[i]);
    }
    
    return 0;
}

输出:

Value at arr[0]: 10
Value at arr[1]: 20
Value at arr[2]: 30
2.2 数组指针

数组指针是一个指向整个数组的指针。它与指针数组的关键区别在于,数组指针指向的是整个数组,而指针数组指向的是数组中的各个元素。

例如,二维数组可以通过数组指针传递给函数:

int (*arr)[10];  // 指向包含10个整数的数组的指针
#include <stdio.h>

void print_array(int (*arr)[3]) {
    for (int i = 0; i < 3; i++) {
        printf("%d ", (*arr)[i]);
    }
    printf("\n");
}

int main() {
    int arr[3] = {1, 2, 3};
    print_array(&arr);
    return 0;
}

3. 数组与指针传参

在C语言中,当我们将数组作为参数传递给函数时,传递的实际上是数组的首地址。通过指针访问数组,可以方便地进行数组的操作。

3.1 一维数组传参
void print_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

由于数组本质上是指针类型,arr[]等价于int* arr。这样,数组的所有元素都可以通过指针进行访问。

3.2 二维数组传参

二维数组在传递时,需要指定第二维的大小,这样才能正确计算内存偏移量。例如:

void print_2d_array(int arr[3][4]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

4. 函数指针(function pointer

函数指针是指向函数的指针,能够存储一个函数的地址。通过函数指针,我们可以实现动态调用函数,这对于回调函数和事件驱动的编程非常有用。

4.1 函数指针的基本用法

定义一个函数指针并通过它调用函数:

#include <stdio.h>

void test(int a) {
    printf("Test: %d\n", a);
}

int main() {
    void (*func_ptr)(int) = test;
    func_ptr(10);  // 通过函数指针调用 test 函数
    return 0;
}
4.2 使用函数指针数组

函数指针数组是一个数组,其中每个元素都是一个指向函数的指针。常用于实现多态性或函数的动态调度。

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 (*ops[4])(int, int) = {add, sub, mul, div};
    int x = 10, y = 5;
    
    printf("Addition: %d\n", ops[0](x, y));
    printf("Subtraction: %d\n", ops[1](x, y));
    printf("Multiplication: %d\n", ops[2](x, y));
    printf("Division: %d\n", ops[3](x, y));
    return 0;
}

输出:

Addition: 15
Subtraction: 5
Multiplication: 50
Division: 2

5. 指向函数指针数组的指针

指向函数指针数组的指针是一种较为复杂的结构,允许通过指针访问一个存储函数指针的数组。它在复杂的回调机制或动态函数调用中非常有用。

int (*(*pf)[10])(int, int);

这种复杂的结构通常用于处理多个回调函数或多态调用。

6. 回调函数(Callback Function)

回调函数是通过函数指针传递的函数,它通常在某个事件发生时被调用。在C语言中,回调函数广泛用于处理异步事件或某些特定条件的处理。

例如,标准库中的qsort函数就是一个典型的回调函数应用场景:

#include <stdio.h>
#include <stdlib.h>

int compare(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {5, 3, 8, 1, 2};
    qsort(arr, 5, sizeof(int), compare);
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

在这个例子中,compare函数作为回调函数传递给qsort,用于比较数组元素,从而完成排序。

完~


http://www.kler.cn/a/501946.html

相关文章:

  • CNN张量输入形状和特征图
  • Http 响应状态码 前后端联调
  • ElasticSearch在Windows环境搭建测试
  • Cookie和Session
  • 【大数据】机器学习 -----关于data.csv数据集分析案例
  • ubuntu20.04 安装RTX2060驱动
  • 云原生周刊:Prometheus 3.0 正式发布
  • 检测模型安全的更高级的方法
  • 例子:WeTextProcessing,如何查看现在已安装的这个模块的版本号呢?查看虚拟环境中模块的版本
  • 征服Windows版nginx(2)
  • 今日总结 2025-01-13
  • 【Apache Paimon】-- 14 -- Spark 集成 Paimon 之 Filesystem Catalog 与 Hive Catalog 实践
  • matlab的绘图的标题中(title)添加标量以及格式化输出
  • 青少年编程与数学 02-006 前端开发框架VUE 17课题、组件深入
  • CClink IEF Basic设备数据 转 EtherCAT项目案例
  • 基于React的两种方式使用React-pdf
  • 开关不一定是开关灯用 - 命令模式(Command Pattern)
  • HarMonyOS使用Tab构建页签
  • Megatron:深度学习中的高性能模型架构
  • LeetCode 977 题:有序数组的平方
  • Python AI教程之十八:监督学习之决策树(9) 决策树模型中的过度拟合
  • 提升租赁效率的租赁小程序全解析
  • ElasticSearch在Windows环境搭建测试
  • springcloudalibaba集成fegin报错ClassNotFoundException解决方案
  • 探索 C++ 与 LibUSB:开启 USB 设备交互的奇幻之旅
  • 47_Lua文件IO操作