尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

动态数组

动态数组
📅 发布时间:2026/6/18 0:20:14

** p 相当于一个指向指针的指针

比如我去创建一个 int 数组,用

#include <stdio.h>int main() {int *p=(int *)malloc(4*sizeof(int));for(int i=0;i<4;i++) p[i]=i+1;for(int i=0;i<4;i++) printf("%d ",p[i]);return 0;
}

那我开一个都是指针的数组,比如说一个行指针数组,里面存放着二维数组的行指针。那么,此时,指向指针的指针,相当于把数组元素换成 int * 了,那么你自然的指向这个数组就要多带一个 *。

#include <stdio.h>int main() {int **p=(int **)malloc(4*sizeof(int*));int tot=1;for(int i=0;i<4;i++) {p[i]=(int *)malloc(4*sizeof(int)); //p[i] 为一个指针,指向的应该是这一行第一个元素的地址 for(int j=0;j<4;j++) p[i][j]=++tot;}for(int i=0;i<4;i++) {for(int j=0;j<4;j++) printf("%d ",p[i][j]);printf("\n");}return 0;
}

动态二维数组作为参数详解

一、为什么需要动态二维数组?

在讲解具体用法前,我们先理解为什么需要动态二维数组。静态数组在编译时就必须确定大小,但很多实际场景中,数组大小需要在运行时才能确定:

// 静态数组 - 大小固定
int static_matrix[10][20]; // 只能处理10×20的矩阵// 但实际需求可能是:
int rows, cols;
printf("请输入矩阵的行数和列数: ");
scanf("%d %d", &rows, &cols); // 用户输入决定大小

这时候就需要动态二维数组来解决这个问题。

二、动态二维数组的内存模型

理解动态二维数组的关键是要明白它的内存布局与静态二维数组不同:

静态二维数组(连续存储)
┌───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ ← 所有元素连续存储
└───┴───┴───┴───┴───┴───┘
matrix[0]    matrix[1]动态二维数组(非连续存储)
┌───────┐    ┌───┬───┬───┐
│ 地址1 │───→│ 1 │ 2 │ 3 │ ← 第0行
└───────┘    └───┴───┴───┘
┌───────┐    ┌───┬───┬───┐
│ 地址2 │───→│ 4 │ 5 │ 6 │ ← 第1行
└───────┘    └───┴───┴───┘
┌───────┐    ┌───┬───┬───┐
│ 地址3 │───→│ 7 │ 8 │ 9 │ ← 第2行
└───────┘    └───┴───┴───┘

关键区别:动态二维数组的每一行都是独立分配的内存块,可能不连续!

三、创建动态二维数组的完整流程

3.1 分步创建过程

#include <stdio.h>
#include <stdlib.h>int main() {int rows, cols;// 步骤1:获取矩阵大小printf("请输入矩阵的行数和列数: ");scanf("%d %d", &rows, &cols);// 步骤2:创建"行指针数组"int **matrix = (int**)malloc(rows * sizeof(int*));if (matrix == NULL) {printf("内存分配失败!\n");return -1;}// 步骤3:为每一行分配内存for (int i = 0; i < rows; i++) {matrix[i] = (int*)malloc(cols * sizeof(int));if (matrix[i] == NULL) {printf("第%d行内存分配失败!\n", i);// 需要释放之前已分配的内存for (int j = 0; j < i; j++) {free(matrix[j]);}free(matrix);return -1;}}// 步骤4:使用矩阵printf("动态二维数组创建成功!大小: %d×%d\n", rows, cols);// 步骤5:释放内存(重要!)for (int i = 0; i < rows; i++) {free(matrix[i]);  // 先释放每一行}free(matrix);         // 再释放行指针数组return 0;
}

四、动态二维数组作为函数参数

4.1 函数声明和定义

由于动态二维数组实际上是"指针的指针",所以函数参数应该使用 int ** 类型:

#include <stdio.h>
#include <stdlib.h>// 函数声明:动态二维数组作为参数
void initialize_matrix(int **matrix, int rows, int cols);
void print_matrix(int **matrix, int rows, int cols);
void free_matrix(int **matrix, int rows);// 创建动态二维数组的函数
int** create_matrix(int rows, int cols) {int **matrix = (int**)malloc(rows * sizeof(int*));if (matrix == NULL) return NULL;for (int i = 0; i < rows; i++) {matrix[i] = (int*)malloc(cols * sizeof(int));if (matrix[i] == NULL) {// 分配失败,清理已分配的内存for (int j = 0; j < i; j++) {free(matrix[j]);}free(matrix);return NULL;}}return matrix;
}// 初始化矩阵
void initialize_matrix(int **matrix, int rows, int cols) {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {matrix[i][j] = i * cols + j + 1; // 填充数据}}
}// 打印矩阵
void print_matrix(int **matrix, int rows, int cols) {printf("矩阵内容:\n");for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {printf("%4d", matrix[i][j]);}printf("\n");}
}// 释放矩阵内存
void free_matrix(int **matrix, int rows) {for (int i = 0; i < rows; i++) {free(matrix[i]);}free(matrix);
}int main() {int rows = 3, cols = 4;// 创建动态二维数组int **my_matrix = create_matrix(rows, cols);if (my_matrix == NULL) {printf("创建矩阵失败!\n");return -1;}// 使用函数操作矩阵initialize_matrix(my_matrix, rows, cols);print_matrix(my_matrix, rows, cols);// 释放内存free_matrix(my_matrix, rows);return 0;
}

五、理解 int **matrix 的含义

这是最让人困惑的部分,我们来拆解理解:

int **matrix;  // 这是什么?// 分解理解:
// 1. matrix 是一个指针,指向什么?
// 2. 它指向的是 int* 类型(整数指针)
// 3. 所以 matrix 是"指向整数指针的指针"// 实际内存布局:
matrix → [指针0] → [整数00, 整数01, 整数02...]  // 第0行[指针1] → [整数10, 整数11, 整数12...]  // 第1行  [指针2] → [整数20, 整数21, 整数22...]  // 第2行

访问元素的各种等价写法:

matrix[i][j]        // 最直观的写法
*(matrix[i] + j)    // 先取第i行指针,再偏移j个元素
*(*(matrix + i) + j) // 完全用指针运算

六、完整实战示例:矩阵运算

#include <stdio.h>
#include <stdlib.h>// 矩阵相加:C = A + B
int matrix_add(int **A, int **B, int **C, int rows, int cols) {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {C[i][j] = A[i][j] + B[i][j];}}return 0;
}// 矩阵转置
int matrix_transpose(int **src, int **dst, int rows, int cols) {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {dst[j][i] = src[i][j];  // 行列互换}}return 0;
}int main() {int rows = 2, cols = 3;// 创建三个矩阵int **A = create_matrix(rows, cols);int **B = create_matrix(rows, cols); int **C = create_matrix(rows, cols);int **T = create_matrix(cols, rows);  // 转置矩阵大小互换// 初始化A, Binitialize_matrix(A, rows, cols);initialize_matrix(B, rows, cols);// 矩阵相加matrix_add(A, B, C, rows, cols);printf("矩阵A:\n");print_matrix(A, rows, cols);printf("矩阵B:\n"); print_matrix(B, rows, cols);printf("矩阵C = A + B:\n");print_matrix(C, rows, cols);// 矩阵转置matrix_transpose(A, T, rows, cols);printf("A的转置矩阵:\n");print_matrix(T, cols, rows);// 释放所有内存free_matrix(A, rows);free_matrix(B, rows);free_matrix(C, rows); free_matrix(T, cols);return 0;
}

七、常见错误与调试技巧

7.1 内存泄漏检测

// 错误示例:只释放了部分内存
void wrong_free(int **matrix, int rows) {free(matrix); // 只释放了行指针数组,没释放每一行!// 应该先释放所有 matrix[i],再释放 matrix
}// 正确做法:按分配顺序逆序释放
void correct_free(int **matrix, int rows) {for (int i = 0; i < rows; i++) {free(matrix[i]);  // 释放每一行}free(matrix);         // 释放行指针数组
}

7.2 边界检查

void safe_access(int **matrix, int rows, int cols, int i, int j) {if (i < 0 || i >= rows || j < 0 || j >= cols) {printf("索引越界: (%d, %d)\n", i, j);return;}printf("matrix[%d][%d] = %d\n", i, j, matrix[i][j]);
}

八、总结

动态二维数组作为参数的核心要点:

  1. 理解 int ** 类型:这是"指针的指针",指向一个指针数组
  2. 内存非连续:每一行独立分配,可能不连续存储
  3. 必须传递行列参数:函数内无法自动获取大小信息
  4. 严格的内存管理:分配时检查返回值,释放时按正确顺序
  5. 灵活的尺寸:可以创建不规则二维数组(每行长度不同)

通过这种理解,你就能熟练使用动态二维数组来解决各种复杂的编程问题了!

相关新闻

  • 【Linux进阶系列】:线程(上) - 详解
  • Solon AI 开发学习8 - chat - Vision(理解)图片、声音、视频
  • Python全栈项目:基于Django的电子商务平台编写

最新新闻

  • 2026福田区搬家公司Top5榜单:服务范围全街道,适配本地人强推正规搬运公司 - 从来都是英雄出少年
  • 联邦学习如何重构心理App的临床可信度
  • 5步实战OpenCore Legacy Patcher:让老旧Mac焕发新生的完整指南
  • 终极ESP-Drone开源飞控教程:从零构建你的第一架智能无人机
  • 学充电桩维修有前途吗 - 湖南阳光技术
  • MC68VZ328 BGA焊接可靠性:为何官方推荐HASL而非ENIG表面处理?

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号