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. 忘记释放动态内存

相关推荐
苦藤新鸡1 小时前
64 搜索平移递增数组中的元素
数据结构·算法
百锦再1 小时前
Java InputStream和OutputStream实现类完全指南
java·开发语言·spring boot·python·struts·spring cloud·kafka
Vic101011 小时前
链表算法三道
java·数据结构·算法·链表
二年级程序员1 小时前
一篇文章掌握“栈”
c语言·数据结构
mjhcsp1 小时前
C++区间 DP解析
开发语言·c++
danyang_Q2 小时前
vscode python-u问题
开发语言·vscode·python
再难也得平2 小时前
[LeetCode刷题]128.最长连续序列(从零开始的java题解)
java·算法·leetcode
春和景明3602 小时前
费曼学习法8
学习
忘忧记2 小时前
python QT sqlsite版本 图书管理系统
开发语言·python·qt