主题:【求助】向各位高手请教一个c语言中数组与指针的问题 -- 数值分析
无论是多少维德的数组,其数组名都是指针,而不是指针的指针。
比如说你的a,尽管是二位数组,其数组名其实只是指向数组首地址的指针。具体这个数组多少维,每一维的长度是多少,那是另外的信息。
所以如果编译器允许,你的函数应该写为
void f1(int a[][5]),表明这是一个两维,最低维长度为5的数组。可以直接引用。
如果编译器不支持,可以写为
void f1(int* a)
然而你必须知道这是个几维的数组,每维的长度是多少。
而引用a[i][j]的时候就写为
a[i*5+j]
如果都不知道,就写为
void f1(int* a, int dimension, int* dimensionLength)
——————————————————————
int** a是指向指针的指针。通常用于指针数组(比如说链表之类),不可以用于多维数组
dimension 表明这个数组是几维的,
dimensionLength表明每一维的长度。
比如int a[3][4],这里的a其实是一个指向数组的指针。如果要和变量对应的话a应该是和
int (*pa)[4];
里的pa相同类型的一个常量。
也不是int **
应该是int (*pa)[4]中的pa这种类型。
也就是说a和pa都是一个指向含有4个元素的int数组的指针。只不过a是常量。
pa++的话指针应该向下移动4*4byte。
当然,此时a里存的地址和a[0][0]元素的地址是相同的。只不过a+1不是a[0][1]的地址,而是和a[1][0]的地址相同。还是指针的“基类型”的问题。
比如
int *p = (int*)a;
应该是可以的。
指针说白了就是一个里面放着地址的变量。啥地址不是地址啊
此时a应该是一个“指向数组的指针”类型的常量。
int *pa[4]
vs
int (*pa)[4]
我觉得楼主的困惑可能是这两个的区别。
只不过它知道(或者说它认为自己知道)自己要指向的是个什么类型的玩意儿。(其实确切的说是编译器认为)
还是先确定下角色吧,这样好说。
路人甲:int a[3][4];
路人乙:int *p;
a知道每行的宽度,是因为您交待它了,它的“基类型”是一个有4个元素的int数组。也就是说这时它就认为自己指的东西有4*4byte那么长。所以您让他+1,他自己就找下一个了。也就是给自己所存的数(就是地址)加上了个16。所以您看到a+1就是a[1]也就是数组第二行的地址。
但是
p=(int *)a
的时候,您交待a了,这会儿你不能跟p说你是个数组指针,要这么说它就不跟你玩儿了。你就跟他说你是个int指针。反正都是地址,那家伙瞧不出来
于是,p就从了……
我以前做得项目用的基本都是C。已经有两年多没有碰这种指针运用了。
如果我记得没错,以int* 方式传过去的,都可以向我说的那样用。a+1这种我还没有正经用过。
肯定不对,但不知道你迷糊在什么地方。C原则上没有多维数组的概念,任何多维数组实际上都是一个更长的一维数组。你这个地址传递当然是对的,C只管把地址传过去不管你传的是什么地址,自己保证正确。问题在于即使主函数里面定义了个a[m][n],函数f1里面并不知道n,你也无法重新定义,a[0][0]也许还能知道(没把握),其他的统统不知道是何物。
C原则上是不推荐多维数组的,部分原因就在于会引起你这样的混乱。替代方法简单,开始就定义为一维数组a[m*n],使用的时候也按照这个方法使用即可。至于带两个星号的比如int **x,这个是多级间指,**x才是int数字,而多维数组的a,不管多少维,即使是int a[i][j][k][l][m][n],*a就是数字。二者完全不一样。(int **)a等于是进行了强制类型转换,把一个int指针变成了一个指向指针的指针。
根本上,我还是建议你在C不要用多维数组,一干二净。
在c里,默认多维数组结构,实际上一通过一个内存片实现的。a[][],指向一个内存片,a指向首地址,从首地址开始,里面顺序存着a[0][0],a[0][1].....a[1][0]a[1][1]...等等。。
int**类型指向一个地址类型,which指向一个int。
所以a[][]定义里a是个指向int的指针,而不是指向一个int指针的指针。
----------------------------------
另外一种常用的动态实现多维数组的方法是这样子的。
假如要实现一个5*5的二维数组,
int ** a = (int **) malloc(5*sizeof(int *));
for (int i = 0;i<5;i++) {
a[i] = (int *) malloc (5*sizeof(int));
}
之后就可以用a[1][2]的形式访问多维数组,传递的时候传递int**类型。但要注意越界和释放问题。
a+1这种用法只是在讨论理论的时候提提,一般不会用。太乱。
其实指针这东西,只需要搞清两件事情:
1.指针就是个很普通的变量,只不过它里面放的不是具体的数据,而是一个地址。您要是*它,它就按着自己记下的地址去提货。
2.指针知道自己的“基类型”是个什么类型。它永远认为自己记的那个地址里放的就是基类型的数据。这点很重要,因为:
2.1 其实指针里放的只是一个起始地址,您*它的时候,它就按照自己的“基类型”的长度从它记的地址开始去取那么长的内存数据。并且将这些二进制按“基类型”的方式解读:这么多位0和1到底记录的是一个整数,还是一个数组,还是一个浮点数。
2.2 您要给指针+n,它就认为是要它指向后面第n个“基类型”数据。所以它会把自己记的地址加上个
n*基类型长度
这个第一点,只要是使用指针的都知道,没啥可说的。所以我们要用一个指针的时候,需要注意的就是要时刻记得这个指针的“基类型”是什么,这个影响到指针的大部分行为特点。
数组和指针,就一句话。数组名是一个“基类型”是数组元素类型的指针常量。可以向指针一样用,但不能改变其取值。
多维数组也是一句话。多维数组是“数组的数组”。
其实我认为C语言里的指针和数组就这么点儿东西。
希望对您有帮助。理解不对的地方也请大牛们指正。
请教老兄一下,这样弄出来的“二维数组”不是在栈里而是在堆里吧?
内存里这些int也是5个一伙5个一伙散布的,不一定是25个挤在一起的吧?