C语言基础-六、指针

目录

0、指针基础概念

[0.1 指针与指针变量](#0.1 指针与指针变量)

[0.2 指针变量定义](#0.2 指针变量定义)

[0.3 *号和&号的含义](#0.3 *号和&号的含义)

[0.4 &和*的关系](#0.4 &和*的关系)

1、指针的作用

[1.1 查询和修改数据](#1.1 查询和修改数据)

[1.2 函数参数传递(修改外部变量)](#1.2 函数参数传递(修改外部变量))

[1.3 函数返回多个值](#1.3 函数返回多个值)

[1.4 函数返回状态和结果分离](#1.4 函数返回状态和结果分离)

[1.5 延长变量生命周期(static)](#1.5 延长变量生命周期(static))

2、指针的运算

[2.1 指针加减整数(偏移)](#2.1 指针加减整数(偏移))

[2.2 指针减法(计算距离)](#2.2 指针减法(计算距离))

[2.3 指针运算规则](#2.3 指针运算规则)

3、指针与数组

[3.1 数组名与指针的关系](#3.1 数组名与指针的关系)

[3.2 数组名退化的例外情况](#3.2 数组名退化的例外情况)

[3.3 指针遍历数组](#3.3 指针遍历数组)

[3.4 数组指针 vs 指针数组](#3.4 数组指针 vs 指针数组)

4、指针与函数

[4.1 函数指针](#4.1 函数指针)

[4.2 函数指针数组(回调函数)](#4.2 函数指针数组(回调函数))

[4.3 函数作为参数(回调)](#4.3 函数作为参数(回调))

5、特殊指针类型

[5.1 void指针(万能指针)](#5.1 void指针(万能指针))

[5.2 const与指针](#5.2 const与指针)

[5.3 二级指针(多级指针)](#5.3 二级指针(多级指针))

[5.4 三级指针示例](#5.4 三级指针示例)

6、危险指针

[6.1 野指针](#6.1 野指针)

[6.2 悬空指针](#6.2 悬空指针)

[6.3 返回局部变量地址](#6.3 返回局部变量地址)

[6.4 指针类型总结](#6.4 指针类型总结)

7、指针与动态内存

[7.1 malloc/free](#7.1 malloc/free)

[7.2 calloc(初始化为0)](#7.2 calloc(初始化为0))

[7.3 realloc(重新分配)](#7.3 realloc(重新分配))

8、综合练习

[8.1 字符串复制函数](#8.1 字符串复制函数)

[8.2 动态数组实现](#8.2 动态数组实现)

[8.3 链表节点(指针应用)](#8.3 链表节点(指针应用))

9、常见错误与避坑指南

10、指针使用原则

指针:存储内存地址的变量,是C语言最强大也最危险的特性

本质:指针变量里存储的是另一个变量的内存地址

核心价值:直接操作内存、提高效率、实现复杂数据结构


0、指针基础概念

0.1 指针与指针变量

cpp 复制代码
指针 → 内存地址本身
指针变量 → 存储内存地址的变量(通常简称"指针")

关系:指针变量 存储 指针(地址) 指向 目标变量

0.2 指针变量定义

cpp 复制代码
// 语法格式
数据类型 *指针变量名;

// 示例
int *p;        // 指向int的指针
float *pf;     // 指向float的指针
char *pc;      // 指向char的指针

// 定义并初始化
int a = 10;
int *p = &a;   // p存储a的地址

⚠️ 重要:指针的数据类型必须与指向变量的类型保持一致

0.3 *号和&号的含义

符号 名称 使用场景 含义 示例
& 取地址运算符 普通变量前 获取变量的内存地址 &a
* 指针声明符 定义时 声明这是一个指针变量 int *p;
* 解引用运算符 使用时 通过地址访问目标数据 *p
cpp 复制代码
#include <stdio.h>

int main() {
    int a = 10;
    int *p = &a;  // 定义时的*是指针声明符
    
    printf("a的值: %d\n", a);      // 10
    printf("a的地址: %p\n", &a);   // 0x...
    printf("p的值: %p\n", p);      // 0x... (与&a相同)
    printf("p的地址: %p\n", &p);   // 0x... (p变量自己的地址)
    printf("*p的值: %d\n", *p);    // 10 (解引用,获取a的值)
    
    *p = 20;  // 使用时的*是解引用运算符,修改a的值
    printf("修改后a的值: %d\n", a);  // 20
    
    return 0;
}

0.4 &和*的关系

cpp 复制代码
& 和 * 互为逆运算:

&*p = p    (先解引用再取地址,回到指针本身)
*&a = a    (先取地址再解引用,回到原值)

形象理解:
& → 问"你家住哪儿?" (得到门牌号/地址)
* → 按门牌号"找人" (得到房子里的人/数据)

1、指针的作用

1.1 查询和修改数据

cpp 复制代码
#include <stdio.h>

int main() {
    int a = 10;
    int *p = &a;
    
    // 查询数据
    int value = *p;  // value = 10
    
    // 修改数据
    *p = 20;         // a 变为 20
    
    printf("a = %d\n", a);  // 20
    
    return 0;
}

1.2 函数参数传递(修改外部变量)

cpp 复制代码
#include <stdio.h>

// 值传递:无法修改原变量
void swapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

// 地址传递:可以修改原变量
void swapByPointer(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 10, y = 20;
    
    swapByValue(x, y);
    printf("值传递后: x=%d, y=%d\n", x, y);  // 10, 20 (未变)
    
    swapByPointer(&x, &y);
    printf("地址传递后: x=%d, y=%d\n", x, y);  // 20, 10 (已变)
    
    return 0;
}

1.3 函数返回多个值

cpp 复制代码
#include <stdio.h>

// 通过指针参数返回多个结果
void getMaxAndMin(int arr[], int len, int *max, int *min) {
    *max = arr[0];
    *min = arr[0];
    
    for (int i = 1; i < len; i++) {
        if (arr[i] > *max) {
            *max = arr[i];
        }
        if (arr[i] < *min) {
            *min = arr[i];
        }
    }
}

int main() {
    int arr[] = {3, 7, 1, 9, 5, 2, 8, 4, 6, 10};
    int len = sizeof(arr) / sizeof(arr[0]);
    
    int max, min;
    getMaxAndMin(arr, len, &max, &min);
    
    printf("最大值: %d\n", max);  // 10
    printf("最小值: %d\n", min);  // 1
    
    return 0;
}

1.4 函数返回状态和结果分离

cpp 复制代码
#include <stdio.h>

// 返回值表示状态,指针参数返回结果
// 返回0表示成功,返回1表示失败
int getRemainder(int num1, int num2, int *result) {
    if (num2 == 0) {
        return 1;  // 错误:除数为0
    }
    *result = num1 % num2;
    return 0;  // 成功
}

int main() {
    int a = 10, b = 3, res;
    
    int status = getRemainder(a, b, &res);
    
    if (status == 0) {
        printf("%d %% %d = %d\n", a, b, res);
    } else {
        printf("错误:除数不能为0\n");
    }
    
    // 测试除数为0的情况
    status = getRemainder(10, 0, &res);
    if (status == 1) {
        printf("捕获到除零错误!\n");
    }
    
    return 0;
}

1.5 延长变量生命周期(static)

cpp 复制代码
#include <stdio.h>

// 普通局部变量:函数结束即销毁
int* getPointerNormal() {
    int a = 10;
    return &a;  // 危险!返回局部变量地址
}

// static变量:程序结束才销毁
int* getPointerStatic() {
    static int a = 10;
    return &a;  // 安全
}

int main() {
    // int *p = getPointerNormal();  // 野指针!
    
    int *p = getPointerStatic();
    printf("*p = %d\n", *p);  // 10
    
    return 0;
}

2、指针的运算

2.1 指针加减整数(偏移)

cpp 复制代码
#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p = arr;  // p指向arr[0]
    
    printf("p = %p, *p = %d\n", p, *p);      // arr[0]
    printf("p+1 = %p, *(p+1) = %d\n", p+1, *(p+1));  // arr[1]
    printf("p+2 = %p, *(p+2) = %d\n", p+2, *(p+2));  // arr[2]
    
    // 指针步长 = sizeof(基类型)
    // int* 步长 = 4字节
    // char* 步长 = 1字节
    // double* 步长 = 8字节
    
    return 0;
}

2.2 指针减法(计算距离)

cpp 复制代码
#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p1 = &arr[1];  // 指向arr[1]
    int *p2 = &arr[4];  // 指向arr[4]
    
    // 指针相减 = 元素个数(不是字节数)
    int distance = p2 - p1;  // 3
    
    printf("距离: %d 个元素\n", distance);
    printf("字节距离: %ld 字节\n", (char*)p2 - (char*)p1);  // 12字节
    
    return 0;
}

2.3 指针运算规则

操作 是否合法 说明
指针 + 整数 向后移动N个元素
指针 - 整数 向前移动N个元素
指针 - 指针 计算元素个数差
指针 + 指针 无意义
指针 × 整数 无意义
指针 ÷ 整数 无意义

3、指针与数组

3.1 数组名与指针的关系

cpp 复制代码
#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int *p = arr;  // 数组名退化为首元素地址
    
    // 三种等价写法
    printf("%d\n", arr[0]);    // 1
    printf("%d\n", *arr);      // 1
    printf("%d\n", *p);        // 1
    printf("%d\n", p[0]);      // 1
    
    // 地址相同但类型不同
    printf("arr = %p\n", (void*)arr);
    printf("&arr[0] = %p\n", (void*)&arr[0]);
    printf("&arr = %p\n", (void*)&arr);
    
    return 0;
}

3.2 数组名退化的例外情况

cpp 复制代码
#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    
    // 例外1:sizeof不会退化
    printf("sizeof(arr) = %zu\n", sizeof(arr));    // 20 (5×4)
    printf("sizeof(*arr) = %zu\n", sizeof(*arr));  // 4
    
    // 例外2:&arr不会退化
    printf("arr = %p\n", (void*)arr);        // 0x...
    printf("arr+1 = %p\n", (void*)(arr+1));  // +4字节
    printf("&arr = %p\n", (void*)&arr);      // 0x... (值相同)
    printf("&arr+1 = %p\n", (void*)(&arr+1)); // +20字节 (整个数组)
    
    return 0;
}

3.3 指针遍历数组

cpp 复制代码
#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int len = sizeof(arr) / sizeof(arr[0]);
    
    // 方式1:下标法
    printf("下标法: ");
    for (int i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    // 方式2:指针法(不改变p)
    printf("指针法1: ");
    for (int i = 0; i < len; i++) {
        printf("%d ", *(arr + i));
    }
    printf("\n");
    
    // 方式3:指针移动
    printf("指针法2: ");
    int *p = arr;
    for (int i = 0; i < len; i++) {
        printf("%d ", *p++);
    }
    printf("\n");
    
    return 0;
}

3.4 数组指针 vs 指针数组

cpp 复制代码
// 数组指针:指向数组的指针
int (*p)[5];    // p是一个指针,指向含5个int的数组
int arr[5];
p = &arr;       // 正确

// 指针数组:存放指针的数组
int *arr2[5];   // arr2是一个数组,含5个int指针
int a = 1, b = 2, c = 3, d = 4, e = 5;
arr2[0] = &a;
arr2[1] = &b;
// ...
类型 声明 含义 步长
数组指针 int (*p)[5] 指向数组的指针 20字节
指针数组 int *p[5] 存放指针的数组 8字节

4、指针与函数

4.1 函数指针

cpp 复制代码
#include <stdio.h>

// 普通函数
int add(int a, int b) {
    return a + b;
}

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

int main() {
    // 定义函数指针
    int (*funcPtr)(int, int);
    
    // 指向函数
    funcPtr = add;
    printf("5 + 3 = %d\n", funcPtr(5, 3));  // 8
    
    funcPtr = subtract;
    printf("5 - 3 = %d\n", funcPtr(5, 3));  // 2
    
    return 0;
}

4.2 函数指针数组(回调函数)

cpp 复制代码
#include <stdio.h>

int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { 
    if (b != 0) return a / b;
    return 0;
}

int main() {
    // 函数指针数组
    int (*operations[4])(int, int) = {add, subtract, multiply, divide};
    const char *names[] = {"加法", "减法", "乘法", "除法"};
    
    int num1, num2, choice;
    
    printf("请输入两个数字: ");
    scanf("%d %d", &num1, &num2);
    
    printf("选择运算: 0-加法 1-减法 2-乘法 3-除法\n");
    scanf("%d", &choice);
    
    if (choice >= 0 && choice < 4) {
        int result = operations[choice](num1, num2);
        printf("%s 结果: %d\n", names[choice], result);
    } else {
        printf("无效选择\n");
    }
    
    return 0;
}

4.3 函数作为参数(回调)

cpp 复制代码
#include <stdio.h>

// 通用排序函数(使用回调)
void bubbleSort(int arr[], int len, int (*compare)(int, int)) {
    for (int i = 0; i < len - 1; i++) {
        for (int j = 0; j < len - 1 - i; j++) {
            if (compare(arr[j], arr[j + 1]) > 0) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

// 升序比较
int compareAsc(int a, int b) {
    return a - b;
}

// 降序比较
int compareDesc(int a, int b) {
    return b - a;
}

int main() {
    int arr[] = {5, 2, 8, 1, 9};
    int len = sizeof(arr) / sizeof(arr[0]);
    
    bubbleSort(arr, len, compareAsc);
    printf("升序: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    printf("\n");
    
    bubbleSort(arr, len, compareDesc);
    printf("降序: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    printf("\n");
    
    return 0;
}

5、特殊指针类型

5.1 void指针(万能指针)

cpp 复制代码
#include <stdio.h>
#include <string.h>

// 通用交换函数(按字节交换)
void swap(void *p1, void *p2, size_t size) {
    char *temp = (char*)malloc(size);
    if (temp == NULL) return;
    
    memcpy(temp, p1, size);
    memcpy(p1, p2, size);
    memcpy(p2, temp, size);
    
    free(temp);
}

int main() {
    // 交换int
    int a = 10, b = 20;
    swap(&a, &b, sizeof(int));
    printf("a=%d, b=%d\n", a, b);  // 20, 10
    
    // 交换double
    double x = 1.5, y = 2.5;
    swap(&x, &y, sizeof(double));
    printf("x=%.1f, y=%.1f\n", x, y);  // 2.5, 1.5
    
    return 0;
}

⚠️ void指针特点

  • 可以接收任意类型指针
  • 不能直接解引用(需类型转换)
  • 不能进行指针运算(需类型转换)

5.2 const与指针

cpp 复制代码
#include <stdio.h>

int main() {
    int a = 10, b = 20;
    
    // 1. 指针常量:指针本身不能变
    int * const p1 = &a;
    *p1 = 30;  // 可以修改指向的值
    // p1 = &b;  // 不能修改指针本身
    
    // 2. 常量指针:指向的值不能变
    const int *p2 = &a;
    // *p2 = 30;  // 不能修改指向的值
    p2 = &b;  // 可以修改指针本身
    
    // 3. 常量指针常量:都不能变
    const int * const p3 = &a;
    // *p3 = 30;  // 不能变
    // p3 = &b;   // 不能变
    
    return 0;
}
类型 声明 指针可变 值可变
普通指针 int *p
指针常量 int * const p
常量指针 const int *p
常量指针常量 const int * const p

5.3 二级指针(多级指针)

cpp 复制代码
#include <stdio.h>

int main() {
    int a = 10;
    int *p = &a;      // 一级指针
    int **pp = &p;    // 二级指针
    
    printf("a = %d\n", a);          // 10
    printf("*p = %d\n", *p);        // 10
    printf("**pp = %d\n", **pp);    // 10
    
    printf("&a = %p\n", (void*)&a);
    printf("p = %p\n", (void*)p);
    printf("*pp = %p\n", (void*)*pp);
    
    // 通过二级指针修改一级指针
    int b = 20;
    *pp = &b;  // 修改p指向b
    printf("修改后 *p = %d\n", *p);  // 20
    
    return 0;
}

5.4 三级指针示例

cpp 复制代码
#include <stdio.h>

int main() {
    int a = 100;
    int *p = &a;
    int **pp = &p;
    int ***ppp = &pp;
    
    printf("a = %d\n", a);          // 100
    printf("*p = %d\n", *p);        // 100
    printf("**pp = %d\n", **pp);    // 100
    printf("***ppp = %d\n", ***ppp); // 100
    
    return 0;
}

6、危险指针

6.1 野指针

cpp 复制代码
#include <stdio.h>

int main() {
    // 野指针:未初始化的指针
    int *p;  // p的值是随机的
    // *p = 10;  // 危险!可能崩溃
    
    // 正确做法:初始化为NULL
    int *p2 = NULL;
    if (p2 != NULL) {
        *p2 = 10;
    }
    
    return 0;
}

6.2 悬空指针

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *p = (int*)malloc(sizeof(int));
    *p = 10;
    
    free(p);  // 释放内存
    // p = NULL;  // 忘记置NULL
    
    // *p = 20;  // 悬空指针!危险!
    
    // 正确做法
    int *p2 = (int*)malloc(sizeof(int));
    *p2 = 10;
    free(p2);
    p2 = NULL;  // 避免悬空
    
    return 0;
}

6.3 返回局部变量地址

cpp 复制代码
#include <stdio.h>

// 错误:返回局部变量地址
int* getBadPointer() {
    int a = 10;
    return &a;  // 函数结束后a被销毁
}

// 正确:使用static或动态分配
int* getGoodPointer1() {
    static int a = 10;
    return &a;  // static变量生命周期到程序结束
}

int* getGoodPointer2() {
    int *a = (int*)malloc(sizeof(int));
    *a = 10;
    return a;  // 堆内存,调用者负责free
}

int main() {
    // int *p = getBadPointer();  // 危险!
    
    int *p1 = getGoodPointer1();
    printf("*p1 = %d\n", *p1);
    
    int *p2 = getGoodPointer2();
    printf("*p2 = %d\n", *p2);
    free(p2);
    
    return 0;
}

6.4 指针类型总结

指针类型 状态 危险程度 解决方案
野指针 未初始化 ⚠️⚠️⚠️ 初始化为NULL
悬空指针 已释放 ⚠️⚠️⚠️ free后置NULL
越界指针 超出范围 ⚠️⚠️⚠️ 检查边界
类型不匹配 错误转换 ⚠️⚠️ 正确类型转换

7、指针与动态内存

7.1 malloc/free

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    // 分配单个int
    int *p = (int*)malloc(sizeof(int));
    if (p == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    *p = 10;
    printf("*p = %d\n", *p);
    free(p);
    p = NULL;
    
    // 分配数组
    int n = 5;
    int *arr = (int*)malloc(n * sizeof(int));
    if (arr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    
    for (int i = 0; i < n; i++) {
        arr[i] = i * 10;
    }
    
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    free(arr);
    arr = NULL;
    
    return 0;
}

7.2 calloc(初始化为0)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    // calloc自动初始化为0
    int *arr = (int*)calloc(5, sizeof(int));
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);  // 0 0 0 0 0
    }
    printf("\n");
    
    free(arr);
    return 0;
}

7.3 realloc(重新分配)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr = (int*)malloc(3 * sizeof(int));
    arr[0] = 1; arr[1] = 2; arr[2] = 3;
    
    // 扩容到5个元素
    int *temp = (int*)realloc(arr, 5 * sizeof(int));
    if (temp == NULL) {
        free(arr);
        return 1;
    }
    arr = temp;
    
    arr[3] = 4; arr[4] = 5;
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);  // 1 2 3 4 5
    }
    printf("\n");
    
    free(arr);
    return 0;
}

8、综合练习

8.1 字符串复制函数

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 手动实现strcpy
char* myStrcpy(char *dest, const char *src) {
    char *originalDest = dest;
    while ((*dest++ = *src++) != '\0');
    return originalDest;
}

// 动态分配字符串
char* createString(const char *src) {
    size_t len = strlen(src) + 1;
    char *str = (char*)malloc(len);
    if (str != NULL) {
        myStrcpy(str, src);
    }
    return str;
}

int main() {
    char dest[100];
    myStrcpy(dest, "Hello, World!");
    printf("%s\n", dest);
    
    char *str = createString("Dynamic String");
    if (str != NULL) {
        printf("%s\n", str);
        free(str);
    }
    
    return 0;
}

8.2 动态数组实现

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *data;
    int size;
    int capacity;
} DynamicArray;

// 初始化
void initArray(DynamicArray *arr, int capacity) {
    arr->data = (int*)malloc(capacity * sizeof(int));
    arr->size = 0;
    arr->capacity = capacity;
}

// 添加元素
void pushBack(DynamicArray *arr, int value) {
    if (arr->size >= arr->capacity) {
        arr->capacity *= 2;
        arr->data = (int*)realloc(arr->data, arr->capacity * sizeof(int));
    }
    arr->data[arr->size++] = value;
}

// 获取元素
int get(DynamicArray *arr, int index) {
    if (index >= 0 && index < arr->size) {
        return arr->data[index];
    }
    return -1;
}

// 释放
void freeArray(DynamicArray *arr) {
    free(arr->data);
    arr->data = NULL;
    arr->size = 0;
    arr->capacity = 0;
}

int main() {
    DynamicArray arr;
    initArray(&arr, 5);
    
    for (int i = 0; i < 10; i++) {
        pushBack(&arr, i * 10);
    }
    
    printf("数组内容: ");
    for (int i = 0; i < arr.size; i++) {
        printf("%d ", get(&arr, i));
    }
    printf("\n");
    
    freeArray(&arr);
    return 0;
}

8.3 链表节点(指针应用)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 链表节点
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 创建节点
Node* createNode(int data) {
    Node *node = (Node*)malloc(sizeof(Node));
    node->data = data;
    node->next = NULL;
    return node;
}

// 插入头部
void insertHead(Node **head, int data) {
    Node *newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

// 遍历
void printList(Node *head) {
    Node *current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

// 释放
void freeList(Node *head) {
    Node *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

int main() {
    Node *head = NULL;
    
    insertHead(&head, 3);
    insertHead(&head, 2);
    insertHead(&head, 1);
    
    printList(head);  // 1 -> 2 -> 3 -> NULL
    
    freeList(head);
    return 0;
}

9、常见错误与避坑指南

错误类型 错误示例 正确写法
野指针 int *p; *p=10; int *p = NULL;
悬空指针 free(p); *p=10; free(p); p=NULL;
返回局部地址 return &local; 使用static或malloc
类型不匹配 int *p; double *d; p=d; 使用类型转换
数组越界 arr[len] arr[len-1]
忘记free malloc后不释放 配对使用free
重复free free(p); free(p); free后置NULL
const误用 const int *p; *p=10; 去掉const或改值

10、指针使用原则

cpp 复制代码
✅ 应该做的:
1. 定义指针时初始化为NULL
2. 使用前检查是否为NULL
3. free后立即置NULL
4. 指针类型与指向类型一致
5. 数组传参时同时传递长度
6. 返回堆内存时文档说明需要free

❌ 不应该做的:
1. 使用未初始化的指针
2. 访问已释放的内存
3. 返回局部变量地址
4. 指针运算超出数组范围
5. 混用不同类型的指针
6. 忘记释放动态内存

相关推荐
野犬寒鸦9 分钟前
面试常问:HTTP 1.0 VS HTTP 2.0 VS HTTP 3.0 的核心区别及底层实现逻辑
服务器·开发语言·网络·后端·面试
沐墨专攻技术9 分钟前
一、项目初始化
笔记·学习
geovindu13 分钟前
python: Null Object Pattern
开发语言·python·设计模式
闫记康19 分钟前
scp工具
linux·运维·服务器·学习·ssh·github
lisus200720 分钟前
GO并发统计文件大小
开发语言·后端·golang
我命由我1234523 分钟前
Git 问题:Author identity unknown*** Please tell me who you are.
java·服务器·git·后端·学习·java-ee·学习方法
梦游钓鱼28 分钟前
Logger.h和Logger.cc文件分析
开发语言·c++
G果30 分钟前
LIO-SAM 学习总结
学习·slam·点云·ros2·导航·nav2·liosam
CRMEB系统商城34 分钟前
CRMEB标准版系统(PHP)v6.0公测版发布,商城主题市场上线~
java·开发语言·小程序·php
mit6.82436 分钟前
Agent memory发展路线
算法