当前位置: 首页 > article >正文

二级指针略解【C语言】

int** a为例

      1.二级指针的声明

  • a 是一个指向 int*(指向整型的指针)的指针,即二级指针

  • 通俗的讲,a是一个指向指针的指针,对a解引用会是一个指针

  • 它可以用于操作动态分配的二维数组、指针数组或需要间接修改指针的场景。

    2.动态二维数组的表示

  • 例如动态分配一个 N×M 的二维数组:

    int** a =(int**)malloc(N*sizeof(int*));
    	for(int i=0;i<N;i++){
    		*(a+i)=(int*)malloc(M*sizeof(int));
    		//a[i]=(int*)malloc(M*sizeof(int));
    	}

    3.函数参数传递

  • 当二级指针作为函数参数传递是,有以下几种意思:

  • 1.作为指针数组使用:

  • void example(int** a,int size){
    	for(int i=0;i<size;i++){
    		a[i]=NULL;//初始化
    	}
    }

    2.作为二维数组使用:

  • void example(int** a,int size,int* aColSize){
    	for(int i=0;i<size;i++){
    		for(int j=0;j<aColSize[i];j++){
    			a[i][j]=0;//初始化
    		}
    	}
    }

    3.作为传回的指针使用:

  • void example(int** a){
    	*a=NULL;
    }

    和这段代码是一样的作用:

  • int* example(int* a){
    	a=NULL;
    	return a;
    }

    注意:

  • 1.混淆二维数组和二级指针

  • 虽然二级指针作为函数参数传递可以作为二维数组使用,但不能二维数组作为二级指针接收的参数使用!

  • 例如以下是错误做法

  • #include<stdio.h>
    void example(int** a,int size,int* aColSize){
    	for(int i=0;i<size;i++){
    		for(int j=0;j<aColSize[i];j++){
    			a[i][j]=0;//初始化
    		}
    	}
    }
    int main() {
    	int a[10][10],size=10,aColSize[10];
    	for(int i=0;i<10;i++){
    		aColSize[i]=10;
    		for(int j=0;j<10;j++){
    			scanf("%d",&a[i][j]);
    		}
    	}
    	example(a,size,aColSize);//错误:企图将二维数组作为二级指针接收的参数	
    	return 0;
    }

    正确做法应该这样做:

  • #include<stdio.h>
    #include<stdlib.h>
    void example(int** a, int size, int* aColSize) {
    	for (int i = 0; i < size; i++) {
    		for (int j = 0; j < aColSize[i]; j++) {
    			a[i][j] = 0; //初始化
    			printf("%d_%d ", i, j);
    		}
    	}
    }
    int main() {
    	int *a[10], size = 10, aColSize[10];
    	for (int i = 0; i < size; i++) {
    		a[i] = (int*)malloc(10*sizeof(int));
    	}
    	for (int i = 0; i < size; i++) {
    		aColSize[i] = size;
    		for (int j = 0; j < size; j++) {
    			scanf("%d", &a[i][j]);
    		}
    	}
    	example(a, size, aColSize);
    	for(int i=0;i<size;i++){
    		free(a[i]);
    	}
    	return 0;
    }

    千万不要写成以下这样,虽然编译器可能不会报错,但向野指针指向的区域赋值是不可取的,程序会崩溃的。

  • #include<stdio.h>
    #include<stdlib.h>
    void example(int** a, int size, int* aColSize) {
    	for (int i = 0; i < size; i++) {
    		for (int j = 0; j < aColSize[i]; j++) {
    			a[i][j] = 0; //初始化
    			printf("%d_%d ", i, j);
    		}
    	}
    }
    int main() {
    	int *a[10], size = 10, aColSize[10];//a数组未初始化
    	for (int i = 0; i < size; i++) {
    		aColSize[i] = size;
    		for (int j = 0; j < size; j++) {
    			scanf("%d", &a[i][j]);
    		}
    	}
    	example(a, size, aColSize);
    	return 0;
    }

  • 二级指针用来作为动态二维数组时,分配的内存不连续的,但静态分配的二维数组内存上是连续的!因此,也不能将静态二维数组的首元素地址赋给二级指针!

  • 以下是错误示例:

  •      int arr[3][4];
         int **p = (int**)arr;  // ❌ 编译通过但运行崩溃

    2.动态内存释放

  • 虽然程序一般在运行结束后会自动释放所用内存,但为保证程序长时间运行内存足够,因此用malloc等函数动态分配的内存使用后要释放!一般称其为避免内存泄漏。养成用完释放的好习惯,避免工作时的项目出错。

  • 内存释放对于二级指针一定要有先后顺序

  • 以下是错误示范1

  • void example(){
    	int N,M;
    	scanf("%d %d",&N,&M);
    	int** a=(int**)malloc(N*sizeof(int*));
    	for(int i=0;i<N;i++){
    		a[i]=(int*)malloc(M*sizeof(int));
    	}
        free(a);//只释放了a数组,但未释放a+i(0<i<10)这些数组!
    }

    以下是错误示范2

  • void example(){
    	int N,M;
    	scanf("%d %d",&N,&M);
    	int** a=(int**)malloc(N*sizeof(int*));
    	for(int i=0;i<N;i++){
    		a[i]=(int*)malloc(M*sizeof(int));
    	}
    	free(a);
    	for(int i=0;i<N;i++){
    		free(a[i]);//由于a数组的内存已经释放,a[i]的指针信息丢失,无法释放内存!
    	}
    }

    以下是正确示例

  • void example(){
    	int N,M;
    	scanf("%d %d",&N,&M);
    	int** a=(int**)malloc(N*sizeof(int*));
    	for(int i=0;i<N;i++){
    		a[i]=(int*)malloc(M*sizeof(int));
    	}
    	for(int i=0;i<N;i++){
    		free(a[i]);
    	}
    	free(a);
    }

  • 关键要点总结

  • ✅ 二级指针本质:指向指针的指针

  • ✅ 正确使用场景:动态多维数组、需间接修改指针

  • ⚠️ 常见错误:混淆静态/动态内存布局、未初始化指针

  • 🔧 最佳实践:分配后立即初始化、使用完毕及时释放
     


http://www.kler.cn/a/553935.html

相关文章:

  • mac下使用webstorm监听less文件自动生成wxss文件
  • 内核数据结构用法(2)list
  • Kubernetes: Kustomize 进阶, 使用 Patch 精准操控 ConfigMap 多行文本,实现配置参数化
  • 【JavaWeb10】服务器渲染技术 --- JSP
  • 51c深度学习~合集2
  • Rust中的Trait与Trait Bounds
  • C++时之律者的代码掌控:日期类计算器万字详解
  • 仿 Sora 之形,借物理模拟之技绘视频之彩
  • 嵌入式面试高频面试题:嵌入式系统调试方法大全
  • Mysql基础语句
  • LeetCode 1299.将每个元素替换为右侧最大元素:倒序遍历,维护最大值,原地修改
  • rust笔记5-derive属性2
  • python和pycharm 和Anaconda的关系
  • Mysql各操作系统安装全详情
  • 主机的基本构成
  • 【Qt】缩略词
  • SpringCloud系列教程:微服务的未来 (五)枚举处理器、JSON处理器、分页插件实现
  • ceph HEALTH_WARN clock skew detected on mon.f, mon.o, mon.p, mon.q
  • 网络安全要学python 网络安全要学爬虫吗
  • vscode创建java web项目