C语言进阶知识点详解

C语言进阶知识点详解

一、指针的高级应用

(一)指针与数组

1. 数组名的本质

在C语言中,数组名在大多数情况下会被隐式地转换为指向数组首元素的指针。例如,对于一个整型数组int arr[5];arr在表达式中(除了作为sizeof运算符的操作数和&运算符的操作数)会被转换为指向数组第一个元素(arr[0])的指针,其类型是int*。这使得我们可以用指针的方式来访问数组元素。比如*(arr + i)arr[i]是等价的,都是访问数组的第i个元素。

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5}; // 定义一个整型数组
    int* ptr = arr; // 将数组名赋给指针变量,数组名隐式转换为指向首元素的指针

    // 使用指针访问数组元素
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] = %d\n", i, *(ptr + i)); // *(ptr + i)等价于arr[i]
    }

    return 0;
}

输出结果:

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5

由于数组名是地址常量,不能对数组名进行赋值操作来改变它的指向。例如,arr = arr + 1;是非法的。

2. 多维数组与指针

对于多维数组,如int arr[3][4];,数组名arr是一个指向数组第一行的指针,其类型是int (*)[4]。这意味着arr指向的是一个包含4个整数的数组。我们可以通过*(arr + i)来访问第i行,而*(arr + i) + j可以用来访问第i行第j列的元素。

#include <stdio.h>

int main() {
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    }; // 定义一个二维数组

    // 使用指针访问二维数组元素
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("arr[%d][%d] = %d\n", i, j, *(*(arr + i) + j));
        }
    }

    return 0;
}

输出结果:

arr[0][0] = 1
arr[0][1] = 2
arr[0][2] = 3
arr[0][3] = 4
arr[1][0] = 5
arr[1][1] = 6
arr[1][2] = 7
arr[1][3] = 8
arr[2][0] = 9
arr[2][1] = 10
arr[2][2] = 11
arr[2][3] = 12

当我们将多维数组传递到函数中时,函数的参数声明可以利用指针来实现。例如,如果要传递一个二维数组到函数中,函数原型可以写为void func(int (*p)[4]),其中p是一个指向包含4个整数的数组的指针。在函数体内,可以通过(*p)[i][j]或者p[i][j]来访问数组元素。

#include <stdio.h>

// 函数声明,参数是一个指向包含4个整数的数组的指针
void printArray(int (*p)[4], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", p[i][j]); // 访问二维数组元素
        }
        printf("\n");
    }
}

int main() {
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    printArray(arr, 3); // 调用函数,传递二维数组

    return 0;
}

输出结果:

1 2 3 4 
5 6 7 8 
9 10 11 12 

(二)指针与函数

1. 函数指针

函数指针是一种特殊的指针,它指向的是函数的入口地址。函数指针的声明方式是返回值类型 (*指针变量名)(参数列表)。例如,int (*func_ptr)(int, int);声明了一个函数指针func_ptr,它可以指向一个返回整型值并且有两个整型参数的函数。

#include <stdio.h>

// 定义一个函数,返回两个整数的和
int add(int a, int b) {
    return a + b;
}

// 定义一个函数指针,指向返回整型值并且有两个整型参数的函数
int (*func_ptr)(int, int);

int main() {
    func_ptr = add; // 将函数add的地址赋给函数指针func_ptr
    int result = func_ptr(3, 4); // 通过函数指针调用函数
    printf("Result: %d\n", result);

    return 0;
}

输出结果:

Result: 7

函数指针可以用于实现回调函数。例如,在一个图形用户界面程序中,当用户点击按钮时,可以将一个函数指针作为参数传递给按钮的事件处理函数,这样当按钮被点击时,就可以调用这个函数指针指向的函数来处理事件。

函数指针还可以用于函数数组。如果有一组功能相似但具体实现不同的函数,可以将它们的地址存储在一个函数指针数组中,然后通过索引调用不同的函数。例如,int (*func_array[5])(int);声明了一个包含5个函数指针的数组,每个函数指针都指向一个返回整型值并且有一个整型参数的函数。

#include <stdio.h>

// 定义几个功能不同的函数
int addOne(int a) {
    return a + 1;
}

int subtractOne(int a) {
    return a - 1;
}

int multiplyByTwo(int a) {
    return a * 2;
}

int divideByTwo(int a) {
    return a / 2;
}

int square(int a) {
    return a * a;
}

int main() {
    // 定义一个函数指针数组
    int (*func_array[5])(int) = {addOne, subtractOne, multiplyByTwo, divideByTwo, square};

    int num = 10;
    for (int i = 0; i < 5; i++) {
        printf("Function %d result: %d\n", i + 1, func_array[i](num));
    }

    return 0;
}

输出结果:

Function 1 result: 11
Function 2 result: 9
Function 3 result: 20
Function 4 result: 5
Function 5 result: 100
2. 指针作为函数参数

当指针作为函数参数时,函数可以通过指针直接修改调用者传入的变量。这与值传递不同,值传递只是将变量的副本传递给函数,函数内部对参数的修改不会影响调用者的变量。

例如,有一个函数void swap(int* a, int* b),它的作用是交换两个整数变量的值。在函数体内,可以通过*a*b来访问和修改传入的变量。当调用swap(&x, &y)时,xy的值就会被交换。这种方式可以避免返回多个值时使用结构体或者数组来传递返回值,提高了代码的简洁性。

#include <stdio.h>

// 定义一个函数,交换两个整数变量的值
void swap(int* a, int* b) {
    int temp = *a; // 通过指针访问变量的值
    *a = *b;       // 修改变量的值
    *b
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

槐月杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值