您的位置:首页 > 编程语言 > C语言/C++

c语言中二维数组的问题

2012-11-13 16:25 99 查看
在论坛上看到一个关于二维数组讨论的帖子,觉得很有价值就整理了一下转帖了过来

1)二维数组 参数传递 和二维数组的定义是一个道理。

二维数组声明时要求给定第二维下标。(同样,多维数组声明时要求给定除第一维外其他所有维的下标)

这是因为不管几维数组在内存中的存储和一维数组没有本质区别,都是线性存储的,长度是各个维下标之积。

程序运行时访问二维数组的某元素时要靠各维下标作偏移指标,比如a[10][3],只有给定第二维下标“3”,

当你写a[10]时,程序才知道要从a这个位置向后移动10个“3”。

参数的道理相同,也是局部变量的一种,和你在函数中声明的变量没有太大区别(栈中的位置不同)。

所以必须这样写:void trans(int a[][3], int b[]);

#include <stdio.h>

#include <stdlib.h>

void trans(int a[][3], int b[]);

int main(void)

{

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

int b[9];

int i;

trans(a, b);

for (i = 0; i < 9; i++)

printf("%d/t", b[i]);

printf("/n");

exit(0);

}

void trans (int a[][3], int b[]) { //形参

int i, j, k;

for (i = 0; i < 3; i++) {

for (j = 0; j < 3; j++) {

b[k++] = a[i][j];

}

}

}

二维数组做参数

#include <iostream>

using namespace std;

void pb(char** a)

{

cout<<a[1][1];//只是测试调用成功不

}

int main()

{

char a[2][2];

for(int k=0;k<2;k++) {

for(int w=0;w<2;w++)

cin>>a[k][w];

}

pb((char **)a);

//二维数组做参数强制转换也有错!

return 0;

}

有什么好办法传递参数,吗,最好能有完整程序!谢谢

提问者: yjc_5252 - 试用期 一级 最佳答案

#include <iostream>

using namespace std;

void pb(char a[][2])

//一楼的稍改下,100改为2,即 a[][2]

{

cout<<a[1][1];

}

int main()

{

char a[2][2];

for(int k=0;k<2;k++){

for(int w=0;w<2;w++)

cin>>a[k][w];

}

pb(a);

return 0;

}

参考资料:一楼

0回答者: 江玉菡 - 试用期 一级 2009-5-25 20:56

其他回答 共 1 条

#include <iostream>

using namespace std;

void pb(char a[][100])

{

cout<<a[1][1];

}

int main()

{

char a[2][2];

for(int k=0;k<2;k++)

for(int w=0;w<2;w++)

cin>>a[k][w];

pb(a);

return 0;

}

搞人的二维数组指针,求助!

事情是这样的,我们老师说对于声明如下的

int a[4][5];

a这个二维数组,它的类型实际上是int**,

但是我在编程的时候试,写了下面的代码:

int a[4][5];

int** p = a;

VC中说不能将int [4][5]转化成int**,

BCB和Dev-C++中说

不能将int (*)[5]转化成int**,

所以我想应该是老师弄错了,

实际上一个二维数组的类型是int (*)
(其中n是第二维的维数),



int (*p)[5] = a;

就行了。

我跟我们老师说,她坚持说int**是对的。

大家怎么看啊?我都有点晕了。

2 楼goodboy1881

如果要如此写,你写

int** p =(int**)a;

尝试一下。

要不然你说这个a怎么解释,是二维数组第一行的首指针?还是二维数组的首指针?

3 楼

她说二维数组是int**型的,但是赋值指针的时候和类型又是不一样的,两者是有区别的。

所以我感到很奇怪,为什么赋值的时候不一样的,还要说二位数组是int**,

要不然为什么不能用一个int**的指针指向它呢?这不是明显的赋值不相容吗?

5 楼SaiRose(Learning......)

指针!=数组名

int a[4][5]它的类型绝对不是int**

只是函数在传参数的时候会将数组转化为指针

具体的查书了,c专家编程上有详细讲解

6 楼qingyuan18(zealot_tang)

二维数组名不能简单理解成二维的指针,

int a[4][5];

a是二维数组的首地址,但它不是一个int **型的指针。

int** p = a;

这样赋值是错误的,用指针对二维数组的操作应该参考用指针数组(int * p[4])

或者或者行指针((int *)p[4])的方式

7 楼anyy0929()

同意上面的,a是二维数组的首地址,

而P是指向指针的指针,不能这样赋值~~~

8 楼ywhs()

我想问的是int a[5][3]中a的类型是int**吗?

12 楼FreeFice(庄鱼)

int **用于表示二维数组的缺点在于指针的间隔无法确定,因此,虽然,int**可以描述二维数组,但地址并不是“自动”的一次性赋给的,作为定长多维数组,在很多时候可以被当作一位数组直接操作,然而,多级指针却绝不可以这样,这是数组与指针最本质的区别。如果一定要问int**与什么数组形式相对的话,int** = int[][],

而int[][]与int[5][3]完全是两回事。

13 楼

多维数组在意义上和指针完全不是一回事了

指针是一个间接指向的过程

但是多维数组,确实一个定点计算的问题

作为参数传递的时候,也不能如此直接传递

必须强制转化为一维数组,然后给出各个原始纬度的大小,再通过计算偏移得到原始数据

14 楼

给个例子

int a[2][3];

int** p;

p = new int*[2];

p[0] = new int[3];

p[1] = new int[3];

然后你反汇编这段代码:

a[1][2] = 5;

p[1][2] = 5;

汇编代码都不一样...

a[1][2] = 5;

00416AFE mov dword ptr [ebp-8], 5

p[1][2] = 5;

00416B05 mov eax, dword ptr [p]

00416B08 mov ecx, dword ptr [eax+4]

00416B0B mov dword ptr [ecx+8], 5

这个是我针对我的例子反汇编的结果,认为可以相互转换的朋友,可以看看

15 楼

这么用

int a[4][5];

int** p = &a[0];

其实区别就在二维数组的空间为连续,而二维指针申请的堆空间不是。

18 楼

二维数组名不能简单理解成二维的指针,int a[4][5];

a是二维数组的首地址,也是数组第一行的首地址(在数值上是一样的),但它不完全等同于一个int **型的指针。

int** p = a;这样赋值是可以的,多维数组就只能用多层的指针,(使用数组名除外)。至少这点在TC中是完全正确的,也许VC有不同的规定!!

19 楼

可以用,不代表会正确,下面这个代码在C中都没有问题:

char c;

int* p;

c = 'a'

p = &c;

*p = 65535;

赋值确实可以,但是执行结果不会正确...

20 楼

int[][]是什么意思?

为什么int** == int[][]?

int[][]与int[5][4]分别表达什么?有什么区别?

21 楼

其实,int a[4][5];

这种型式中,a的类型为:int (* )[5];

是的,编译器会把最后一维的数量做为类型的一种参考,更严格一点说的话,应该是:int (* const )[5];

22 楼

int a[4][5];

这种型式的的确确会在“很多时候可以被当作一位数组直接操作”。但最好不要这样做,我觉得不安全。

23 楼

int [][]二维不定数组,

C/C++中并不允许这样描述,根据C/C++对数组的定义要求:在做参数声明时,仅允许存在一个[](第一个)以表示数组大小的不确定性。数组大小在非参数声明时必须明确指明或初始化的。上面用int [][] <=> int **主要目的在于表述没有一种数组形式可以与int**相对应。指针*与数组[]实际上是不能用等号相联系的,唯一的例外是字符串char*与char[]一致,但实际上,字符串并不是什么指针,而是类似于隐式链表的数组(必须满足空字节结束表示),用于写成指针格式纯属早期编程习惯。千万不能拿来当验证指针与数组关系的工具。

由于指针的外延比数组(包括不定数组)大得多,因此,通常可以将A[4][5]赋值给B[][5]赋值给*C[5],但反过来却是不行的。

关于二维数组指针的问题

这是主函数

main()

{

int a[3][4]={{1,1,2,3},{4,5,6,7},{8,9,10,11}};

printf(" %u/n %u/n %u/n %u/n %u/n %u/n",

a+1,a[1],&a[1][0],*(a+1),*((a+1)+2),*(*(a+1)+2));

}

输出的结果是

65480

65480

65480

65480

65496

6

我想问一下从前三个可以看出a+1==*(a+1)可是为什么

*((a+1)+2)和*(*(a+1)+2)的结果不一样谁能能解释一下吗

其实这是C在实现多维数组时的魔术而已,实际上a就是一个12个int的数据区。你在写a[1][2]时编译器实际上知道这个数组一行是4个元素,所以计算它的地址为a+(1*4)+2,即a[1][2]就是*(a+(1*4)+2)。

另一方面,编译器允许使用形如a[1]这样的表述,由于它知道a是一个定义为a[3][4]的数组,所以它知道a+1实际上应该将a这个首地址加上4个int的大小,你如果再试一下就会发现在int为4个字节的机器上a[1]应该是a加上4.

C语言中的指针的值虽然可能是同一个内存地址,但是编译器知道它的语言不同,在做同样的指针增量的时候加的地址也是不同的。就像你如果把a的值强制转换成char *,比如char *p = (char *)a;再看p+1就只是指向a[0][0]的第二个字节了一样。同样的+1,含义却是不同的。

这样你就应该明白了,虽然*(a+1)的值只能是跟a+1一样,因为它也只能指向a[1][0],但是编译器知道它再增量的话就只需要加上1个int的大小,而不是4个int的大小了。因此*((a+1)+2)实际上是指向a[3],而*(*(a+1)+2)就是*(a[1]+2),也就是a[1][2]了。

#include<stdio.h>

void f(int a[][3])

{

a[1][1]=32;

a[1][2]=348;

}

int main()

{

int a[3][3];

f(a);

int *b;

b=(int *)a;

printf("%d",*(*(a+1)+2));

printf("%d",*(b+5));

scanf("%d");

return 0;

}

a+1代表第二行的首地址,(性质仍为二重数组)因此,a[1][2]可以用*(*(a+1)+2)来访问。

二重数组也可以用一维指针来访问,因为二维数组在内从中是按照从左到右从上到下的顺序排列的。b+5是第五个数的地址,按照二维数组在内存中排列的方法也就是a[1][1].

二维数组还可以用二维指针来访问:

#include<stdio.h>

void f(int a[][3])

{

a[1][1]=32;

a[1][2]=348;

}

int main()

{

int a[3][3];

f(a);

int (*p)[3];

p=a;

printf("%d",p[1][1]);

scanf("%d");

return 0;

}

上面的p表示指向二维数组的指针,该数组每行共计四个元素。

注意与char *a[4]相区别。后者是一个指针数组,每一个数组元素指向char型元素。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: