Home > Mobile >  Why do A[i][j] and *((int*)A i * n j) give me different output?
Why do A[i][j] and *((int*)A i * n j) give me different output?

Time:03-04

I am learning C pointers. My instructor mentioned that *((int*)A i * n j) is another way to linearize A[i][j] notation. I tried testing out it with a 2x4 2D array in this main function.

int main()
{
    int** A = new int* [100];
    for (int i = 0; i < 2;   i)
    {
        A[i] = new int[100];
    }

    //assign value
    for (int i = 0; i < 2;   i)
        for (int j = 0; j < 4;   j)
            cin >> *((int*)A   i * 4   j);
            //cin >> A[i][j]; //if I do this instead of the line above, I will get trash values in the output

    for (int i = 0; i < 2;   i)
    {
        for (int j = 0; j < 4;   j)
        {
            cout << *((int*)A   i * 4   j) << " ";
        }
        cout << "\n";
    }
    
    for (int i = 0; i < 2;   i)
       delete[] A[i];
    delete [] A;
}

Sample input:

1 2 3 4
5 6 7 8

I do not understand why when I do

cin >> A[i][j];

then

cout << *((int*)A   i * 4   j) << " ";

It gives me trash values. Does that mean I have to cin >> *((int*)A i * 4 j); if I am gonna cout << *((int*)A i * 4 j) << " ";?

My other question is: Why must I explicitly cast (int*)? Why can't it be (A i * 4 j)?

CodePudding user response:

You drastically misunderstood what the instructor was trying to tell you. The keyword in their description is "notation", but they left out something important (which I'll get to in a minute)

First off, if you're instructor is telling you to do this:

*((int*)A   i * n   j)

take everything they say into question. That cast is neither necessary nor advised, and can literally do nothing but hide bad code. If A is the right type it should be sufficient to do this:

*(A   i*n   j)

and if it isn't the right type, you probably shouldn't be doing this in the first place (which you just found out).

Second, what your instructor did not tell you is that this is useful for establishing a faux multi-dimension array in the linear space of an single dimension array using creative indexing. The key there is single dimension array. The modus operandi is this:

Given the desire to map a 2D space M rows by N columns into a 1D space of M*N elements, you can do this:

constexpr size_t M = 10;
constexpr size_t N = 5;

int A[M*N];
A[row * N   col] = value;

// equivalent to...
*(A   row * N   col) = value;

Note, row should be in the range 0...(M-1), and col should be the range 0..(N-1) inclusively.

This model can be extended to more dimensions. For example, a "3D" mapping, with L denoting slabs, M denoting rows, and N denoting columns:

constexpr size_t L = 10;
constexpr size_t M = 8;
constexpr size_t N = 5;

int A[L*M*N];

A[slab * (M*N)   row * N   col] = value;

// equivalent to...
*(A   slab * (M*N)   row * N   col) = value;

where slab is in the range 0...(L-1), row is in the range 0...(M-1), and finally col is in the range 0...(N-1).

You should see a pattern forming. Any native single-dimension array can be indexed with subscripts manufactured with multi-dimension representation so long as you know the limits of each dimension, and the resulting index does not breach the single-dimension array bed.

Most of the time you will have no need for this, but sometimes it comes in handy, especially in C , as it lacks runtime-VLA support that C delivers.

Therefore, the proper usage of what your instructor tried to tell you would be something like this:

#include <iostream>

int main()
{
    static constexpr size_t M = 2;
    static constexpr size_t N = 4;
    
    int *A = new int[M*N];
    
    //assign value
    for (size_t i = 0; i < M;   i)
    {
        for (size_t j = 0; j < N;   j)
            std::cin >> *(A   i * N   j);
    }

    for (size_t i = 0; i < M;   i)
    {
        for (size_t j = 0; j < N;   j)
            std::cout << *(A   i * N   j) << " ";
        std::cout << "\n";
    }
    
    delete [] A;
}
  • Related