简体   繁体   中英

How do I access the memory using pointers for a multidimensional array?

I have been learning memory allocation and pointers lately, and I made this program which will ask the user to input the dimensions of a matrix and enter it's elements, after which it displays the elements in a matrix format. Here's the code that I've typed.

#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;
}

However when I gave my inputs, I got this:

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

What's wrong? Amn't I supposed to get

1 2 3
4 5 6
7 8 9

Is there anything I had made wrong in my code?

You get incorrect output because *(A+k+l) is not the right way of accessing matrix element at matrix[k][l] .

For addressing a matrix stored as a "flat" array you need to multiply the value of one of the indexes by the size of the opposite dimension. Depending on which index you multiply you get either a row-major order or a column-major order.

You need to apply the same fix to (M+i+j) inside minput function.

// Input
scanf("%d",(M+y*i+j));
...
// Output
printf("%d ",*(A+b*k+l));

The idea behind multiplying k by b is to make k "count faster". For each increment of k by 1 you need to skip an entire row of b elements. In your three-column matrix example, if you would like to access elements at A[k][0] (the initial column) of your matrix for each row, your index would count by three: 0 , 3 , 6 . This is accomplished by multiplying k by b . The rest is the same as the usual pointer arithmetic: *(A+b*k+l) is equivalent to A[b*k+l] .

Demo.

Lets take a close look at one of your loops (I use the input loop, but the error is in the output loop as well):

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));
    }
}

The first iteration of the outer loop, i is zero. Then the inner loop runs, and we read into (in turn) M+0+0 , M+0+1 and M+0+2 .

Then we run the second iteration of the outer loop, where the inner loop will read into M+1+0 , M+1+1 and M+1+2 .

In these two iterations of the outer loop you will read into M+1 and M+2 twice . That's because M+0+1 and M+1+0 are the same element .


To fix this, lets take a look at your "matrix" as it is in memory

+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+---+---+---+---+---+---+---+---+---+

The numbers inside are the indexes. Now, 0 , 1 and 2 is the first row. 3 , 4 and 5 is the second. And 6 , 7 and 8 is the last.

From this we can see that to get to the next line, we have to add the number of columns.

From this we get the formula line * number_of_columns + column to get the index.

Putting it in place, your input loop could look like

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);
    }
}

To choose the address in which to write a value, you use:

M+i+j

Let's try that for a few values of (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.

You want M + (i * x) + j . For x == 3 :

0,0  -> M + 0
0,1  -> M + 1
0,2  -> M + 2  
1,0  -> M + 3  
1,1  -> M + 4  
... etc. 

The same goes for the pointer arithmetic when reading from the same memory.


Furthermore, since the pointer just goes up by one each time, you could get the same behaviour with:

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++;
    }
}

Or even:

for(int i=0; i<x*y; i++) {
   printf("A(%d,%d)=", i/3, i%3);
   scanf("%d", M + i);
}

Other points:

In one method you use variables x,y,i,j , and in another you use a,b,k,l . I assume you've done this because you don't want to overwrite one with the other. But because of scope , that's not a factor. x is local to the function minput() -- you can have another x in main() and they will be completely independent of one another. Use x,y,i,j in both places, because they are the "sensible" names for dimensions and loop counters.

for(i=0; i<x; i++) is the conventional way of looping x times. Your i<=(x-1) is equivalent but messy and confusing.

Casting the result of malloc() is discouraged nowadays. Do I cast the result of malloc?

int *M = malloc(x*y*sizeof(int));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM