您的位置:首页 > 其它

二维数组和一维数组的数据分布和存取

2016-03-20 19:27 274 查看

二维数组和一维数组的数据分布和存取

标签:c/c++

二维数组在存储分布上和一维数组是一样的,但是存取的写法却是有很大差异的

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
int i, j;
char mark[64][64] = {0};
char a = 1;

for (i = 0; i < 64; i++){
for (j = 0; j < 64; j++){
memcpy(mark + i * 64 + j, &a, sizeof(char));
}
}

return 0;
}


  上述代码会越界(如果换作一维数组就不会发生越界),原因是mark是二维数组的首地址,所以对mark进行+1操作,事实上得到的结果表示的是mark的下一维[64]数组的首地址,即一次加上的是整个第二维数组的大小。

如何像操作一维数组一样操作二维数组

  在实际的项目中,可能会经常涉及到将二维数组改成一维数组的情况,也会经常执行类似于从数组中取值的操作。

如果操作是从数组第一个元素(0, 0)开始

  我们可以用数组名初始化指针,之后用指针进行相关操作,没有问题(见下面例子,这种方法其实也不好操作)。此时如果是选用数组名进行操作,需要特别注意不能出现上述情况(在二维数组名上进行加法运算不等同于“遍历”数组元素)。

如果是从数组中间进行取值

  我们可以用指针指向该元素,之后用指针进行相关的操作。但是,前提是一定要找准该元素的地址。举两个例子(例子中将二维数组的第一维第二维分别成作“行”和“列”;mark_[64*64]是mark对应的转换后的一维数组):

(1)从第二列首地址开始

char *p = mark[1];


对应的将二维数组转换为一维数组的写法:

&mark_[1*64] <=> mark[1]


(2)从第二列的第三个元素开始

char *p = &mark[1][2];


对应的将二维数组转换一维数组的写法:

&mark_[1*64+2] <=> &mark[1][2]


二维数组名初始化指针问题

// 略去头文件

int main()
{
int a[3][3] = {
{1, 2, 3},
{3, 4, 5},
{6, 7, 8}
};

int *p1 = a;         //[1]
printf("*p:%d %d\n", *p1 , *(p1+1));

int **p2 = a;        //[2]
printf("**p:%d %d\n", *p2, *(p2+1));

int(*p3)[3] = a;     //[3]
printf("(*p)[]:%d %d\n", (*p3)[0], (*p3)[1]);
printf("(*p)[]:%d %d\n", *(*p3), *(*(p3)+1));

int sd = 0;

return 0;
}


注释[1]

  g++或gcc编译器会直接报错:
test.cpp:18:14: error: cannot convert ‘int (*)[3]’ to ‘int*’ in initialization int *p1 = a;
;vs下可以编译通过,且通过p1指针(+1或++),我们可以对二维数组进行遍历操作,可见vs的编译器在这种情况下会对数组名a进行类型转换,即将
int (*)[3]
转换为
int *
。不要使用这种写法,因为会出现不兼容的问题。

注释[2]

  g++或gcc编译器会直接报错:
test.cpp:18:14: error: cannot convert ‘int (*)[3]’ to ‘int**’ in initialization int **p2 = a;
;vs下可以编译通过,且通过p2二维指针(+1或++),我们可以对二维数组进行遍历操作,可见vs的编译器在这种情况下也会对数组名a进行类型转换,即将
int (*)[3]
转换为
int **


  注意这里是【int 】,因为是二维数组的缘故,此时会发现*p2依旧是一个指针,只不过这个指针存储的“地址”是a[0][0]对应的值;那么相应的,p2是指针的指针,存储的是*p2的地址;但是,**p存储的就是未知的值了,因为a[0][0]作为地址再去取地址的值,会发生意想不到的问题,内存越界!**不要使用这种写法,因为会出现不兼容的问题。

注释[3]

  正常的写法,不会出现强制类型转换,但是你会发现这种方法和数组操作没有太大区别,因为类型的关系,*p表示的是只是一个地址,如果需要取值,则外层需要再有一个取地址符 * 。正常的写法,推荐。

小结

  代码中使用的应该是一维数组到指针的转换,或者是多维指针通过calloc/malloc获取空间之后的相互转换(指向)。不应该存在上述过程中的多维数组到指针之间的转换。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: