【C语言】指针的基本用法及语法规范

文章目录


前言

本文详细讲解 C 语言中指针的概念、声明方式以及正确使用方法


一、指针是什么?

指针是 C 语言中一种特殊的变量,它存储的是其他变量的内存地址。指针让程序可以直接操作内存,从而实现高效的数据传递和灵活的数据结构管理。


二、指针用法及规范

1.基本指针语法

标准写法(推荐写法):星号(*)紧贴变量名,明确表示该变量是指针:

int *p;  // p 是指向 int 的指针

类型后写法:星号(*)可紧贴类型名,但需注意编译器视角:星号(*)实际绑定的是变量名而非类型。

int* p;  // 合法,但注意多变量声明时的陷阱

多变量声明:如果在同一行声明多个变量,必须对每个指针变量都加上 *

int *p, *q;   // 正确:p 和 q 都是 int* 类型
int* p, q;    // 错误:仅 p 为指针,q 为普通 int

指针初始化:未初始化的指针(野指针)指向未知内存,直接解引用可能导致程序崩溃

// 正确示范
int x = 5;
int *p = &x;   // 指向变量 x
int *q = NULL; // 初始化为空指针

// 错误示范
int *p;        // 未初始化的野指针
*p = 10;       // 崩溃风险极高

多级指针:多级指针即指针的指针,常用于需要多重间接访问的场景

int x = 10;
int *p = &x;        // 一级指针
int **pp = &p;      // 二级指针
printf("%d", **pp); // 输出 10

2.指针数组与数组指针

指针数组:指针数组是一个数组,数组中的每个元素都是指针。由于数组下标 []的优先级高于 *,下面的声明表示数组内元素为指针

int *arr[5];  // 定义一个包含 5 个 int* 的数组

// 可定义一个包含若干整数地址的数组
int a = 1, b = 2, c = 3;
int *ptr_arr[3] = {&a, &b, &c};

数组指针:数组指针则是一个指针,指向一个数组(整个数组的首地址)。为避免优先级混淆,需要使用括号明确表示指针绑定的是变量,而非类型

int (*ptr)[5]; // ptr 是指向包含 5 个 int 的数组的指针

// 处理二维数组
int matrix[3][4] = {0};   // 3 行 4 列的二维数组
int (*p)[4] = matrix;     // p 指向一个含 4 个 int 的一维数组

// 通过函数参数传递二维数组时:
void print_matrix(int (*mat)[4], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

3.函数指针

基本语法:函数指针允许将函数作为参数传递或返回,函数指针声明时(*)必须被括号包裹,后面紧跟参数列表。

int (*func_ptr)(int, int);  // func_ptr 是指向接受两个 int 参数并返回 int 的函数的指针
int *func(int, int);       // 错误:声明了一个返回 int* 的函数

回调函数

// 回调函数 compare 用于排序比较
int compare(int a, int b) {
    return a - b;
}

void sort(int *arr, int size, int (*compare)(int, int)) {
    // 简化示例:假设排序实现调用 compare 比较数组元素
}

int main() {
    int data[] = {5, 2, 9};
    sort(data, 3, compare);
    return 0;
}

4.常量指针与指针常量

常量指针:指向常量的指针,指针所指向的数据不能通过该指针修改,但指针本身可以指向其他地址。

const int *p = &x;   // 或写作 int const *p;
// *p = 10;  // 错误,不能通过 p 修改 *p 的值
p = &y;    // 正确,可以改变 p 的指向

指针常量:指针本身是常量,一旦初始化后就不能再改变指向的地址,但可以修改所指数据的值。

int *const p = &x;
*p = 10;   // 正确,可以修改 x 的值
// p = &y; // 错误,不能改变 p 的指向

指向常量的指针常量:指针和所指向的数据都不可修改

const int *const p = &x;
// *p = 10; // 错误,不能修改数据
// p = &y;  // 错误,不能改变指向

5.函数参数与返回值

作为函数参数

(1)传递变量地址

void modifyValue(int *p) {
    *p = 20;
}

int main() {
    int a = 10;
    modifyValue(&a);
    printf("%d\n", a); // 输出 20
    return 0;
}

(2)传递数组指针(数组首地址)

void modifyArray(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        arr[i]++;  // 每个元素加 1
    }
}

int main() {
    int nums[] = {1, 2, 3};
    modifyArray(nums, 3);
    return 0;
}

(3)传递只读数据

// 传入常量指针
void printArray(const int *arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
}

 作为函数返回值

错误示范:返回局部变量地址

int *createValue() {
    int x = 100;
    return &x;  // 错误:x 是局部变量,函数返回后内存无效
}

正确示范:使用动态内存分配

int *createValue() {
    int *p = malloc(sizeof(int));
    if (p) {
        *p = 100;
    }
    return p;
}

int main() {
    int *p = createValue();
    if (p) {
        printf("%d\n", *p);
        free(p);
        p = NULL;
    }
    return 0;
}

 

6.typedef与指针

使用typedef 可以简化复杂指针的声明,使代码更易读

typedef定义指针类型

typedef int* IntPtr;
IntPtr p1, p2;  // p1 和 p2 都是 int* 类型
// 注意与int* p, q; 中 q 变为 int 的区别

typedef与函数指针

typedef int (*FuncPtr)(int, int);
int add(int a, int b) { return a + b; }
FuncPtr f = add;

typedef与结构体指针

typedef struct Node {
    int data;
    struct Node *next;
} Node, *NodePtr;

7.动态内存管理

int main() {
    int *arr = malloc(5 * sizeof(int));
    if (!arr) {
        perror("Memory allocation failed");
        exit(1);
    }
    // 使用 arr...
    free(arr);  // 释放内存
    arr = NULL; // 避免悬空指针
    return 0;
}

8.代码风格建议

指针声明风格

int* p;        // 推荐(指针和 `int*` 绑定)
int *p1, *p2;  // 避免 `int *p1, p2;` 误解

对于不应修改的数据,使用const 限制

void printData(const int *data);

避免内存泄漏

free(ptr);
ptr = NULL;  // 避免 `free()` 之后的悬空指针

对于固定常量,使用 #definetypedef,增加代码可维护性

#define MAX_SIZE 100
typedef unsigned char byte;

总结

本文从指针的基本概念出发,详细介绍了指针的声明、指针数组与数组指针、函数指针、常量指针及其在函数参数和返回值中的应用。同时,还讨论了使用typedef简化复杂指针声明、动态内存管理的正确方法,以及代码风格和最佳实践。希望通过这些内容,能帮助你写出更安全、可读和高效的 C 语言代码。


通过不断实践和积累经验,你会发现指针既强大又灵活,祝你在 C 语言的学习和编程中不断进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值