首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

C语言中二维数组的有关问题,纠结很久了,求解脱,多谢

2012-05-09 
C语言中二维数组的问题,纠结很久了,求解脱,谢谢C语言中 二维数组a[i][j]的地址为什么可以表示成*(a+i)+j为

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个元素 

[解决办法]

C/C++ code
//在堆中开辟一个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个小数组的地址。

如果是动态生成的二维数组,那么每个小数组还是一样的连续空间,只不过另一个维度的数组内保存的就是这些小数组的地址,这些小数组是零散地分布在内存中,但是每个小数组还是保持连续的。
[解决办法]
对于二维数组我是这么理解的,数组里面又存储的了一个数组
[解决办法]
探讨

对于二维数组我是这么理解的,数组里面又存储的了一个数组

[解决办法]
补充一下,对于int a[3][3]来讲,a[0]的地址就是a[0],也就是说*a=&a
[解决办法]
其实根本就不存在二维数组,从内存的角度来说都是一维的,如
1 2 3
4 5 6
7 8 9
也就是由三个一维数组组成,分别是a[0] = { 1,2,3},a[1] = {4,5,6},a[2] = {7,8,9}

由于数组名是指针常量,所以a + i就表示说指针移动i个位置,也就相当于a[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编译器默认的编译规律吧

C/C++ code
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、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

不要写连自己也预测不了结果的代码!

[解决办法]
C/C++ code
#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;}
[解决办法]
探讨

引用:

对于二维数组我是这么理解的,数组里面又存储的了一个数组

正解,例如一个int a[3][3]
a其实就是a[0]的地址
a+1就是a[1]的地址
a+2就是a[2]的地址

*(a+1)就是a[1][0]的地址
*(a+1)+1就是a[1][1]的地址
*(*(a+1)+1)就是a[1][1]的值

[解决办法]
把这个数组分开看,行和列分开看你就会悟出来了
如果定义一个指针变量,是可以将数组的第一个元素也就是数组的入口(既数组名)传给指针
就比如你举得例子
二维数组a[i][j]的地址为什么可以表示成*(a+i)+j
此时a=[0],a+i=&a[i](这里的i代表向后移几位,1的话就是1,后面以此类推),所以*(a+i)=a[i]
到这里我觉得你应该明白了,i代表行,j就代表列
加i就是上下移动,就是移行,erj就是左右移动了
不知道这样说你明不明白
这都是根据我自己做题悟出来的,希望能帮到你
[解决办法]
探讨

C/C++ code
//在堆中开辟一个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++) {
……

热点排行