C 的二维数组

前些日子在做毕设,用的是 C 语言,当时需要用到二维数组,我不是很清楚,就上网查查二维数组的声明与函数传参的一些资料,当时做毕设急着用,就没有弄得很清楚。最近放假在家,没有事情可做,我就看了《C与指针》这本书,书中着重讲了 C 语言的指针与数组,以及指针与数组的函数传参问题。看完后,我对 C 语言的指针和数组终于有了一个比较深入的了解。这篇文章就当是这本书的读书笔记吧,当然,我不会长篇大论地写,我就着重说说 C 语言的二维数组问题(大于二维的数组的原理其实差不多,就不说了)。

首先,在这篇文章中,代码是用 GCC (Windows 平台)编译的。

说二维数组之前,我先说说 C 语言的一维数组和指针,后面的理解需要用到。我先举个一维数组的例子:

它的内存示意图如图 1 所示。

图 1 一维数组的内存示意图

图 1 一维数组的内存示意图

a 可以看作指针常量,指向这个一维数组的第一个元素,看作数组变量时,代表整个数组。

上面代码的输出为:

可以看出,a 和 &a[0] 的值是一样的,这就表示,a 确实是指向数组第一个元素,是一个指针常量。另外,这其中 &a 的值也和 a 的值相同,但 &a 是把整个数组当作一个整体来看,是取整个数组的地址。所以,&a + 1 的值和 &a[1] 的值不同,&a + 1 是向后偏移了整个数组,然后求地址,&a[1] 是向后偏移了一个数组元素,然后求地址。

我再举个指针的例子:

它的内存示意图如图 2 所示

图 2 指针的内存示意图

图 2 指针的内存示意图

这个例子就是常用的动态数组的声明,a 是一个指针变量,它有自己的存储地址,它里面的值(a 所指向的地址)是动态数组第一个元素的地址。

上面代码的输出(每次结果可能不一样)为:

可以看出,a 的存储地址和数组首地址(a 所指向的地址,也就是 a 变量所存储的值)是不一样的。

现在开始说 C 语言的二维数组,首先是第一种声明方法,如下所示:

以上声明了一个二行五列(也可以叫作五行二列)的二维数组,a 当作指针常量时,指向一维数组 a[0],当作数组变量时,代表整个二维数组。a 在内存中的示意图如图 3 所示。

二维数组

图 3 二维数组的内存示意图

 

可以看出,这种二维数组在内存中是按照右边的下标先增加的顺序排列的。

上面代码的输出:

a 是一维数组 a[0] 的地址,和 &a[0] 相同,&a 是求整个二维数组的地址,&a[0][0] 是求一维数组 a[0] 首元素的地址。a + 1 显然是求一维数组 a[1] 的地址,和 &a[0] + 1,以及 &a[1] 相同,而 &a + 1 是向后偏移了整个二维数组,&a[0][1] 是求一维数组 a[0] 第二个元素的地址,只向后偏移了一个数组元素。

第二种声明方法,用的是指向指针的指针,如下所示:

它在内存中的示意图如图 4 所示。

图 4 指向指针的指针的内存示意图

图 4 指向指针的指针的内存示意图

上面是动态声明了一个二行五列(也可以叫作五行二列)的二维数组,更严谨的说,是声明了一个可以当作二行五列(也可以叫作五行二列)的二维数组使用的指向指针的指针。

以上代码的输出(每次结果可能不一样):

可以看出,a 的值是一维数组 a[0] 的地址,这和 a 自己的存储地址以及数组的首元素 a[0][0] 的地址是不一样的。

说完了二维数组的声明,我想再说说二维数组的函数传参问题。

第一种声明方法如果如下面来传参:

上面的代码编译是无法通过的,编译器的错误消息为:error: array type has incomplete element type。使用这种声明方法,C 语言在寻址时,比如说 a[1][2],是按照 &a[0][0] + (1 * 5  + 2) * sizeof(int),也就是必须要知道第二维的长度,才能寻址。上面的代码需要修改,才能通过编译,如下所示:

第二种声明方法正确传参方法如下:

传入函数的是 a 的值,a[i][j] 在寻址时,方法为:*(a + i) + j,这样是不需要第二维的长度的。

最后,本文是对 C 的二维数组做了一个相对完整的介绍,若想要更加详细了解 C 语言的数组和指针,我推荐看看《C与指针》这本书。

One thought on “C 的二维数组

  1. Pingback: WordPress 代码高亮插件 | peterchou139's Blog

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">