二维数组与指针

来源:互联网 发布:知无涯者经典语录 编辑:程序博客网 时间:2024/04/27 19:36

一、实现一个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竟然指向了我们想要指向的数组内容空间,我表示很不理解,看来我要学的东西还很多啊!

原创粉丝点击