C中动态二维数组的获取

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情
话说这C中的动态获取二维数组好比艺术作品中的爱情(好烂的比喻~~),都是永恒而难缠的主题。假期写并行的作业,又碰到了这个问题,依然绞尽脑汁。
其实二维数组理解起来是很容易的,一维的是void *,二维自然就是void **,高维以此类推。然而多了一个和数个*好比一个“不可逾越的障壁”。不过直接申请**,初始化很难并且退回也很难。上次遇到的时候就直接malloc了一个width * height大小的区域,然后写一个取值的宏。看起来很丑陋。这次决定做个了断。搜到台湾一个技术论坛,找到了这个终极方案,真的很妙~
原帖地址:http://y120062140.win.aplus.net/pc2020v5/forum/showSameTitleN.asp?board_pc2020=c&id=34046&keyword=
原帖讨论了至少2种方案,不再赘述。最好的方案是“ma_hty(白老鼠(Gary))”的那个。程序如下:
void** malloc2d(int w, int h, int size)
{
  
int j;
  
int rowSize = w * size;
  
int indexSize = h * sizeof(void *);
  
void **= (void **) malloc(indexSize + h * rowSize);
  
char *dataStart = (char *) a + indexSize;
  
for(j = 0; j < h; j++)
    a[j] 
= dataStart + j * rowSize;
  
return a;
}

参数w,h是所申请二维数组的列数和行数,size是数组单元的字节数。比如,申请一个4*5的int型的二维数组,使用:
int **m = (int **) malloc2d(5, 5, sizeof(int));
直接使用m[x][y]即可以引用x行y列的值。
退回时,直接使用free(m)即可。
跟白老鼠开始的程序相比,改了一些地方,返值改成void **,(char *)(a + h)改成了(char *) a + h。加进了一些循环外的计算。
解释一下~就好像原帖里面cromayen2000所讲的,动态申请二维数组通常需要一个index区域和一个数据区域。index区域保存每一行数据区域的首地址,数据区域存放实际的值。m的地址是index区域的首地址。
这样,对二维数组中x行y列元素的引用m[x][y],实际上是一个两步的运算。
首先,m是一个int**的元素。m[x]是*(m + x),即index区域,第x个元素内的值,这个值就是数据区域第x行的起始地址。*(m + x)的类型是int*。
之后,寻找第y列的值。就是*(*(m + x) + y)。正好对int**进行两次解除引用。得到一个int。而写成中括号的表示法,m[x][y] === *(*(m + x) + y)。
白老鼠的函数把index和数据区域连在了一起。
       +====+
    +--+--* |〔0〕
    |  |----|
  +----+--* |〔1〕
  | |  |----|
  | |  ~    ~
  | |  |----|
+------+--* |〔h-1〕
| | |  +====+
| | |
| | |   〔0〕              〔w-1〕
| | |  +======================+
| | +->|                      |〔0〕
| |    |----------------------|
| +--->|                      |〔1〕
|      |----------------------|
|      ~                      ~
|      |----------------------|
+----->|                      |〔h-1〕
       +======================+
嗯,这个ASCII图画的真是绝妙。佩服台湾的技术人员。
首先,区域的总长度h * sizeof(void *) + h * rowSize。前一个加数就是index区域的长度。即h个void *指针的长度。后面的加数就是数据区的长度,h个rowSize。
数据区的开始也就是开始指针后移整个index区后的地址。即地址dataStart。循环把后面的数据区每一行开始地址连接到前面的index区域。
一个malloc,一个free,一个二维数组,妙哉~
这个方法要比直接栈上申请多一个index区域,思路和申请w * h大小的区域然后算出每一个元素地址根本不一样。
帖子的后面讨论了一下字节对齐的问题。白老鼠应该是藐视了字节对齐的重要性了。稍微弄一下SSE也会有感觉,字节不对齐的话会不见血的死掉的。按照这个函数,只需要保证数据区的字节对齐就可以了。方法是在index和数据区域之间加上padding。白老鼠随手写出来的程序疑似有问题。自己写了一个。
void **malloc2d(int width, int height, size_t size, int align)
{
  
// alloc all spaces: index area, largest padding area and data area
  int index_size = sizeof(void ** height;
  
int row_size = size * width;
  
void **= (void **) malloc(index_size + align + height * row_size);
  
// compute padding
  char *ptr_index_ending = (char *) p + index_size;
  
int padding = (align - ((int) ptr_index_ending + 1% align) % align;
  
// link index area and data area
  
// starting address of data area
  char *ptr_data = ptr_index_ending + 1 + padding;
  
for (int i = 0; i < height; i++)
  
{
    p[i] 
= ptr_data;
    ptr_data 
+= size * width;
  }
   return p;
}

在申请总大小的时候把最大可能的padding申请出来(就是要对齐的字节数本身),然后链接的时候,数据区的首地址根据整片区域的首地址数值(a的地址),加上index区的大小,适当后移到对齐的字节数上。
测试了一下应该是好使的,嗯。 最后还是赞一下台湾的PG们,可以看到大家的回帖里面重要的概念都附上了wiki的地址,认真劲儿很了不起啊。
 
基于C语言动态的创建二维数组,可以自动扩容并且获取每行长度 阅读详情

相关推荐

9.1【二维数组指针编程】使用指针法编程找出二维数组中最大的数

【问题描述】 现有如下的二维数组,请找出其中最大的数。 要求: 1、不在子函数中输出。 2、使用指定子函数,不得修改。 int GetMax(int *p,int m,int n) 【输入形式】 主函数中循环输入2行3列元素: 【输出形式】 输出最大值 【样例输入】 1 2 9 4 9 8 【样例输出】 max=9 【样例说明】 注意:主函数中函数调用要考虑传实参是行地址。 #include<stdio.h> int GetMax(int *p,int m,int

qq_39977056的博客 1872

题外话:谈谈malloc()和free()

http://www.nowamagic.net/librarys/veda/detail/1807   对于串的顺序存储,有些需要补充说明。串值的存储空间可在程序执行过程中动态分配而得。比如在计算机中存在一个自由存储区,叫做“堆”。这个堆可由C语言的动态分配函数malloc()和free()来管理。 那么今天就来点题外话,谈谈malloc()和free() malloc()和free()

Jensyn' blog 1541

二维数组malloc与free

特别适用于C语言动态字符串数组操作 #include &lt;stdio.h&gt; typedef unsigned int wchar; #define LENGTH 10 //需求:字符串数组二维数组动态开辟 //name[n][LENGTH]  。。。。。。。。。。 //                   。。。。。。。。。。 //                   。。。。。...

我的博客 5553

使用malloc和free创建和销毁一维数组二维数组

使用malloc和free创建和销毁一维数组二维数组 1.c语言实现 (1)一维数组: 代码实现: int *arr=(int *)malloc(sizeof(int )*10);//创建一维数组 free(arr);//释放 测试: int *arr=(int *)malloc(sizeof(int )*10); for(int i=0;i<10;i++) { arr[i] = i; printf("%d\n",arr[i]); } free(arr); 结果: (2

kyrie_sakura的博客 2916

c语言二维数组错误语法,关于c语言动态分配二维数组free的错误求dalao看看怎么回事谢谢啊~~~~...

typedef struct {int**data;int row;int col;}MyMatrix;typedef MyMatrix* Matrix;/*编写矩阵输入函数 INPUT_MAT,通过该函数完成矩阵的输入并返回保存矩阵的数组和对应矩阵的行数、列数。(不能使用全局变量)*/Matrix INPUT_MAT() {int m_row, m_col;printf("输入要创建的矩阵的行数...

weixin_28687807的博客 511

Python通过cytps调用C/C++动态获取二维数组

最近开发的Python工具有部分实现需要算法帮忙实现,找了算法同事实现了,但是因为是C++写的。只有两条路选择,要么手动改写转.py的。要么通过ctypes进行调用。为了偷懒,还是用用了后者,本篇主要记录具体实现方法,防止后面忘记这个笔记知识描述其中一种通过结构体的方法获取dll动态数组的方法,其他ctypes调用的问题。网上有很多教程。这里知识记录查不到的知识。

weixin_43153912的博客 1236

c语言动态创建二维数组的方法

#include"stdio.h" #include"string.h" #include"stdlib.h" #include"malloc.h" //动态创建二维数组方法一: typedef enum{  style_char,  style_short,  style_int }Array2Style; typedef struct{  int line;  

haohaojian的专栏 1847

c语言二维数组行和列怎么看,二维数组行列怎么看

c语言中如何获取一个二维数组的行列数?有两种方式: 1 二维数组的行列数在定义的时候就是确定好的,所以编程人员是知道二维数组的大小以及行列数的。 所以可以直接使用行列数的值。 为方便维护,可以将行列数定义为宏,直接调用对应的宏名作为行列值。 2 动态获龋 对于type array[A][从键盘输入一个数组a[3][4],统计每行每列的和。 例如: 4 5 4 5 4 2 2 3#include i...

weixin_29441555的博客 1万+

C语言 数组行列数获取

两种方法 1. 在定义数组的时候已经定义好数组的行数和列数。 2. 动态获取。 对于type array[A][B];形式的二维数组,可以通过计算sizeof获取行列数。 sizeof(array[0][0])为一个元素占用的空间, sizeof(array[0])为一行元素占用的空间, sizeof(array)为整个数组占用的空间, 于是: 行数 = sizeof(array

qq_34707315的博客 6043

C语言中的二维数组:赋值、取地址与数组大小的奥秘

首先,让我们来看看如何在C语言中声明一个二维数组二维数组其实是一个数组数组,它由多个一维数组组成。其中,type是数据类型,rows是行数,cols是列数。例如,声明一个3x3通过本文的学习,你应该对C语言中的二维数组有了更加全面的理解。二维数组赋值:可以通过静态初始化、循环赋值等方式给二维数组赋值。注意数组的维度和初始化的匹配。取二维数组的地址:二维数组名可以被视为指向第一行的指针,可以通过指针偏移访问数组元素。计算二维数组的大小:使用sizeof。

m0_62599305的博客 1007

c语言二维数组程序,C语言二维数组的程序实现.docx

C语言二维数组的程序实现template classBDArray{Type**elements; intRow,Col;voidgetArray();public:BDArray();BDArray(intm;int n);BDArray(constBDArray &A);~BDArray();int Length(inti);BDArray&operator =(constBD...

weixin_35146121的博客 333

malloc 申请二维数组

#include  #include  int main() {     int (*a)[2] = malloc(sizeof(int)*3*2);     a[0][0] =1;     a[0][1] =2;     a[1][0] =3;     a[1][1] = 4;     a[2][0] =5;     a[2][1] =

2124

二维数组动态分配内存

二维数组动态分配内存

ls3614140的博客 443

c语言用指针数组储存一串数,c语言 :如何定义一个动态指针数组,用来储存几组数字;该怎么办,又如何释放该二维数组?...

匿名用户1级2011-12-19 回答以下代码应该能够达到你的要求!另外:代码未作容错处理,即未加入对输入值正确性的判断,请自行修改。#include #include #include int main(void){int nRows, nColumns, i, j;int **ppInt = NULL;printf("请输入数组行数和列数(用空格分隔):\n");scanf("%d %d", ...

weixin_26840895的博客 231

C语言

指向数组的指针arr参与计算的时候,会退化为第一个元素的指针把多个小数组,放到一个大的数组当中结构体可以理解为在定义的数据类型它是由一批数据组合而成的结构性数据里面的每一个数据都是结构体的“成员”结构体作为函数参数,在函数中可以传递结构体组大类型的整数倍。

lujiinghe的博客 2000

看完这篇文章一定弄懂C语言数组作为函数参数的用法

C语言数组作为函数参数 文章目录一:数组元素作为函数的实参二:数组名作为函数的实参关于数组作为函数参数调用的讨论关于函数定义的参数表的讨论获取二维数组的行和列更高维数组作为函数参数同二维数组类似参考文档 一:数组元素作为函数的实参 数组元素就是变量,与普通变量没有区别,将数组元素传送给形参,实现单向的值传递。 用数组元素作实参时,只要数组类型和函数的形参变量的类型一致,那么作为下标变量的数组元素的类型也和函数形参变量的类型是一致的。 因此,并不要求函数的形参也是下标变量。换句话说,对数组元素的处理是按普通变

weixin_40162095的博客 1万+

Java——数组(一维数组二维数组

一维数组:创建,初始化,赋值 可以先创建再初始化,也可以创建的时候直接初始化。但是,如果选择先创建再初始化,就不能够整体赋值,只能一个一个赋值;如果选择创建的同时直接初始化,就可以直接整体赋值。

x18037177724的博客 861

C语言(九)

类型说明符 数组名[常量表达式1][常量表达式2];常量表达式1:表示行数;常量表达式2:表示列数。表示一个3行4列的二维整型数组,共有3 × 4 = 12个元素。本质上,二维数组是多个一维数组组成的线性结构。表示有 3 个字符串,每个字符串最多 99 个字符 + 1 个\0结束符。每行是一个字符串(自动添加\0结束符)。

2302_80202237的博客 379

二维数组中最大的一个值

#include <stdio.h> int main() { int arr[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} }; int max=0; int max_i = 0; int max_j = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { ...

weixin_58368590的博客 174
上一篇: 浅析汉字编码方式
下一篇: 关于STL容器实现,非侵入式容器+Iterator框架和“侵入式”容器实现的思考
hanbf
博客等级 码龄22年 8粉丝 9原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值