/* ============================================================================ Name : TeatArr.c Author : lf Version : Copyright : Your copyright notice Description : 二维数组的认识以及其表示元素的两种方式 备注说明 1 要理解二维数组的存储方式. 2 实际上利用a[i][j]的方式并不"正统",但这靠近我们的 常识一些,更本质和应该的还是利用指针和数组名. 一个二维数组,比如: int array[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; 它在内存中存在方式如下: 0X00F8FE4C 1 2 3 4 0X00F8FE5C 5 6 7 8 0X00F8FE6C 9 10 11 12 即: 从0X00F8FE4C地址开始存放了 1 2 3 4 从0X00F8FE5C地址开始存放了5 6 7 8 从0X00F8FE6C地址开始存放了9 10 11 12 参考资料: http://blog.csdn.net/iu_81/article/details/1782642 http://www.jb51.net/article/54220.htm Thank you very much ============================================================================ */ #include <stdio.h> #include <stdlib.h> int main(void) { // test0(); // test1(); test2(); // test3(); return EXIT_SUCCESS; } /** * 一维数组的两种表达方式 * int *p=&a * 指针p执行了数组a的首元素. * 又因为*p是取内容,所以*(p+N) * 取的就是第N个元素的内容 */ void test0(){ int a[5]={0,1,2,3,4}; //第一种方式:下标表示法 int i=a[2]; printf("i=%d\n",i); //第二种方式:指针表示 int *p=&a; int j=*(p+2); printf("j=%d\n",j); printf("==========\n"); //在一维数组中数组名就是首元素的地址 //所以a和&a[0]是等值的. //但是注意&a虽然值和它们两个相等,但是它是 //代表整个数组的块地址的起始值. //这点通过sizeof()可以看出来 printf("a=%x,sizeof(*a)=%d\n",a,sizeof(*a)); printf("&a[0]=%x,sizeof(*&a[0])=%d\n",&a[0],sizeof(*&a[0])); printf("&a=%x,sizeof(*&a)=%d\n",&a,sizeof(*&a)); printf("==========\n"); } /** * 将二维数组a[3][4]看作一维数组a[3] * 一维数组a[3]中每个元素又是一个一维数组. * 那么&a[i]表示某一行的地址块的首地址 * 所以sizeof(*&a[0])=4*4=16 * 即sizeof(a[0])=4*4=16 * &a[i]是个地址,所以sizeof(&a[0])=4或者8字节 * * 在一维数组: * int c[3]={0,1,2}; * 中数组名c就是第一个元素的首地址,所以*c=0即取出了第一个元素. * 同样的道理a[i]也是一个一维数组,那么*a[i]就是取出了第i行的 * 第一个元素.比如*a[0]=0 */ void test1() { int i=9527; int *p=&i; //p=8d49c90c,&p=8d49c900,*&p=8d49c90c,*p=9527 //p是p指向的内存单元,&p是p本身的内存单元, //*&p取出p中所指向的内存单元就是p(和第一个值一样) //*p取出指针指向的内存单元的值 printf("p=%x,&p=%x,*&p=%x,*p=%d%x\n",p,&p,*&p,*p); int c[3]={0,1,2}; //*c=0,c=8d49c8f0,&c=8d49c8f0,*&c=8d49c8f0 //*c好理解,取出了数组中的第一个元素 //c是数组第一个元素的首地址,这个也好理解 //&c是整个数组的地址块的首地址. //*&c是什么意思呢? //我们习惯简单地说:由于*和&抵消了,所以*&c就是c. //从数值上看也确实是这样. //*&c还可以怎么理解呢? //注意上面的例子: //int i=9527; //int *p=&i; //*&p的值就是p,即*&p的值和p是一样的. //其实此处是非常相似的,可以这么看: //int *p=&c; //就是说把c的地址保存在了p那个内存单元里面 //那么*&p和p是一样的均为整个数组c的地址块的首地址 //所以*&c可以这么理解: //第一步:&c取出了c的地址放到了某个内存单元里面 //第二步:*&c即从某个内存单元里取值,取出的值当然是c的地址 //这个过程和上面是一样的.只是没有用一个指针变量明确存放c的地址而已 printf("*c=%d,c=%x,&c=%x,*&c=%x\n",*c,c,&c,*&c); printf("===========\n"); int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 } }; //&a[0]和a[0]的数值相等,但是含义不同. //&a[0]是整个行的块地址的起始地址 //a[0]是这行第一个元素的首地址 //*a[0]取得了这行的第一个元素的值 //这里把a[0]看做一个一维数组就很好理解了. printf("&a[0]=%x,a[0]=%x,*a[0]=%d\n",&a[0],a[0],*a[0]); printf("sizeof(*&a[0])=%d,,sizeof(a[0])=%d,sizeof(&a[0])=%d,sizeof(*a[0])=%d\n", sizeof(*&a[0]),sizeof(a[0]),sizeof(&a[0]),sizeof(*a[0])); printf("===========\n"); } /** * 二维数组的认识 * * 关于二维数组的指针表示方式,简述如下: * 二维数组的每个元素是一个一维数组. * 这个是认识和分析二维数组的基础和核心 * * 一个二维数组,比如: * int array[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; * 它在内存中存在方式如下: * 0X00F8FE4C 1 2 3 4 * 0X00F8FE5C 5 6 7 8 * 0X00F8FE6C 9 10 11 12 * 即: * 从0X00F8FE4C地址开始存放了 1 2 3 4 * 从0X00F8FE5C地址开始存放了5 6 7 8 * 从0X00F8FE6C地址开始存放了9 10 11 12 * 从本质上而言二维数组的元素在内存中还是线性地按序存放的. * * 把二维数组a[3][4]可以看成是有3个元素的一维数组a[3]: * {0X00F8FE4C,0X00F8FE5C,0X00F8FE6C} * 注意的问题: * 0 这个一维数组a[3]是抽象的,不是很具体 * 1 a[3]每个元素都是一个行地址. * a[3]每个元素的值就是每行即每个一维数组的首地址. * 2 这个数组的首地址就是0X00F8FE4C!!!!! * 同理第2个元素的地址就是0X00F8FE5C,其值也是这个值. * 3 二维数组a[3][4]看成是有3个元素的一维数组a[3]. * 这里的行数为3得到了体现,那么列数4在哪里体现的呢? * 这个a[3]的步长为4个整型长度即16字节. * 比如int b[3]={0,1,2}; * 因为它每个元素都是int类型的,所以它的步长就是4个字节 * b代表第一个元素的地址,b+1代表了第二个元素的地址; * 从b到b+1移动了4个字节. * 所以这里的a[0]到a[1]移动了4*4=16个字节 * * * 利用下标表示法: * 每个元素的地址用下标表示法为&a[i]其值是*&a[i]即a[i] * * 利用指针表示法(数组名表示法): * 每个元素的地址表示为a+i,其值为*(a+i) * * 所以可以说: * &a[i]与a+i等价 * a[i]与*(a+i)等价 * * 这只是两种不同表达方式的差异罢了,获取到的值当然是一样的. * 这两种方式即a[i]和*(a+i)都获取到了a[3]每个元素的值 * 也是每个一维数组的起始地址. * * 小结: * 获取每个一维数组里第j个元素的地址的两种方式就分别是: * a[i]+j和*(a+i)+j * 获取每个一维数组里第j个元素的内容的两种方式就分别是: * *(a[i]+j)和*(*(a+i)+j) * 所以可以说: * a[i]+j和*(a+i)+j等价,都是用来取地址的 * *(a[i]+j)和*(*(a+i)+j)等价,都是用来取内容的 * * 最后,再次提醒a[3]每个元素的地址及其内容是一样的. */ void test2(){ int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 } }; //获取a[3]每个元素地址和其对应的内容的两种方式: //&a[i],a[i]和a+i,*(a+i) printf("&a[0]=%x,a[0]=%x <==> a+0=%x,*(a+0)=%x\n",&a[0],a[0],a+0,*(a+0)); printf("&a[1]=%x,a[1]=%x <==> a+1=%x,*(a+1)=%x\n",&a[1],a[1],a+1,*(a+1)); printf("&a[2]=%x,a[2]=%x <==> a+2=%x,*(a+2)=%x\n",&a[2],a[2],a+2,*(a+2)); printf("==========\n"); //访问第二行的第三个元素: printf("a[1]+2=%x,*(a[1]+2)=%d\n",a[1]+2,*(a[1]+2)); printf("*(a+1)+2=%x,*(*(a+1)+2)=%d\n",*(a+1)+2,*(*(a+1)+2)); printf("==========\n"); } /** * 二维数组的两种表达方式 * * 利用下标方式访问i行j列的数据很简单:a[i][j] * * 如果用指针的方式又该是怎么样呢? * 第一步:找到行 * 从test2()中我们已经知道了行地址是*(a+i) * 第二步:找到列 * 找到了行再找列就简单多了,偏移j个单位就行 * 得到地址为*(a+i)+j * 所以取值为*(*(a+i)+j); * */ void test3(){ int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 } }; //第一种方式:下标表示法 int i=a[2][3]; printf("i=%d\n",i); //第二种方式:指针表示 int j=*(*(a+2)+3); printf("j=%d\n",j); } ///** // * 这是以前我土鳖的认识方法。。。 // * 也就不删了。。。 // * // * // * 二维数组的认识 // * // * 关于二维数组的指针表示方式,简述如下: // * 二维数组的每个元素是一个一维数组. // * 比如此处的a[3][4]可以看成是有3个元素的一维 // * 数组,每个元素又是具有4个元素的一维数组. // * 所以此时可把二维数组a[3][4]看作一维数组a[3] // * 这个一维数组有三个元素,每个元素又是一个一维数组. // * 在此打印每行的地址: // * &a[0]=28feb0 // * &a[1]=28fec0 // * &a[2]=28fed0 // * 可以看到每行的地址相差4*4=16 // * 但是为什么 // * a[0]=28feb0 // * a[1]=28fec0 // * a[2]=28fed0 // * 也打印出来了每行的地址??? // * 这个很简单,在test1()中已经进行了说明: // * &a是一个地址,再执行*&a还是得到这个地址. // * 即&a[0]=*&a[0]在数值上也等于a // * 所以&a[i]与*(&a[i])和a[i]是同一回事!!! // * // * 因为a是指向第一行的地址,所以a+1代表第二行的地址,a+2代表第三行的地址 // * 所以&a[i]与a+i是同一回事!! // * // * 综上所述: // * 在二维数组a中 // * &a[i]与*(&a[i])和a[i]还有a+i是等价的 // * // * 由此可以看到两条演变的路线: // * &a[i]-->*&a[i]-->a[i] // * &a[i]-->*&a[i]-->*(&a[i])-->*(a+i) // * // */ //void test2(){ // // // int a[3][4] = { { 0, 1, 2, 3 }, // { 4, 5, 6, 7 }, // { 8, 9, 10, 11 } }; // //打印二维数组每一行的首地址.&a[i]与a+i等价 // printf("&a[0]=%x,a+0=%x\n",&a[0],a+0); // printf("&a[1]=%x,a+1=%x\n",&a[1],a+1); // printf("&a[2]=%x,a+2=%x\n",&a[2],a+2); // // // printf("&a[0]=%x,a[0]=%x,*(a+0)=%x\n",&a[0],a[0],*(a+0)); // printf("&a[1]=%x,a[1]=%x,*(a+1)=%x\n",&a[1],a[1],*(a+1)); // printf("&a[2]=%x,a[2]=%x,*(a+2)=%x\n",&a[2],a[2],*(a+2)); // // // printf("==========\n"); //} //** // * 这是以前我土鳖的认识方法。。。 // * 也就不删了。。。 // * 二维数组的认识 // * // * 关于二维数组的指针表示方式,简述如下: // * 二维数组的每个元素是一个一维数组. // * 这个是认识和分析二维数组的基础和核心 // * // * 一个二维数组,比如: // * int array[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // * 它在内存中存在方式如下: // * 0X00F8FE4C 1 2 3 4 // * 0X00F8FE5C 5 6 7 8 // * 0X00F8FE6C 9 10 11 12 // * 即: // * 从0X00F8FE4C地址开始存放了 1 2 3 4 // * 从0X00F8FE5C地址开始存放了5 6 7 8 // * 从0X00F8FE6C地址开始存放了9 10 11 12 // * // * 把二维数组a[3][4]可以看成是有3个元素的一维数组a[3] // * 利用下标表示法:每个元素的地址用下标表示法为&a[i]其值是*&a[i]即a[i] // * 利用指针表示法(数组名表示法):每个元素的地址表示为a+i,其值为*(a+i) // * 所以可以说: // * &a[i]与a+i等价 // * a[i]与*(a+i)等价 // * 这只是两种不同表达方式的差异罢了,获取到的值当然是一样的. // * 这两种方式即a[i]和*(a+i)都获取到了a[3]每个元素的值 // * 也是每个一维数组的起始地址 // * // * 每个元素的地址用下标表示法为&a[i]其值是*&a[i]即a[i] // * 我们可以发现&a[i]和a[i]在数值上是相等的. // * 这是为什么呢?可以这么理解: // * 还是要从二维数组的本质说起: // * 1 二维数组的每个元素是个一维数组 // * 2 把二维数组a[i][j]可以看成是有i个元素的一维数组a[i] // * 那么a[0],a[1]....a[i]都是一维数组 // * 既然a[i]是一维数组,那么&a[i]是一维数组地址块的首地址 // * a[i]是一维数组第一个元素的首地址. // * 所以他们在数值上是相等的,但是含义不同. // * // * 每个元素的地址表示用指针和数组名表示为a+i,其值为*(a+i) // * 我们可以发现a+i和*(a+i)在数值上是相等的 // * int array[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // * 它在内存中存在方式如下: // * 0X00F8FE4C 1 2 3 4 // * 0X00F8FE5C 5 6 7 8 // * 0X00F8FE6C 9 10 11 12 // * 可以明确的一点:这一块内存地址是连续的,即每个元素之间也是紧挨着存放的. // * 那么a[3]可以看成{0X00F8FE4C,0X00F8FE5C,0X00F8FE6C} // * 当然这个数组的首地址也就是0X00F8FE4C // * a+i表示第i个元素的地址. // * *(a+i)是其对应的值 // * // * // * 那么获取每个一维数组里第j个元素的地址的两种方式就分别是: // * a[i]+j和*(a+i)+j // * 那么获取每个一维数组里第j个元素的内容的两种方式就分别是: // * *(a[i]+j)和*(*(a+i)+j) // * 所以可以说: // * a[i]+j和*(a+i)+j等价 // * *(a[i]+j)和*(*(a+i)+j)等价 // */ //void test2(){ // // int i=9527; // int *p=&i; // printf("&i=%x,p=%x,&p=%d\n",&i,&(*p),*p); // // int a[3][4] = { { 0, 1, 2, 3 }, // { 4, 5, 6, 7 }, // { 8, 9, 10, 11 } }; // // //获取a[3]每个元素地址和其对应的内容的两种方式: // //&a[i],a[i]和a+i,*(a+i) // printf("&a[0]=%x,a[0]=%x <==> a+0=%x,*(a+0)=%x\n",&a[0],a[0],a+0,*(a+0)); // printf("&a[1]=%x,a[1]=%x <==> a+1=%x,*(a+1)=%x\n",&a[1],a[1],a+1,*(a+1)); // printf("&a[2]=%x,a[2]=%x <==> a+2=%x,*(a+2)=%x\n",&a[2],a[2],a+2,*(a+2)); // printf("==========\n"); // // //访问第二行的第三个元素: // printf("a[1]+2=%x,*(a[1]+2)=%d\n",a[1]+2,*(a[1]+2)); // printf("*(a+1)+2=%x,*(*(a+1)+2)=%d\n",*(a+1)+2,*(*(a+1)+2)); // // printf("==========\n"); //}