现在的位置: 首页 > 综合 > 正文

二维数组与指针

2013年05月13日 ⁄ 综合 ⁄ 共 2862字 ⁄ 字号 评论关闭

一、实现一个display函数,能够打印输出数组中的元素

输入:指向数组第一个元素的指针,数组的行数及列数

输出:无

该函数灵活之处在于我们可以对任意行任意列的数组进行打印,而不需要固定行数或列数;

我们知道二维数组在函数参数传递的过程中,是需要确定列数的,该函数不需要固定列数。

#include <stdio.h>

/*
**Function:display each element in an array
**Input:a pointer of the first element and the array's row and col
**Output:void
*/
void display(int *p, int row, int col)
{
	int i,j;
	for(i = 0; i < row; i ++)
	{
		for(j = 0; j <col; j ++)
		{
			printf("%3d", *(p+col*i+j));//通过*(p+col*i+j)来表示array[i][j]
		}
		printf("\n");
	}
}


int main()
{
	int array[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
	display(&array[0][0],3,4);//通过&array[0][0]这种方式来传递指针
	display((int *)array,3,4);//也可以将数组名(指向一维数组的指针)转换为(int *)型的指针进行传递

	return 0;
}

上述函数的确能够实现我们的功能,但是可能存在这样一个问题:如果该函数不是要打印数组,而是需要用数组进行大量计算,那么势必就会多次引用array[i][j],但是就目前来看,我们只能用*(p+col*i+j)来表示array[i][j],可能我们会觉得很不方便和习惯,那么有没有办法能够在该函数内部直接引用array[i][j]呢?

下面的代码就可以实现。

实现的原理:

动态申请row个指针空间,并用一个指向指针的指针int **array来指向这个指针空间的首地址,这样array[i]就表示动态申请到的第i个指针;

为申请到的第各个指针赋值,令其分别指向二维数组每行首个元素,这样就ok啦。

记得用完后要将动态申请到的指针空间释放。

代码如下:

#include <stdio.h>
#include <stdlib.h>

/*
**Function:display each element in an array
**Input:a pointer of the first element and the array's row and col
**Output:void
*/
void display(int *p, int row, int col)
{
	int i,j;
	int **array = (int **)malloc(sizeof(void *) * row);//在申请row个指针空间,用来存放不同数组中各行的起始位置

	for(i = 0; i < row; i ++)
	{
		array[i] = p + i * col;//array[i]表示动态申请到的第i个指针,它指向数组第i行的起始位置
	}

	for(i = 0; i < row; i ++)
	{
		for(j = 0; j <col; j ++)
		{
			//printf("%3d", *(p+col*i+j));//通过*(p+col*i+j)来表示array[i][j]
			printf("%3d", array[i][j]);//这样就可以方便地通过索引来引入数组元素
		}
		printf("\n");
	}

	free(array);//记得要释放动态申请到的内存
}

二、动态申请二维数组的问题

我们可能经常会碰到需要动态申请二维数组的问题,申请空间并不难,只需要调用malloc函数,指定要申请的内存大小就可以了,关键是如何引用数组元素呢?最简单的申请方法如下:以申请int array[row][col]为例

int *array = (int *)malloc(sizeof(int) * row * col);
//array[i][j] = array[i * col + j]
//array[i][j] = *(array + i * col + j)

可以看到,这样做申请的时候很简单,但是使用的时候会比较麻烦,我们不能方便地通过我们最习惯的array[i][j]来引用,而必须采用注释中描述的两种方式来引用。

通过前面display函数的例子我们就可以知道,其实我们可以将这种比较不方便的引用转化为我们习惯的引用,这个转化的过程需要动态地申请row个指针空间,我们可以将这个转化过程作为一个函数来进行调用,或者我们可以写一个专门动态申请二维数组的函数,这样我们申请内存是调用此函数,那么在使用过程中就能比较方便地引用了。

void **malloc_array(int row, int col, int size)
{
	void ** array = NULL;
	int i;
	int pointSize;

	pointSize = row * sizeof(void *);		//需要额外申请的row个指针空间的内存大小
	array = (void **)malloc(pointSize + size * row * col);//申请内存空间(row个指针空间 + 数组元素空间)
	for(i = 0; i < row; i ++)
	{
		array[i] = array + pointSize + col * i;//为row个指针赋值,指向数组各行的起始位置
	}

	return array;
}

int **a = (int **)malloc_array(2,3,sizeof(int));//可以直接使用a[i][j]

这样也会存在一些其它的问题,比如说刚才我们写的display方法,它能够输出数组中的元素,且不需指定数组的列数,但是那个函数现在却不能用来输出我们动态申请到的这个二维数组,要想输出我们动态申请的二维数组,直接使用

void display2(int **p, int row, int col)
{
	int i,j;

	for(i = 0; i < row; i ++)
	{
		for(j = 0; j <col; j ++)
		{
			printf("%3d", p[i][j]);
		}
		printf("\n");
	}
}

函数的调用方法如下:

int **a = (int **)malloc_array(2,3,sizeof(int));
display2(a,2,3);

 

这似乎也让问题变复杂了,我们需要记忆到底何时该调用哪个方法。这个到底如何使用这些方法,还是要看具体的问题了。

这里还有一点需要注意:malloc_array方法中利用malloc申请内存的代码申请到的内存竟然是不连续的,我就不懂是为何了:

array = (void **)malloc(pointSize + size * row * col);//申请内存空间(row个指针空间 + 数组元素空间)

申请到的内存空间分成两部分,pointSize个字节是连续的,而size * row * col个字节也是连续的,8个字节+24个字节(调用此方法申请int array[2][3]),

更神奇的是array + pointSize竟然指向了我们想要指向的数组内容空间,我表示很不理解,看来我要学的东西还很多啊!

抱歉!评论已关闭.