`
nathan09
  • 浏览: 144800 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

在C语言中实现动态分配二维数组

 
阅读更多
在C语言中动态的一维数组是通过malloc动态分配空间来实现的,动态的二维数组也可以通过malloc动态分配空间来实现。

  实际上,C语言中没有二维数组,至少对二维数组没有直接的支持,取而代之的是“数组的数组”,二维数组可以看成是由指向数组的指针构成的数组。对于一个二维数组p[i][j],编译器通过公式*(*(p+i)+j)求出数组元素的值:

  1、p+i 计算行指针。

  2、*(P+i) 具体的行,是一个指针,指向该行首元素地址。

  3、*(P+i)+j 得到具体元素的地址。

  4、*(*(p+i)+j) 得到元素的值。

  基于上述原理,我们可以通过分配一个指针数组,再对指针数组的每一个元素分配空间实现动态分配二维数组。

  实现

  下面是本人写的一个动态分配二维数组的实现,适用于任何类型的二维数组,可以直接使用。

  类型定义和错误代码

typedef unsigned char MK_Byte;

#define SUCCESS 0 /*No error*/
#define MFAILED 1 /*General failure*/
#define MNOMEMORY 2 /*Out of memory*/

声明

//确保初始化
#define DeclareTwoDArray(ATYPE, iname) ATYPE ** iname = NULL

//定义自己的malloc和free,确保内存正确操作
#define MKMALLOC(nsize) malloc(nsize)
#define MKFREE(name) /
if (NULL != name)/
free(name);/
name = NULL

  实现

int MKCreatArray(int nsize, int X, int Y, void *** parray)
{
 void ** tdarray = NULL;
 MK_Byte * tmparray = NULL;
 int i = 0;

 *parray = NULL;

 //分配指针数组
 if (!(tdarray = (void **)MKMALLOC(sizeof(MK_Byte *) * Y))) {
  return MNOMEMORY;
 }
 //分配实际数组空间
 if (!(tmparray = (MK_Byte * )MKMALLOC(nsize * (X * Y)))) {
  MKFREE(tdarray);
  return MNOMEMORY;
 }

 //初始化内存
 memset(tmparray, 0x00, nsize * (X * Y));

 //指针数组赋值
 for (i = 0; i < Y; i++)
  tdarray[i] = (tmparray + (i * X) * nsize);

 *parray = tdarray;
 return SUCCESS;
}

void MKFreeArray(void *** parray)
{
 if (*parray) {
  MKFREE((*parray)[0]);
  MKFREE((*parray));
 }
}

  使用

void testTwoDArray()
{
 //声明数组
 DeclareTwoDArray(int, a);
 DeclareTwoDArray(float,b);

 //创建整型数组
 MKCreatArray(sizeof(int), 3, 2, &a);
 a[1][2] = 10;
 a[0][1] = 23;
 printf("%d,%d/n",a[1][2],a[0][1]);
 //使用完一定要FREE
 MKFreeArray(&a);

 //重新分配数组
 MKCreatArray(sizeof(int), 6, 6, &a);
 a[5][5] = 234;
 a[4][0] = 567;
 printf("%d,%d/n",a[5][5],a[4][0]);
 MKFreeArray(&a);

 //创建浮点数组
 MKCreatArray(sizeof(float),2,2,&b);
 b[0][0] = 0.5f;
 b[1][1] = 0.006f;
 printf("%g,%g/n",b[0][0],b[1][1]);
 MKFreeArray(&b);
}



 ----------------------------------------------------------------------

其他讨论:

摘自:动态二维数组如何定义?


我在程序中需要使用一个动态的二维数组,行和列的值都需要传入。我在程序中使用了如下的方法:
#include "malloc.h"
...
double *t,**y;
t=(double *)calloc(r*c,sizeof(double)); //r,c是传入的行和列的值
y=(double **)calloc(r,sizeof(double *));
for(int i=0;i<r;i++) y[i]=&t[c*i];
...
结果在编译时没有问题,但运行时就回产生一个内存使用错误。
希望大家能够帮忙解决一下,或者有其他的解决方法也可以。谢谢!
---------------------------------------------------------------

可以这样使用二维数组:

假设前面已经定义了r行 和 c列

/*指向座标为(x,y)的单元的指针*/
#define M_pV(pHead, x, y) (pHead+c*y+x)

double *pArray=(double*)malloc(r*c*sizeof(double));

到时候可以这样用:
*M_pV(pArray, 1, 2)=9;
double temp=*M_pV(pArray, 1, 2);
---------------------------------------------------------------

用MFC的CArray模板为例,你也可以使用STL的vector等
做一个2维的动态int数组

typedef CArray<int,int> INTARRAY;
typedef CArray<INTARRAY,INTARRAY> Int2DArray;
---------------------------------------------------------------

一个二维数组,其实可以用一个一维指针来访问的。
如:int iMatrix[10][10];
int *piMatrix;
piMatrix = iMatrix; //数组名就是数组首地址
那么就有 *piMatrix[2*10+3] = iMatrix[2][3]
所以定义一个一维指针就可以了
int piMatrix;
piMatrix = (int*)malloc(r*c*sizeof(int));
for (i=0;i<r;i++)
for(j=0;j<c;j++)
piMatrix[i*r+j]
(当然,也可以定义一个2维数组,跟Kevin_qing()一样)

--------------------------------

摘自:动态分配二维数组的若干方法


动态分配二维数组的若干方法

  动态分配二维数组,方法很多,在这里我说一下我想到的。针对二维数组两
个维的不同,可用不同的方法处理。

一、两维都固定:

  这种是最简单,如下:

// 有点困惑的方法:
int (*a)[M][N]; // M、N 为常量
a = new int[1][10][20]; // 为什么要这样呢?
delete[] a;

// typedef 法,但一样的困惑
typedef int array_two[10][20];
array_two* a = new array_two[1]; // 还是多了“一维”
delete[] a;

  唉,这个有点失败,使用时还要这样:(*a)[m][n],或者 a[0][m][n],这
还是二维的吗?没办法,只有另想办法了。

// 退一步,声明似乎少了一维 TYPE_1
int (*a)[N];
a = new int[M][N];
a[var_m][var_n] = 0;
delete[] a;

  这样似乎不错,只是在声明时却少了一维,但使用起来简单,形式一样。

二、只有一维固定:

  如果只有一维固定,分两种形式:[M][n] 和 [m][N],以后者较简单。对于
N 固定的,我们只要这样就可以了:

// [m][N] 型 TYPE_2
int (*a)[N];
a = new int[m][N];
a[var_m][var_n] = 0;
delete[] a;

  这个看起来与 TYPE_1 很相似,比较二维数组作为函数的参数传递时,第一
维也是不重要的。看一下 new,出来的类型都是 int (*)[N]。

  对于 [M][n] 这种,能过把下标交换一下,就可以利用 TYPE_2 这种了,确
实是不错。如果坚持用 [M][n] 的话,看一下有什么方法。

// [M][n] 型,直接的方法 TYPE_3
int* a[M];
for (int i = 0; i < M; ++i)
a[i] = new int[n];
a[var_m][var_n] = 0;
for (int i = M; i > 0;)
delete[] a[--i];

  事实上,我们可以改进一下,只用一次 new:

// [M][n] 型,改进 TYPE_4
int* a[M];
a[0] = new int[M*n];
for (int i = 1; i < M; ++i)
a[i] = a[i-1] + n;
a[var_m][var_n];
delete[] a[0];

  这样改进的好处是,减少 new 所带来的固有开销;如果失败,无需对前面
已分配的再 delete[]。当然,如果内存比较碎的话,那就没办法了。

三、二维都是动态确定:

  二维都是动态确定的话,可以这样:

// [m][n],直接的方法 TYPE_5
int** a;
a = new (int*)[m];
for (int i = 0; i < m; ++i)
a[i] = new int[n];
a[var_m][var_n] = 0;
for (int i = m; i > 0;)
delete[] a[--i];
delete[] a;

  类似改进 TYPE_3,我们也可以将 TYPE_5 改进:

// [m][n],改进 TYPE_6
int** a;
a = new (int*)[m];
a[0] = new int[m*n];
for (int i = 1; i < m; ++i)
a[i] = a[i-1] + n;
a[var_m][var_n] = 0;
delete[] a[0];
delete[] a;

  好了,这就是我所想到的办法,当然你可以 std::vector 来搭建二维数组,
只是效率似乎没人满意。实际上,可以只分两种情况:最后一维确定,或不确定。
最后一维确定,只需一次分配;否则,一般要两次。
---------------------------------------------------------------

// [M][n] 型,改进 TYPE_4
int* a[M];
a[0] = new int[M*n];
for (int i = 1; i < M; ++i)
a[i] = a[i-1] + n;
a[var_m][var_n];
delete[] a[0];
这里似乎有些问题,是不是应该改成a[i] = a[i-1] + sizeof(int)*n;
---------------------------------------------------------------

有价值。
up
---------------------------------------------------------------

up
---------------------------------------------------------------

int (*a)[M][N]; // M、N 为常量
a = new int[1][10][20]; // 为什么要这样呢?

这里的a不应该是一个三维数组吗?不知道是楼主弄错了还是我理解得不对?
另外,用vector来构建二维数组我觉得没有什么不好,不知道为什么楼主认为效率不令人满意?
---------------------------------------------------------------

楼上的意见我认可
*a[][]逻辑上已经是三维了

至于你的typedef int array_two[10][20];
array_two* a = new array_two[1]; // 还是多了“一维”
这样定义了 array_two本身是二维数组,定义它的指针也应该是首先分配的是二维数组指针的空间

typedef 定义对象指针
有一个好处就是new的时候不会调用构造函数

class Object{...
}

typedef Object* OFun[1];
OFun = new Object[1];
---------------------------------------------------------------

学习...
---------------------------------------------------------------

mark
---------------------------------------------------------------

int (*a)[M][N]; // M、N 为常量
a = new int[1][10][20]; // 为什么要这样呢?

逻辑上是三维了,感觉就是用起来会方便一点吧,是作为指针来用了,作为一个二维指针,不过自己还没用到过这么困难的东西,看了是不少书,理论也不少了,可还是没实践,学习,
---------------------------------------------------------------

还有,我最推荐的是TYPE_5,这个东西可以搭建的就不只是m*n的数组了,而是一堆大小不同的一维数组的集合

------------------------------

摘自:动态申请二维数组


// allocate memory
p = (int**)malloc(row_x * sizeof(int*));
for (i=0; i<row_x; i++)
{
p[i] = (int*)malloc(row_y * sizeof(int));
}

// use them
for (i=0; i<row_x; i++)
for (j=0; j<row_y; j++)
p[i][j] = i+j;

// free allocated memory
for (i=0; i<row_x; i++)
{
free(p[i]);
}
free(p);

分享到:
评论

相关推荐

    C语言动态分配二维数组

    C语言动态分配二维数组,对数组动态分配进行详细描述

    C语言中动态分配二维数组.doc

    C语言中动态分配二维数组.doc

    C语言 二维数组 malloc 矩阵加法 乘法 转置

    C语言 实在 矩阵的乘法 加法 转置 各个子涵数都有通用性,内存的分配是使用二维数组动态 malloc 分配

    C指针系列之动态申请二维数组

    使用C的二级指针动态分配二维数组,在linux和vs2010下均编译通过。

    c语言动态数组的实现方法

    该项目利用c语言的malloc函数实现了一维和二维动态数组的创建,并且二维数组采用了两种方式。该项目对了解程序的内存分配具有很好的益处。

    关于c语言二维数组初始化

    C语言中的二维数组初始化可以通过以下几种方式实现: 使用花括号进行初始化:在定义二维数组时,直接使用花括号将每个元素赋值 使用循环进行初始化:通过嵌套循环遍历二维数组的每个元素,并为其赋值 使用动态内存...

    基于visual Studio2013解决C语言竞赛题之0510求最大和

    有一个二维数组整型数组中,每一行都有一个最大值,编程求出这些最大值以及它们的和

    八十多条C语言基础教程

    (28)二维数组的初始化 (29)二维数组与指针 (30)二维数组应用实例 (31)二维数组应用实例(2) (32)用一维数组来存储字符串 (33)字符串的输入与输出 (34)字符串数组 (35)用于字符串处理的函数 (36)字符串应用实例 (37)传...

    C语言中多维数组的内存分配和释放(malloc与free)的方法

    如果要给二维数组(m*n)分配空间,代码可以写成下面: 代码如下:char **a, i; // 先分配m个指针单元,注意是指针单元 // 所以每个单元的大小是sizeof(char *) a = (char **) malloc(m * sizeof(char * )); // 再分配n...

    谭浩强C语言设计第三版.pdf

     5.3.3 向函数传送二维数组  5.3.4 多维数组  习题五 第6章 指针  6.1 指针基础  6.1.1 地址与指针  6.1.2 指针变量及其定义  6.1.3指针变量的引用  6.1.4 指针的移动与比较  6.1.5 指向指针变量的指针与...

    C语言程序设计(PDF格式)

    5.2.1 二维数组的一般形式 80 5.2.2 字符串数组 84 5.3 多维数组 85 5.4 数组的初始化 85 5.4.1 数组初始化 85 5.4.2 变长数组的初始化 86 5.5 应用程序举例 87 第6章 指针 91 6.1 指针与指针变量 91 6.2 指针变量的...

    C语言程序设计(高清PDF)

    5.2.1 二维数组的一般形式 80 5.2.2 字符串数组 84 5.3 多维数组 85 5.4 数组的初始化 85 5.4.1 数组初始化 85 5.4.2 变长数组的初始化 86 5.5 应用程序举例 87 第6章 指针 91 6.1 指针与指针变量 91 6.2 指针变量的...

    谭浩强c语言程序设计

    4.3 数据输入输出的概念及在C语言中的实现 54 4.4 字符数据的输入输出 54 4.4.1 putchar 函数(字符输出函数) 54 4.4.2 getchar函数(键盘输入函数) 55 4.5 格式输入与输出 55 4.5.1 printf函数(格式输出函数) ...

    谭浩强 C语言程序设计 教程全书 Word版

    4.3 数据输入输出的概念及在C语言中的实现 4 4.4 字符数据的输入输出 4 4.4.1 putchar 函数(字符输出函数) 4 4.4.2 getchar函数(键盘输入函数) 5 4.5 格式输入与输出 5 4.5.1 printf函数(格式输出函数) 5 ...

    c语言经典源码例子100篇

    实例20 二维数组 实例21 字符数组 // 实例22 数组初始化 // 实例23 数组应用 实例24 函数的值调用 实例25 函数的引用调用 //swap 实例26 数组函数的调用 // 实例27 命令行变元 // 实例28 函数的返回值 实例29 函数的...

    《C语言程序设计》-PDF格式

    5.2.1 二维数组的一般形式 80 5.2.2 字符串数组 84 5.3 多维数组 85 5.4 数组的初始化 85 5.4.1 数组初始化 85 5.4.2 变长数组的初始化 86 5.5 应用程序举例 87 第6章 指针 91 6.1 指针与指针变量 91 6.2 指针变量的...

    C语言程序设计(谭浩强)第三版

     6.2.2怎样引用二维数组的元素  6.2.3二维数组的初始化  6.2.4二维数组程序举例  6.3.字符数组 6.3.1怎样定义字符数组  6.3.2字符数组的初始化  6.3.3怎样引用字符数组中的元素  6.3.4字符串和字符串结束标志...

    谭浩强版c语言程序设计

    4.3 数据输入输出的概念及在C语言中的实现 54 4.4 字符数据的输入输出 54 4.4.1 putchar 函数(字符输出函数) 54 4.4.2 getchar函数(键盘输入函数) 55 4.5 格式输入与输出 55 4.5.1 printf函数(格式输出函数) ...

    《C语言程序设计》谭浩强

    4.3 数据输入输出的概念及在C语言中的实现 54 4.4 字符数据的输入输出 54 4.4.1 putchar 函数(字符输出函数) 54 4.4.2 getchar函数(键盘输入函数) 55 4.5 格式输入与输出 55 4.5.1 printf函数(格式输出函数) ...

Global site tag (gtag.js) - Google Analytics