C语言-二级指针应用场景

二级指针应用

引子:在线性表 销毁函数中,传入二级指针作为参数,可以实现对线性表的销毁操作。

//销毁已存在的线性表
void DestroyList(list_t **L){
   
    // Step 1: 检查L是否为非空指针
    if(L) 
        // Step 2: 释放L指向的内存空间
        free(*L);
    // Step 3: 将L所指向的指针置为NULL,避免悬挂指针
    *L=NULL;
}

上述代码主要功能是销毁一个已存在的线性表。通过接收一个二级指针(指向线性表的指针),函数首先检查传入的二级指针是否为非空。然后释放线性表所占用的内存空间,并将一级指针置为 NULL,从而避免悬挂指针的问题。这是对动态内存管理中销毁操作的安全处理方式。

list_t **L 为什么使用二级指针

在这个函数中,list_t **L 是一个二级指针,而不仅仅是一级指针,这是为了能够在函数内部修改指向线性表的指针。

原因:

1.直接操作并修改原指针: 如果传入的是一个一级指针 list_t *L,那么在函数内部只能操作其指向的内存内容,但无法修改这个指针本身。如果要让外部也能感知到这个指针已经被置为 NULL,需要使用二级指针。

2.避免悬挂指针: 如果只是释放内存而不置 NULL,外部仍然有一个一级指针指向已释放的内存,这会导致悬挂指针,进而可能引发崩溃或不可预知的错误。

例子对比
void DestroyList(list_t *L) {
   
    if (L) free(L);
    // 此处无法将传入的一级指针置为 NULL
}

void test() {
   
    list_t *list = malloc(sizeof(list_t));
    DestroyList(list);
    // 此时 list 仍然指向原内存,但内存已经被释放,存在悬挂指针风险
}

通过使用二级指针,我们可以在函数内部将指针置为 NULL,避免悬挂指针:

void DestroyList(list_t **L) {
   
    if (L && *L) {
   
        free(*L);
        *L = NULL;
    }
}

void test() {
   
    list_t *list = malloc(sizeof(list_t));
    DestroyList(&list);
    // 此时 list 已经被置为 NULL,避免悬挂指针
}

详细示例解释

void DestroyList(list_t **L) {
   
    if (L && *L) {
   
        // 释放 L 所指向的内存
        free(*L);
        // 将 L 所指向的第一个指针 (即原来的指针) 置为 NULL
        *L = NULL;
    }
}

void test() {
   
    list_t *list = malloc
### 关于C语言二级指针的用法 在C语言中,二级指针是一种特殊的指针类型,它指向另一个指针变量。这意味着二级指针存储的是一个一级指针的地址。以下是关于二级指针的一些基本概念及其使用方法。 #### 基本定义与声明 当我们在程序中创建一个二级指针时,实际上是为其分配了一个内存空间来保存某个一级指针的地址。例如: ```c #include <stdio.h> int main() { int num = 10; int *ptr = &num; // 一级指针,指向整型变量 `num` int **pptr = &ptr; // 二级指针,指向一级指针 `ptr` printf("num 的值: %d\n", num); printf("通过一级指针访问 num 的值: %d\n", *ptr); printf("通过二级指针访问 num 的值: %d\n", **pptr); return 0; } ``` 在这个例子中,`*ptr` 表示解引用操作符用于获取 `num` 变量的值,而 `**pptr` 则表示两次解引用操作最终也得到 `num` 的值[^1]。 #### 动态内存管理中的应用 除了简单地间接访问数据外,二级指针还常被用来动态分配多维数组或者处理函数返回复杂结构的情况。比如,在堆上申请一块连续的空间作为二维数组使用时可以这样写: ```c #include <stdio.h> #include <stdlib.h> void allocate_2D_array(int ***array, int rows, int cols){ (*array) = (int **)malloc(rows * sizeof(int *)); for(int i=0;i<rows;i++) { (*(array)+i)=(int *)malloc(cols*sizeof(int)); } } int main(){ int row=3,col=4,**arr=NULL; allocate_2D_array(&arr,row,col); // 初始化并打印矩阵... for(int i=0;i<row;i++) for(int j=0;j<col;j++) arr[i][j]=i*j; for(int i=0;i<row;i++){ for(int j=0;j<col;j++) printf("%d ",arr[i][j]); puts(""); } // 清理资源 for(int i=0;i<row;i++) free(arr[i]); free(arr); return 0; } ``` 此代码片段展示了如何利用二级指针实现动态二维数组的功能[^2]。 #### 参数传递场景下的优势 另外一个重要用途是在向子函数传参过程中改变调用者环境里的原始对象本身而非副本。如果仅需修改数值,则单层指针已足够;但如果要调整整个指针所指向的位置就需要借助双星号形式了——即所谓的“指针参数”。 假设有一个需求是要交换两个字符串的内容位置而不只是它们各自的拷贝版本,那么就可以采用如下方式完成任务: ```c #include<stdio.h> #include<string.h> // 函数原型声明 void swap_strings(char **str1,char **str2); int main(void){ char strA[]="Hello"; char strB[]="World"; printf("Before swapping:\nStr A:%s \t Str B :%s\n",strA,strB ); /* 调用swap_strings*/ swap_strings((char**)&strA,(char**)&strB ); printf("\nAfter Swapping :\nStr A:%s\t Str B :%s\n",strA ,strB ); return 0;} /* 定义实际执行交换动作的方法 */ void swap_strings(char **stringOnePtrRef,char **stringTwoPtrRef ){ char tempStorage[strlen(*stringTwoPtrRef )+1]; strcpy(tempStorage,*stringTwoPtrRef ); strcpy(*stringTwoPtrRef ,*stringOnePtrRef ); strcpy(*stringOnePtrRef ,tempStorage); } ``` 这里值得注意的一点是我们把原生字符数组的名字当作地址送入到更高层次别的指针里去操纵其内部成员项之间的相对次序关系[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可能只会写BUG

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

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

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

打赏作者

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

抵扣说明:

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

余额充值