二级指针略解【C语言】

ops/2025/2/21 4:13:02/

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.ppmy.cn/ops/160138.html

相关文章

macOS部署DeepSeek-r1

好奇&#xff0c;跟着网友们的操作试了一下 网上方案很多&#xff0c;主要参考的是这篇 DeepSeek 接入 PyCharm&#xff0c;轻松助力编程_pycharm deepseek-CSDN博客 方案是&#xff1a;PyCharm CodeGPT插件 DeepSeek-r1:1.5b 假设已经安装好了PyCharm PyCharm: the Pyth…

力扣-二叉树-501 二叉搜索树的众数

思路 二叉搜索树的特性就是中序遍历有序&#xff0c;所以思考时可以先按照有序数组思考 代码 class Solution { public:vector<int> result;TreeNode* pre nullptr;int count 1;int maxCount 0;void travesl(TreeNode* node){if(node nullptr) return;travesl(nod…

Linux系统:ubuntu系统几款系统界面化工具的区别(xubuntu-desktop和ubuntu-desktop和kubuntu-desktop)

‌Xubuntu-desktop、Ubuntu-desktop和Kubuntu-desktop的主要区别在于它们使用的桌面环境、系统资源占用以及用户界面设计。 主要区别 桌面环境系统资源占用用户界面设计 桌面环境 ‌Xubuntu-desktop‌&#xff1a;使用Xfce桌面环境&#xff0c;这是一个轻量级的桌面环境&#…

从 0 到 1:Spring Boot 构建高效应用指南

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 在当下竞争激烈且技术飞速发展的 Java 开发领域&#xff0c;各类框架层出不穷。而 Spring Boot 凭借…

负载测试工具有哪些?

Apache JMeter Apache JMeter 是一款开源的性能测试工具&#xff0c;主要用于对 Web 应用程序进行功能、负载和压力测试。JMeter 支持多种协议和技术&#xff0c;包括 HTTP, HTTPS, FTP 和 WebSocket 等。通过模拟大量并发用户访问来评估应用程序的表现1。 jmeter -n -t testp…

【鸿蒙HarmonyOS Next实战开发】lottie动画库

简介 lottie是一个适用于OpenHarmony和HarmonyOS的动画库&#xff0c;它可以解析Adobe After Effects软件通过Bodymovin插件导出的json格式的动画&#xff0c;并在移动设备上进行本地渲染。 下载安裝 ohpm install ohos/lottieOpenHarmony ohpm 环境配置等更多内容&#xff0c…

TensorFlow项目GPU运行 安装步骤

以下是在 Linux 系统 下搭建完整 GPU 加速环境的详细流程&#xff08;适配 CUDA 11.2 和 Python 3.9&#xff09;&#xff1a; 1. 前置检查 1.1 验证 NVIDIA 驱动 # 检查驱动版本&#xff08;需 ≥ 450.80.02&#xff09; nvidia-smi 输出示例&#xff1a; CUDA Version: 11.2…

腿足机器人之七- 逆运动学

腿足机器人之七- 逆运动学 基本概念腿部运动的数学表示坐标系定义以及自由度说明正运动学模型 逆运动学求解几何解法数值迭代法雅可比矩阵法基础双足机器人步态规划中的雅可比法应用 工程挑战与解决方案实际应用中的工具和算法多解问题高自由度机器人&#xff08;如Atlas的28自…