我最近一直在学习内存分配和指针,我制作了这个程序,要求用户输入矩阵的尺寸并输入它的元素,然后以矩阵格式显示元素。这是我输入的代码。
#include"stdio.h"
#include"stdlib.h"
int *minput();
int *minput(int x,int y)
{
int *M;
M=(int*)malloc(x*y*sizeof(int));
for(int i=0;i<=(x-1);i++)
{
for(int j=0;j<=(y-1);j++)
{
printf("A(%d,%d)=",i+1,j+1);
scanf("%d",(M+i+j));
}
}
return M;
}
int main()
{
int *A,a,b;
printf("Matrix is (m*n)\n\n");
printf("m=");
scanf("%d",&a);
printf("n=");
scanf("%d",&b);
A=minput(a,b);
printf("\n");
for(int k=0;k<=(a-1);k++)
{
for(int l=0;l<=(b-1);l++)
{
printf("%d ",*(A+k+l));
}
printf("\n");
}
free(A);
return 0;
}
然而,当我提供输入时,我得到了这个:
Matrix is (m*n)
m=3
n=3
A(1,1)=1
A(1,2)=2
A(1,3)=3
A(2,1)=4
A(2,2)=5
A(2,3)=6
A(3,1)=7
A(3,2)=8
A(3,3)=9
1 4 7
4 7 8
7 8 9
出了什么问题?我不应该
1 2 3
4 5 6
7 8 9
我的代码中有什么问题吗?
答案 0 :(得分:4)
输出错误,因为*(A+k+l)
不是matrix[k][l]
访问矩阵元素的正确方法。
用于寻址存储为&#34; flat&#34;数组需要将其中一个索引的值乘以相反维度的大小。根据您乘以的索引,您可以获得行主要订单或列主要订单。
您需要对(M+i+j)
函数内的minput
应用相同的修补程序。
// Input
scanf("%d",(M+y*i+j));
...
// Output
printf("%d ",*(A+b*k+l));
将k
乘以b
背后的想法是让k
&#34;计数更快&#34;。对于k
1
的每个增量,您需要跳过整行的b
元素。在您的三列矩阵示例中,如果您想要访问每行的矩阵的A[k][0]
(初始列)中的元素,则您的索引将计为三:0
,{{1} },3
。这是通过将6
乘以k
来实现的。其余部分与通常的指针算法相同:b
等同于*(A+b*k+l)
。
答案 1 :(得分:3)
让我们仔细看看你的一个循环(我使用输入循环,但错误也在输出循环中):
for(int i=0;i<=(x-1);i++)
{
for(int j=0;j<=(y-1);j++)
{
printf("A(%d,%d)=",i+1,j+1);
scanf("%d",(M+i+j));
}
}
外循环的第一次迭代i
为零。然后内循环运行,我们读入(反过来)M+0+0
,M+0+1
和M+0+2
。
然后我们运行外部循环的第二次迭代,其中内部循环将读入M+1+0
,M+1+1
和M+1+2
。
在外循环的这两次迭代中,您将读入M+1
和M+2
两次。那是因为M+0+1
和M+1+0
是相同的元素。
要解决此问题,让我们看一下你在内存中的“矩阵”
+---+---+---+---+---+---+---+---+---+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +---+---+---+---+---+---+---+---+---+
里面的数字是索引。现在,0
,1
和2
是第一行。 3
,4
和5
是第二个。 6
,7
和8
是最后一个。
从这里我们可以看到,为了到达下一行,我们必须添加列数。
从这里我们得到公式line * number_of_columns + column
来获得索引。
将它放在适当位置,您的输入循环可能看起来像
for(int i=0;i<x;i++)
{
for(int j=0;j<y;j++)
{
printf("A(%d,%d)=",i+1,j+1);
scanf("%d",M+i*y+j);
}
}
答案 2 :(得分:1)
要选择写入值的地址,请使用:
M+i+j
让我们尝试使用(i,j)
的几个值:
0,0 -> M + 0
0,1 -> M + 1
0,2 -> M + 2 // So far so good.
1,0 -> M + 1 // not right
1,1 -> M + 2 // not right
... etc.
你想要M + (i * x) + j
。对于x == 3
:
0,0 -> M + 0
0,1 -> M + 1
0,2 -> M + 2
1,0 -> M + 3
1,1 -> M + 4
... etc.
从同一存储器读取时,指针算法也是如此。
此外,由于每次指针只上升一次,你可以得到相同的行为:
int *m = M;
for(int i=0;i<x;i++)
{
for(int j=0;j<=(y-1);j++)
{
printf("A(%d,%d)=",i+1,j+1);
scanf("%d",m);
m++;
}
}
甚至:
for(int i=0; i<x*y; i++) {
printf("A(%d,%d)=", i/3, i%3);
scanf("%d", M + i);
}
其他要点:
在一种方法中,您使用变量x,y,i,j
,在另一种方法中使用a,b,k,l
。我假设你已经这样做了,因为你不想用另一个覆盖一个。但由于范围,这不是一个因素。 x
是函数minput()
的本地函数 - 您可以在x
中拥有另一个main()
,它们将完全相互独立。在这两个地方使用x,y,i,j
,因为它们是维度和循环计数器的“合理”名称。
for(i=0; i<x; i++)
是循环x
次的传统方式。你的i<=(x-1)
是等同的但是混乱和混乱。
现在不鼓励投射malloc()
的结果。 Do I cast the result of malloc?
int *M = malloc(x*y*sizeof(int));