云计算百科
云计算领域专业知识百科平台

C 语言——深入理解指针(三)

以下是为您补全并优化的博客内容,包含了字符指针、数组指针和函数指针的详细解释、代码示例及其使用注意事项。


文章目录

    • @[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 语言中最强大但也最复杂的特性之一。了解指针的本质对于写出高效且安全的代码至关重要。

  • 字符指针:用于操作字符串。直接指向字符串字面量的指针(如 const char*)通常是只读的。如果需要修改内容,应该将字符串复制到字符数组或堆内存中。
  • 数组指针:指向整个数组的指针,用于处理多维数组或需要传递整个数组时。它与普通指针不同,int (*p)[10] 与 int* p 的含义完全不同。
  • 函数指针:指向函数的指针,用于实现回调函数和多态性。由于语法复杂,建议使用 typedef 为其定义别名,以提升代码可读性。
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » C 语言——深入理解指针(三)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!