打印

一维数组和两维数组的关系

[复制链接]
3369|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2008-9-24 00:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一维数组:matr1[K]
char data matr1[6]=
{
  00,01,0x10,0x11,0x20,0x21
};

其中:matr1[k] 
matr1[0]=0,matr1[1]=1,matr1[2]=0x10...matr1[5]=0x21

两维数组:matr2[M][N]
char data matr2[3][2]=
{
  {00,01},
  {0x10,0x11},
  {0x20,0x21}
};
其中:matr2[m][n] 
matr2[0][0]=0,matr2[0][1]=1,matr2[1][0]=0x10...matr2[2][1]=0x21

它们的关系为:
k = m*N + n  (其中:k=0~K-1, m=0~M-1, n=0~N-1)

即当matr1和matr2的存储地址相同时,就有:
matr1[0]等同matr2[0][0]
matr1[1]等同matr2[0][1]
matr1[2]等同matr2[1][0]
matr1[3]等同matr2[1][1]
matr1[4]等同matr2[2][0]
matr1[5]等同matr2[2][1]

那么matr2[2][2]又是什么呢???
因为matr2定义为char data matr2[3][2]即M=3,N=2
那么matr2[2][2]即matr2[m][n].这里m=2,n=2(已经不满足n=0~N-1的条件)

所以matr2[2][2]应该属于非法访问,这在很多编译器编译时会报错误的!!!

但也有些编译器却可通过,实在是倒塌~~~

那么matr2[2][2]访问在何处???

根据一维数组和两维数组的关系:
k = m*N + n  (其中:k=0~K-1, m=0~M-1, n=0~N-1)

可知:
k = 2*2+ 2 = 6,即matr2[2][2]等同matr1[6].即matr1一维数组的第7个单元.

所以matr2[2][2]越界.


实际应用中,编译器都会先把两维数组用k = m*N + n转换为一维数组的.

而且可能还转换为指针.

所以在很多实际应用中,一维数组可能是不错的选择.
相关链接:https://bbs.21ic.com/club/bbs/list.asp?Page=1&boardid=11&t=3099691

相关帖子

沙发
highgear| | 2008-9-24 05:16 | 只看该作者

hotpower前辈,这个问题不是技术问题

这本来不关我事, 我玩游戏累了,上来逗逗wxj1952解闷。

事情很简单,一个不了解wxj1952是什么货色的热心大侠wellrun好意去解答wxj1952的问题,还天真的留下email想真诚的与它交朋友。此侠给出了解答(本来就是一个极菜的问题),本意是将整个数组(char matr[2][2])复制|移动到内存某处,不知此侠没看仔细还是笔误,将wxj1952给出的char matr[3][2]写作char matr[2][2],于是wxj1952抓住就此大肆辱骂嘲弄。

呵呵,wxj1952是什么货色,老警察都知道,可怜那些新警察啊。

使用特权

评论回复
板凳
kanprin| | 2008-9-24 08:24 | 只看该作者

错了就错了

其实就技术问题讨论,错了就错了,尽量别归为笔误之类的借口。
在产品上,没有人会为你的笔误买单。
勇于承认错误并改之,这才有利于提高吧?呵呵。

使用特权

评论回复
地板
平常人| | 2008-9-24 08:37 | 只看该作者

主要的问题是编译器是否有数组越界检查或告警

据我所知不少编译器不做数组越界检查,你可以写array[-1]这样的表达式。

使用特权

评论回复
5
HWM| | 2008-9-24 08:50 | 只看该作者

关于C中的数组,因效率方面的考虑,不可能检验其边界

其实指针同样是如此(数组也是指针的特例)

关于数组,我曾经发过相应的内容,翻了一下,再表如下:


数组实际上是一个由分层次叠加构造而成的一种数据结构,其最底层的基础就是下标操作符。作为一种操作符不仅可以和数组联用,还可以通过重载改变其原始语义(具体可见新手版内 C++ 随笔-21)。

只要有了一个常量指针,配合下标操作符的使用,就可以形成一个数组的雏形(前提是具备一个以常量指针为起始点的存储空间)。当然作为数组的雏形自然有其缺陷,那就是缺少数组的长度信息,以至于不可能得到其有效的整体特性。因此作为一个“完整”的数组定义还必须加入数组的长度信息。但作为一维数组,相关定义并未改变其“数组名”和下标操作符的基本属性。

那么多维数组情形又将是如何的呢?显然由于多维数组必须含有n-1维下标长度的信息(n>1),所以不可能存在上述数组的原始实现(仅用起始指针和下标)。那么多维数组具体又是如何定义的呢?先列出定义形式:

type A[N1][N2]...[Nn];

其中n为数组的维数,N1...Nn为数组各维的长度。

类似的,若将A独立拿出来看,它还是一个指向数组起始位置的常量指针。问题是在此情况下所指对象的“类型”是什么?是否还能象一维数组那样所指类型为数组单元变量类型呢?显然不行,因为这样的话将失去多维数组中相当重要的长度信息。那么不指向数组单元变量又指向什么呢?答案是,A将被定义为指向“数组类型”type [N2]...[Nn]的指针。由此,实际上还可以得出这样一个结论,数组A是被组织成N1个类型为type [N2]...[Nn]的单元的“一维数组”,其中*(A+i)为此“一维数组”的第i+1个单元(即i+1个数组的数组名)。以此类推,可以得到这样一个表达式:

    *(...*(*(A+i)+j)+...k) <=> A[j]...[k]

利用这种层次叠加构造法,顺理成章地建立了从最原始的数组雏形,通过不断地增加维长信息,最终到多维数组空间的形成机制。

下面列出一个具体的实例:

#include "stdafx.h"

int A[10][20][30];
int x, y;

int main(int argc, char* argv[])
{
    A[1][2][3] = 1234;
    *(*(*(A+3)+2)+1) = 4321;
    x = *(*(*(A+1)+2)+3);
    y = A[3][2][1];

    return 0;
}

附:数组的定义

数组是由一个指向首单元的常量指针(数组名)所引领的一组一定数量的连续单元所组成的数据结构。此常量指针的尺寸大小(尺寸的拓广)定义为整个数组的大小。此常量指针的地址(地址的拓广)定义为数组首单元的地址。多维数组type A[N1][N2]...[Nn]定义为一个常量指针(数组名)为A,由N1个单元(类型为type [N2]...[Nn],数组名为*(A+i)的数组,i=0...N1-1)组成的一维数组。这里的单元要理解成相关数组的常量指针(数组名)。


由以上数组的定义可以对实例中的相关表达式作以下分析:

    *(*(*(A+1)+2)+3)

先看A,它是一个指向数组首单元(类型为int [20][30])的常量指针(此单元为*A)。那么*(A+1)就是指向第二个单元(第二个类型为int [20][30]的数组的常量指针)。然后在此数组(常量指针或数组名为*(A+1))内再得到类型为int [30]的第三个数组的常量指针*(*(A+1)+2)。最后在这个数组(常量指针或数组名为*(*(A+1)+2))中指定类型为int的第四个单元*(*(*(A+1)+2)+3),即数组A的单元变量A[1][2][3]。

用地址算式可以表示如下

        *((int*)A + (1*sizeof(*(A)) + 2*sizeof(*(*(A))) + 3*sizeof(*(*(*(A)))))/sizeof(int))

其中
    *(A+1)            的地址为    (int*)A +  1*sizeof(*(A))/sizeof(int)
    *(*(A+1)+2)       的地址为    (int*)A + (1*sizeof(*(A)) + 2*sizeof(*(*(A))))/sizeof(int)
    *(*(*(A+1)+2)+3)  的地址为    (int*)A + (1*sizeof(*(A)) + 2*sizeof(*(*(A))) + 3*sizeof(*(*(*(A)))))/sizeof(int)

使用特权

评论回复
6
农民讲习所| | 2008-9-24 09:14 | 只看该作者

同意highgear意见

就这个地球人都知道的小事,不值得单独开个帖子。kanprin是想当新警察?建议去原帖发言。

使用特权

评论回复
7
computer00| | 2008-9-24 09:47 | 只看该作者

把数组下标写在前面照样也可以…… 8[p]等价p[8]...

结果都是*(p+8),所以在前还是在后无所谓了。

使用特权

评论回复
8
sodwell| | 2008-9-24 15:48 | 只看该作者

re

请问LS的老师们:char **p和char *p[],在使用上要注意哪些!?这2天被这个东西搞晕了!!
比如做为参数的时候,如: int get_file_num(char **p)   和 
int get_file_num(char *p[])  
这个2个函数里面的内容一样对p进行操作,给*p赋值,但是结果会不会有差别?

使用特权

评论回复
9
mohanwei| | 2008-9-24 21:24 | 只看该作者

一般都会处理成一维数组的,除了动态申请的……

使用特权

评论回复
10
highgear| | 2008-9-24 21:39 | 只看该作者

kanprin朋友,我同意你的观点

其实就技术问题讨论,错了就错了,没有什么了不起。但论坛解答,纯属义务性,没有人会仔细推敲严格检查自己的内容,所以如果有人关注疏漏,一定是宵小,恶意的曲解,尖酸的辱骂,那么性质就变了。wellrun的意思表达的很清楚,他被攻击抄袭(与前面的某人的解答某处相同)和什么也不懂,可惜wellrun一怒之下删除了自己的答复,估计也不会再现身与宵小辩解,到底是整个数组还是单个元素,任由wxj胡说了。

这个论坛的气氛很怪异,我见一位我尊敬的前辈无端被辱骂才跳出来对骂,哈哈,论坛里的技术对错关我p事。

楼上的sodwell朋友:没有差别。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1460

主题

21619

帖子

506

粉丝