C语言9 指针

目录

指针的声明与初始化

指针运算

指针的加法和减法

指针的比较

指针与数组

通过指针访问数组元素

指针与多维数组

声明指向多维数组的指针

访问多维数组元素

指针数组和数组指针

指针数组

数组指针

字符指针

字符串的定义和字符指针

直接使用字符指针初始化字符串

void指针

void指针的声明与使用

const修饰指针

修饰指针指向的内容

修饰指针本身

同时修饰指针和指针指向的内容

多级指针

二级指针

多级指针的使用

指向函数的指针

指针函数

指针传递

指针与动态内存分配

函数指针

回调函数


指针是一个变量,它的值是另一个变量的地址。它通过存储内存地址来间接访问变量。

指针的声明与初始化

指针的声明格式为:

复制代码
类型 *指针名;

例如:

复制代码
int *ptr; // 声明一个指向int类型的指针

指针的初始化可以通过取地址运算符&来完成:

复制代码
int var = 10;
int *ptr = &var; // ptr现在指向变量var的地址

此时,ptr存储的是var的地址,而不是var的值。要访问var的值,可以使用解引用运算符*

复制代码
printf("%d\n", *ptr); // 输出10

指针运算

指针运算包括指针的加法和减法,这些运算在数组遍历和指针偏移中非常有用。

指针的加法和减法

指针加法和减法的本质是以指针所指向数据类型的大小为单位进行的。例如,对于int类型指针,每次加1实际上是加上sizeof(int)个字节。

复制代码
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // ptr指向数组的第一个元素

ptr++; // ptr现在指向数组的第二个元素
printf("%d\n", *ptr); // 输出20

ptr--; // ptr现在指向数组的第一个元素
printf("%d\n", *ptr); // 输出10
指针的比较

指针还可以进行比较运算,常用于判断指针是否达到数组的末尾。

复制代码
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr;

while (ptr < arr + 5) {
    printf("%d ", *ptr);
    ptr++;
}

指针与数组

数组名在很多情况下可以看作是一个指向数组第一个元素的指针。例如:

复制代码
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 等同于int *ptr = &arr[0];

这意味着可以使用指针来遍历数组:

复制代码
for (int i = 0; i < 5; i++) {
    printf("%d ", *(ptr + i)); // 输出数组的每个元素
}
通过指针访问数组元素

可以使用指针加偏移量的方式访问数组元素:

复制代码
printf("%d\n", *(arr + 2)); // 输出30,与arr[2]等价

同样,可以使用下标运算符[]来访问指针所指向的数组元素:

复制代码
printf("%d\n", ptr[2]); // 输出30,与arr[2]等价

指针与多维数组

多维数组的指针处理稍微复杂一些。以二维数组为例:

复制代码
int arr[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};
声明指向多维数组的指针

指向二维数组的指针的声明方式如下:

复制代码
int (*ptr)[4] = arr; // ptr是一个指向包含4个int的数组的指针
访问多维数组元素

可以使用指针偏移来访问多维数组的元素:

复制代码
printf("%d\n", *(*(ptr + 1) + 2)); // 输出7,相当于arr[1][2]

这表示:

  1. ptr + 1移动到第二行,即指向arr[1]
  2. *(ptr + 1)解引用得到第二行的数组,即arr[1]
  3. *(ptr + 1) + 2移动到第二行的第三个元素,即arr[1][2]
  4. 最终,*(*(ptr + 1) + 2)解引用得到该元素的值,即7。

指针数组和数组指针

指针数组和数组指针是两个容易混淆的概念。

指针数组

指针数组是一个数组,其元素是指针。例如:

复制代码
int *arr[3];
int a = 1, b = 2, c = 3;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;

例如,可以创建一个字符指针数组来存储多个字符串:

复制代码
char *names[] = {"Alice", "Bob", "Charlie"};

for (int i = 0; i < 3; i++) {
    printf("%s\n", names[i]);
}
数组指针

数组指针是一个指向数组的指针。例如:

复制代码
int *arr[3];
int a = 1, b = 2, c = 3;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;

字符指针

字符指针用于指向字符类型数据,常用于处理字符串。

字符串的定义和字符指针

在C语言中,字符串是以'\0'结尾的字符数组。字符指针可以指向字符串的第一个字符:

复制代码
char str[] = "Hello, world!";
char *ptr = str; // ptr指向字符串的第一个字符

通过字符指针可以访问字符串中的各个字符:

复制代码
while (*ptr != '\0') {
    printf("%c", *ptr);
    ptr++;
}
直接使用字符指针初始化字符串

可以直接使用字符指针指向字符串常量:

复制代码
char *ptr = "Hello, world!";

需要注意的是,字符串常量是存储在只读内存中的,不能通过指针修改其内容:

复制代码
char *ptr = "Hello, world!";
ptr[0] = 'h'; // 未定义行为,可能导致程序崩溃

void指针

void指针是一种通用指针类型,可以指向任何类型的数据,但不能直接解引用。需要先进行类型转换。

void指针的声明与使用
复制代码
void *ptr;
int a = 10;
ptr = &a; // void指针指向int类型的变量

// 需要进行类型转换后才能解引用
printf("%d\n", *(int *)ptr);

const修饰指针

const可以修饰指针,使指针或指针指向的内容不可修改。

修饰指针指向的内容
复制代码
int a = 10;
const int *ptr = &a; // ptr指向的内容不可修改
// *ptr = 20; // 错误:尝试修改只读变量
ptr = &b; // 可以修改指针本身

本身

修饰指针本身
复制代码
int a = 10;
int b = 20;
int *const ptr = &a; // ptr本身不可修改
*ptr = 20; // 可以修改指针指向的内容
// ptr = &b; // 错误:尝试修改const指针
同时修饰指针和指针指向的内容
复制代码
int a = 10;
const int *const ptr = &a; // ptr本身和ptr指向的内容都不可修改
// *ptr = 20; // 错误:尝试修改只读变量
// ptr = &b; // 错误:尝试修改const指针

多级指针

多级指针是指指向指针的指针。它们可以用于间接访问变量,常用于处理复杂数据结构。

二级指针

二级指针是指向指针的指针:

复制代码
int a = 10;
int *ptr = &a;
int **pptr = &ptr; // 二级指针指向一级指针

printf("%d\n", **pptr); // 输出10,通过二级指针间接访问变量a
多级指针的使用

多级指针在处理动态内存分配和多维数组时非常有用:

复制代码
int rows = 3, cols = 4;
int **matrix = malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
    matrix[i] = malloc(cols * sizeof(int));
}

// 使用matrix
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        matrix[i][j] = i * cols + j;
    }
}

// 释放matrix
for (int i = 0; i < rows; i++) {
    free(matrix[i]);
}
free(matrix);
指向函数的指针

指针不仅可以指向变量,还可以指向函数。函数指针用于实现回调函数和动态函数调用。

复制代码
int add(int a, int b) {
    return a + b;
}

int (*func_ptr)(int, int) = add; // 声明并初始化函数指针

printf("%d\n", func_ptr(2, 3)); // 输出5,通过函数指针调用函数

指针函数

指针函数是指返回指针的函数。它在需要返回动态分配的内存块或者其他指针类型数据时非常有用。

示例
复制代码
int* createArray(int size) {
    int *arr = malloc(size * sizeof(int));
    for (int i = 0; i < size; i++) {
        arr[i] = i;
    }
    return arr;
}

int main() {
    int *array = createArray(5);
    for (int i = 0; i < 5; i++) {
        printf("%d ", array[i]);
    }
    free(array); // 记得释放内存
    return 0;
}

指针传递

在函数调用时传递指针,可以实现对原数据的修改。这是C语言实现传引用的方式。

示例
复制代码
void increment(int *num) {
    (*num)++;
}

int main() {
    int a = 5;
    increment(&a);
    printf("%d\n", a); // 输出6
    return 0;
}

指针与动态内存分配

C语言中使用malloccallocrealloc进行动态内存分配,使用free释放内存。

示例
复制代码
int main() {
    int *arr = malloc(5 * sizeof(int));
    if (arr == NULL) {
        printf("Memory allocation failed");
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        arr[i] = i * i;
    }

    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }

    free(arr); // 释放内存
    return 0;
}

函数指针

函数指针是指向函数的指针,可以用于实现回调函数和动态函数调用。

示例
复制代码
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int main() {
    int (*operation)(int, int);

    operation = add;
    printf("Add: %d\n", operation(5, 3)); // 输出8

    operation = subtract;
    printf("Subtract: %d\n", operation(5, 3)); // 输出2

    return 0;
}

回调函数

回调函数是一种通过函数指针调用的函数,常用于事件驱动编程和异步编程。

示例
复制代码
void processArray(int *arr, int size, void (*process)(int *))
相关推荐
网络安全研发随想几秒前
C语言核心结构+难点精讲+工程技巧
c语言·开发语言·算法
别来无恙2026 分钟前
数据结构(6)
c语言·数据结构
superior tigre13 分钟前
C++学习:六个月从基础到就业——面向对象编程:虚函数与抽象类
开发语言·c++·学习
ademen19 分钟前
关于 IntelliJ IDEA 中频繁出现的 Kotlin 及其核心作用
java·开发语言·kotlin
李煜鑫36 分钟前
关于视频的一些算法内容,不包含代码等
算法·音视频·语音识别
我爱工作&工作love我1 小时前
【深基18.例3】查找文献-图的储存与遍历
算法·深度优先·图论
心软且酷丶1 小时前
leetcode:2899. 上一个遍历的整数(python3解法)
python·算法·leetcode
啾啾Fun1 小时前
数据结构与算法学习导航
学习·算法
m0_zj1 小时前
41.[前端开发-JavaScript高级]Day06-原型关系图-ES6类的使用-ES6转ES5
开发语言·javascript·es6
海棠蚀omo1 小时前
C++笔记-list
开发语言·c++·笔记