C语言中二维数组的问题,纠结很久了,求解脱,谢谢
C语言中 二维数组a[i][j]的地址为什么可以表示成*(a+i)+j
为什么 *(a+i)不是表示(a+i)地址里面存放的值?a[i]可以看成是一位数组,取值(一维数组)就等于地址?而不是地址里面存放的值?我在这个问题上纠结很久了。求详细解释,一针见血。谢谢啊。
[解决办法]
这里a是数组,而不是指针.
a[i]可以看做一维数组.
仔细看下面这篇帖子,你会明白的:
http://topic.csdn.net/u/20091123/11/0C03D2E2-0655-4634-8287-0E2315D889FC.html#r_61360164
[解决办法]
123
456
789
假设定义一个a[3][3]的二维数组(如上),你也可以把它看成3个一维数组来看待。
即:
a[1]={1,2,3}
a[2]={4,5,6}
a[3]={7,8,9}
i就代表它的列数,j代表它的宽度,不知道这样解释,lz能看明白不,如果不明白的话,你学到指针的时候就会明白的。
[解决办法]
给你找个方法理解,最好先看看数组和指针的基础知识,然后再看C和指针。
一维数组和指针,若有定义int a[10],*p=a;
引用数组元素的方法有
1、a[i]
2、*(a+i)
3、*(p+i) 因为从地址值上看,p与a相等所以把2的a换成p是可以的
4、*p++ 此种方式指使用指针来引用元素,且指针不断移动
5、p[i] 1,2两种形式可以互换,所以3可以换成5这种形式,当然要理解指针带下标的含义
二维数组若有定义int a[4][4];
引用数组元素的方法是a[i][j],设t=a[i],得t[j],换成第二种形式*(t+j),
再带回*(a[i]+j),再把a[i]写成第二种得*(*(a+i)+j),总之通过变换可得各种形式,深入理解一下!
[解决办法]
先从一维数组开始理解
a[i] 地址可以写成 a+i 取里面的内容就是*(a+i)
a[i][j]
*(a+i)+j 是不是就等于 a[i]+j 我们要取里面的内容 是不是就是要 *(a[i]+j) 也就是*(*(a+i)+j)
所以*(a+i)+j 表示的就是二维数组的地址
[解决办法]
你其实可以这样理解:将二维数组理解成一维数组的顺序排列
正如你所说二维数组a[i][j]的地址可以表示成*(a+i)+j
a+i---第i个一维数组的第j个元素
[解决办法]
你画个十字架,假如a[2][3],可以看成有3个数据元素的2个数据的一位数组。*(a+i)代表第i个数据,而
*(a+i)+j 表示在第i列的第j个元素
[解决办法]
//在堆中开辟一个4×5的二维int数组#include <stdio.h>#include <malloc.h>int **p;int i,j;void main() { p=(int **)malloc(4*sizeof(int *)); if (NULL==p) return; for (i=0;i<4;i++) { p[i]=(int *)malloc(5*sizeof(int)); if (NULL==p[i]) return; } for (i=0;i<4;i++) { for (j=0;j<5;j++) { p[i][j]=i*5+j; } } for (i=0;i<4;i++) { for (j=0;j<5;j++) { printf(" %2d",p[i][j]); } printf("\n"); } for (i=0;i<4;i++) { free(p[i]); } free(p);}// 0 1 2 3 4// 5 6 7 8 9// 10 11 12 13 14// 15 16 17 18 19
[解决办法]
如果不是动态生成的二维数组,那么可以这么理解。
不管是一维数组还是二维数组,都是一块连续的内存空间,计算机都是不会区分几行几列的,所谓的几行几列都是我们思维的模式。这里二维数组的好处就是能够一定程度上接近我们的思维模式,我们可以定义几行几列。我们把每一行想象成一个维度上的一个数组,每一小数组的地址想象成另一个维度上的数组就清楚了。例如,对于一个3*3的二维数组,其实也是一个大小为9的一维数组,只不过每3个数又可以组成一个小数组,我们可以通过每个小数组的地址快速找到我们需要的数(a[1][2]),也可以通过(int *p = a;p = p+1*3+2)来获得。
lz的a+i是在另一维度中的a+i,这个维度中的数组每一个都是一个小数组的地址,你+1就是取下一个小数组的地址,+i就是取下i个小数组的地址。
如果是动态生成的二维数组,那么每个小数组还是一样的连续空间,只不过另一个维度的数组内保存的就是这些小数组的地址,这些小数组是零散地分布在内存中,但是每个小数组还是保持连续的。
[解决办法]
对于二维数组我是这么理解的,数组里面又存储的了一个数组
[解决办法]
*(a + i)也就是指向a[i]这个一维数组的第一个元素的地址,再加上j(即:*(a+i)+j)即使说指针在移动j个位置
这样也就可以表示数组a在第i行第j列的地址(也就是a[i][j])
[解决办法]
个人认为用动态存储开辟数组的例子是很有助于理解的,还有在二维数组a[i][j]中数组名代表第一个元素的地址即a[0][0],但是移动一下就会跳过j个元素大小的空间,其实a,a[0]都是指针,但是移动一下移动的空间不一样a[0]在二维数组的一维数组中移动,a在一维数组间移动
[解决办法]
楼主 我想这个应该是C编译器默认的编译规律吧
void main() { int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int b=3; int *n; int *m; int *p; n=*(a+1); m=*a+1; p=*(a+1)+2;}
[解决办法]
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
提醒:
“学习用汇编语言写程序”
和
“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
不要写连自己也预测不了结果的代码!
[解决办法]
#include <iostream>using namespace std;int main(int argc, char** argv){ int a[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; // 1. 如果要把上面的数组,用指针的眼光来看待的话,那么a是一个二级指针, // 那么*a是一个一级指针,*(*a)才是数组里面的int值 // 2. *a或者*(a + 0)就是一维数组{1, 2, 3, 4}的首地址,其中的2的地址就是在该一维数组的首地址上+1,即*(a + 0) + 1 // *(a + 1)就是一维数组{5, 6, 7, 8}的首地址,其中的8的地址就是在该一维数组的首地址上+3,即*(a + 1) + 3 // *(a + 2)就是一维数组{9, 10, 11, 12}的首地址,其中的11的地址就是在该一维数组的首地址上+2,即*(a + 2) + 2 cout << *(*(a + 0) + 1) << endl; // 输出2 cout << *(*(a + 1) + 3) << endl; // 输出8 cout << *(*(a + 2) + 2) << endl; // 输出11 // 事实上,你可以用1级指针来解决多级指针的问题,如下面代码: int* b = *a; cout << *(b + 1) << endl; // 输出2 cout << *(b + 1 * 4 + 3) << endl; // 输出8,其中的4就是第二维的长度 cout << *(b + 2 * sizeof(a[0])/sizeof(int) + 2) << endl; // 输出11,也可以用这种方式求出第二维的长度 return 0;}
[解决办法]