关于二级指针和二维数组的问题 15
#include<stdio.h>#defineROWS3#defineCOLS4intsumrows(int**,int,int);intmain(){intar[RO...
#include<stdio.h>
#define ROWS 3
#define COLS 4
int sumrows(int **,int,int);
int main(){
int ar[ROWS][COLS]={
{5,6,7,8},
{1,2,3,4},
{10,2,4,2}
};
sumrows((int **) ar,ROWS,COLS);
printf("%p=========%p",ar,(int **)ar);
return 0;
}
void sumrows(int **ar,int rows,int cols){
int i,j,tal=0;
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
//正确
printf("%d\n",*((int *)ar+i*COLS+j));
//编译通过,访问报错
//printf("%d\n",*(*(ar+i)+j));
}
}
}
这是为什么? 展开
#define ROWS 3
#define COLS 4
int sumrows(int **,int,int);
int main(){
int ar[ROWS][COLS]={
{5,6,7,8},
{1,2,3,4},
{10,2,4,2}
};
sumrows((int **) ar,ROWS,COLS);
printf("%p=========%p",ar,(int **)ar);
return 0;
}
void sumrows(int **ar,int rows,int cols){
int i,j,tal=0;
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
//正确
printf("%d\n",*((int *)ar+i*COLS+j));
//编译通过,访问报错
//printf("%d\n",*(*(ar+i)+j));
}
}
}
这是为什么? 展开
6个回答
展开全部
这个问题,如果手把手的教,恐怕才好理解;不过,这里我会尽量给你讲清楚的。
首先,你要分清楚,数组类型,和指针类型,的区别,然后再看二维的
int a[4]; //a 的类型 int [4], 也就是4个元素的数组类型,它是个地址的概念,首地址,即&a[0]
int *pi; // pi 的类型 int*,整型指针,变量 pi 可以存放个地址
pi = a; //或是 pi = &a[0]; 这里的赋值是可以的;
pi[2] = 321; // 等价于*(pi + 2) = 321; 等价于a[2] = 321;
上面是指针和数组的相同,下面是他们的不同:
sizeof(a): 16 ,4 * 4, 4个int元素,每个元素4个字节;
sizeof(pi): 4,它就是个指针,指针变量都是4个字节;
a + i 等效于 pi + i, 他们都相对于a(或是pi)偏移i个int元素的位置;
下面看二维数组:
int a[3][4];
改写下形式,也许,你就懂了 int (a[3])[4];
a[0], a[1], a[2] //他们都是int [4]的类型,都是4个int元素的首地址,你可以画个图
a // 是 int [3] [4]的类型,它是a[0] , a[1], a[2] ,3个元素的首地址,画个图;
a + 1 就是&a[1] , a + 2 就是&a[2];
*(a + 1 ) + 2 就是 a[1] + 2, 也就是 &a[1][2], 于是 *( *(a + 1) + 2) 就是a[1][2];
现在看二维指针和数组指针,
int * * pi; // pi = a;这里的赋值是不可以的,你懂的,类型不一样,除非你强制转换
int (*pj)[4]; // pj = a; 这里赋值是可以的;数组指针
假设int 4个字节,指针也都是4个字节,而且 pj = pi = 0 (地址十进制)
pi + 1 // 地址是 4,偏移了一个int*的元素,
pj + 1 // 地址是 16,偏移了4 * 4个int元素,
如果,这里的你都看懂了,你问的那个问题,已经不成问题了;
//编译通过,访问报错
//printf("%d\n",*(*(ar+i)+j));
ar 什么类型? int ** 类型,而不是int [3][4]这种类型,也不是int (*)[4]这种类型,
你希望ai + i 他偏向 第 i 行,实际上他不会,它只会,向后偏 i 个位置
我感觉要说的,差不多了,你要是想理解,要么再看看书,画画图,或是问问其他同学,我这上面的也不可能讲的生动形象;祝你好运~~~
首先,你要分清楚,数组类型,和指针类型,的区别,然后再看二维的
int a[4]; //a 的类型 int [4], 也就是4个元素的数组类型,它是个地址的概念,首地址,即&a[0]
int *pi; // pi 的类型 int*,整型指针,变量 pi 可以存放个地址
pi = a; //或是 pi = &a[0]; 这里的赋值是可以的;
pi[2] = 321; // 等价于*(pi + 2) = 321; 等价于a[2] = 321;
上面是指针和数组的相同,下面是他们的不同:
sizeof(a): 16 ,4 * 4, 4个int元素,每个元素4个字节;
sizeof(pi): 4,它就是个指针,指针变量都是4个字节;
a + i 等效于 pi + i, 他们都相对于a(或是pi)偏移i个int元素的位置;
下面看二维数组:
int a[3][4];
改写下形式,也许,你就懂了 int (a[3])[4];
a[0], a[1], a[2] //他们都是int [4]的类型,都是4个int元素的首地址,你可以画个图
a // 是 int [3] [4]的类型,它是a[0] , a[1], a[2] ,3个元素的首地址,画个图;
a + 1 就是&a[1] , a + 2 就是&a[2];
*(a + 1 ) + 2 就是 a[1] + 2, 也就是 &a[1][2], 于是 *( *(a + 1) + 2) 就是a[1][2];
现在看二维指针和数组指针,
int * * pi; // pi = a;这里的赋值是不可以的,你懂的,类型不一样,除非你强制转换
int (*pj)[4]; // pj = a; 这里赋值是可以的;数组指针
假设int 4个字节,指针也都是4个字节,而且 pj = pi = 0 (地址十进制)
pi + 1 // 地址是 4,偏移了一个int*的元素,
pj + 1 // 地址是 16,偏移了4 * 4个int元素,
如果,这里的你都看懂了,你问的那个问题,已经不成问题了;
//编译通过,访问报错
//printf("%d\n",*(*(ar+i)+j));
ar 什么类型? int ** 类型,而不是int [3][4]这种类型,也不是int (*)[4]这种类型,
你希望ai + i 他偏向 第 i 行,实际上他不会,它只会,向后偏 i 个位置
我感觉要说的,差不多了,你要是想理解,要么再看看书,画画图,或是问问其他同学,我这上面的也不可能讲的生动形象;祝你好运~~~
展开全部
本程序一共两个错误
1.你形参ar定义的是一个int**的类型,实参ar传递进来表示里面只能存放“指向数组首地址的指针变量”的地址,你将这个地址+1,只表示将这个指针变量(用来存放数组首地址)自身的地址+1,并不表示指向数组下一个地址。(这种操作导致了内存越界)。而你 printf("%d\n",*((int *)ar+i*COLS+j));这句话正确是因为你对ar进行了强制类型转换,将int**转换成了int*,而数组的空间是连续的,所以int*+1是允许的。举个最简单的例子,你一看就懂了。
# include <stdio.h>
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
int * p = &a[0];
int ** q = &p;
printf("%d", **(q+1));
return 0;
}
这个程序是错误的,因为**(q+1)与*(p+1)并不等价,也就是说与p紧邻的下一块地址不一定存着a数组a[1]的地址。**(q+1)指向了一块系统未分配的内存,从而导致内存越界。
2.第二个错误,难道没有人看出来吗,真不知道你咋编译成功的。函数声明你写的是int sumrows,而下面的又写的是void sumrows,显然不一致啊。
希望给你说明白了。要给分哦
1.你形参ar定义的是一个int**的类型,实参ar传递进来表示里面只能存放“指向数组首地址的指针变量”的地址,你将这个地址+1,只表示将这个指针变量(用来存放数组首地址)自身的地址+1,并不表示指向数组下一个地址。(这种操作导致了内存越界)。而你 printf("%d\n",*((int *)ar+i*COLS+j));这句话正确是因为你对ar进行了强制类型转换,将int**转换成了int*,而数组的空间是连续的,所以int*+1是允许的。举个最简单的例子,你一看就懂了。
# include <stdio.h>
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
int * p = &a[0];
int ** q = &p;
printf("%d", **(q+1));
return 0;
}
这个程序是错误的,因为**(q+1)与*(p+1)并不等价,也就是说与p紧邻的下一块地址不一定存着a数组a[1]的地址。**(q+1)指向了一块系统未分配的内存,从而导致内存越界。
2.第二个错误,难道没有人看出来吗,真不知道你咋编译成功的。函数声明你写的是int sumrows,而下面的又写的是void sumrows,显然不一致啊。
希望给你说明白了。要给分哦
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
c/c++里面函数的传递会将数组退化为指针,所以int**传给sumrows之后,就几乎变成一个int*了,
*(ar+0)的值直接为5,所以不能进行二元访问。
你可以先在外面循环遍历,将取得的值在传入函数,这样一样可以进行你的试验,呵呵
*(ar+0)的值直接为5,所以不能进行二元访问。
你可以先在外面循环遍历,将取得的值在传入函数,这样一样可以进行你的试验,呵呵
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
二维数组即a[i][j],如a[1][1]是第一行第一列的那个数;指针只是指向了这个数所在的地址,没有具体指出那个数.他们的区别 一个是指向具体的数,一个是执行了该数所在的地址
本回答被网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
数组名ar只是一个地址,
*(*(ar+i)+j));
它里面的 *(ar+i)是取得ar+i地址所对应的值,并非二维数组合法地址,此值再加j实际上是一个普通的值,而并非数组地址,所以才会出错。
*(*(ar+i)+j));
它里面的 *(ar+i)是取得ar+i地址所对应的值,并非二维数组合法地址,此值再加j实际上是一个普通的值,而并非数组地址,所以才会出错。
本回答被网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询