在学C语言的时候,每次遇到二维数组,都特别头疼,并不是它难用,而是我搞不清楚它的数组名代表的是什么。但我们知道:当我们定义一个一位数组的时候,它的数组名就是第一个元素的地址,也就是,下面的语句是等价的:
int a[3]={1,2,3}; printf ("%d/n",a); printf ("%d/n",&a[0]);
他们将会输出相同的值,而且更重要的是,他们的 意义 是一样的。 因为在数组访问成员的过程中,它是完全转化成指针的形式来间接访问的,也就是:
a[i]等价于*(a+i) &a[i]等价于(a+i)
也就是根据这种思想,我们来看看二位数组:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; printf ("%u/n",a); //地址我们使用%u来输出,防止地址过大。 printf ("%u/n",a[0]); printf ("%u/n",&a[0]);
在一个二位数组中,上面输出结果的数值是一样,但,仅仅是数值一样而已,他们的意义是大不一样的。那么,上面的二维数组名到底和谁等价呢? 答案是&a[0];//行地址
其实,C语言并没有二维数组,但C语言有一维数组,那么,要模仿出N维数组,也就不是难事了。所以,二维数组只是数组的数组,只不过数组的没一个元素也是一个数组罢了。
那么就是,每一个元素a[i]代表的就是一个数组,那我们用一维数组来理解,就不是难事了。上面说过,在一维数组中,数组名和第一个元素的首地址是等价的就是a <-->&a[0];(一维数组)。
那么,我们的数组的数组(二维数组),每一个元素都是一个数组,
所以a[0] <--> &a[0][0];//这里代表的是列地址,后面会区分列地址和行地址的区别
所以 a <--> &a[0];//这里代表的是行地址
到了这里,我们已经知道了二维数组的数组名的含义,和它与那个等价。那么,我们现在看看行地址和列地址的区别。
其实,在上面二维数组的代码中,输出的结果是一样的,但是,他们的含义是大相径庭的。含义不同?区别在哪里呢?区别就是:在指针的移动中。
我们知道,在指针的移动是以数据类型所占字节大小为单位进行移动的。两个指针所指向的地址可能相同,但他们的单位却很可能不同。
int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; printf ("%u/n",b+1);//+16 printf ("%u/n",b[0]+1);//+4 printf ("%u/n",&b[0]+1);//+16
可以看到,同样是加一,但是指针移动的距离却很是不同(本人觉得这点很重要)。这是因为,b和&b[0]是等价的,而且,他们代表的是行地址,也就是,每次移动1个单位,就移动一行的距离。
而b[0]等价于&b[0][0],代表的是列地址,每次移动,只移动sizeof(b[0][0])个字节,就是一个元素所占的字节,这就是它们含义不同的一个区别。
在我以前用memset函数的时候,最怕要用到二维数组, 我真的不知道是传入a,a[0],&a[0],还是&a[0][0]。我们知道,他们的值是一样的,只是代表的含义不一样,我们需要传入哪一个呢?其实,那个都行,这已经不是二维数组的知识了,这关乎到void *指针和memset函数内部处理的方式,
void *memset( void *dest, int c, size_t count ); //memset函数的声明
void *指针,代表的一个地址,仅仅是一个地址,我们不考据他们的含义,为什么呢?刚不是说指针的含义很重要吗?现在又不考据?这是因为,memset函数可以把任可的内存置成某一个值,我们可以传int *,double * ,float *,char *甚至struct _Person *。我们没可能每个类型都写一个函数,因为我们有了结构体这个类型后,数据类型已经不能捉摸了。所以,我们要做到这一点,只能仅仅传入一个地址,我们一个字节一个字节地处理(因为计算机是已字节为单位的).下面就贴代码算了,已经不是二维数组的知识了。
void *mymemset(void *str,int number,int ByteSize) { char *ptr = (char *)str; int i; for (i=0;i<ByteSize;i++) { *ptr=number; ptr++; } //*ptr='/0';//调用完memset后,如果是字符串的话,记得设置结束符 return str; }
以上仅是个人理解观点,如有错误,希望读者们指出,楼主感激不尽。