How to get column of a multidimensional array in C/C++?
Asked Answered
K

10

5
int matrix[9][9],*p;
p=matrix[0]; 

this works and gives first row of matrix, but how to get first column of matrix I've tried p=matrix[][0]; ? Also I don't understand why below code gets compiler error ?

int matrix[9][9],p[9];  // it looks really ugly, byt why it doesn't work ?
p=matrix[0];            // compiler gives "invalid array assigment"

is it because multidimensional arrays are arrays of arrays - and we should interpret matrix[i][j] as j-th element of i-th nested array ?

Kelcey answered 6/3, 2013 at 21:7 Comment(0)
T
16

In C/C++, multidimensional arrays are actually stored as one dimensional arrays (in the memory). Your 2D matrix is stored as a one dimensional array with row-first ordering. That is why getting a column out of it is not easy, and not provided by default. There is no contiguous array in the memory that you can get a pointer to which represents a column of a multidimensional array. See below:

When you do p=matrix[0], you are just getting the pointer to the first element matrix[0][0], and that makes you think that you got the pointer to first row. Actually, it is a pointer to the entire contiguous array that holds matrix, as follows:

matrix[0][0]
matrix[0][1]
matrix[0][2]
.
.
matrix[1][0]
matrix[1][1]
matrix[1][2]
.
.
matrix[8][0]
matrix[8][1]
matrix[8][2]
.
.
matrix[8][8]

As seen above, the elements of any given column are separated by other elements in the corresponding rows.

So, as a side note, with pointer p, you can walk through the entire 81 elements of your matrix if you wanted to.

Testicle answered 6/3, 2013 at 21:11 Comment(3)
"Stored as one-dimensional arrays" is a bit of an odd way to put it. They're just arrays of arrays, so I'll grant that the memory layout is similar, but the semantics are a bit different.Gobbledegook
Semantics are different yes, I was referring to the memory layout. I will re-write that part.Testicle
@Testicle mistake, sorry, they are really next to each other in memoryKelcey
O
8

You can get the first column using a loop like

for(int i = 0; i < 9; i++)
{
    printf("Element %d: %d", i, matrix[i][0]);
}

I think the assignment doesn't work properly because you're trying to assign something's that's not an address to a pointer.

(Sorry this is c code)

Origin answered 6/3, 2013 at 21:13 Comment(3)
sorry but I wanted generic solution, be happy it is your first post +1Kelcey
I believe it should be matrix[i][0] as C and C++ use 0 as the first element.Sides
This is the way to do it. You have to loop through the array to get the elements you want. There's no easy way because, as mentioned, the elements are not located in contiguous memory locations.Bell
P
4

There is no difference between specifying matrix[81] or matrix[9][9]

matrix[r][c] simply means the same as matrix[9*r+c]

There are other containers better suited fort multidimensional arrays like boost::multi_array

http://www.boost.org/doc/libs/1_53_0/libs/multi_array/doc/index.html

Think of the bare array just like allocating a contiguous piece of memory. You, the programmer then has to handle this piece of memory yourself. The bare name of the array, e.g. matrix is a pointer to the first element of this allocated piece of memory. Then *(matrix+1) is the same as matrix[0][1] or matrix[1].

Peal answered 6/3, 2013 at 21:7 Comment(3)
Are you positive that matrix[81] is the same as matrix[9][9]? My understanding is that matrix[9][9] is equivalent to int * matrix[9], which means that it is a container of pointers, not contiguous memory locations.Sides
When you asked I became unsure. So I looked it up and now I am sure. See here for example #7785258Peal
I need to make a small correction to this. From a memory layout point of view there is no difference. But if the compiler has information about the original array declaration there is a difference on how it is interpreted. For example matrix[R][C] can be accessed linearly from a pointer int* mp (int*)matrix, the cast is needed to avoid warnings. You can access rows as int (row_ptr*)[C] = matrix then pointer arithmetic will ensure you move one whole row, e.g. (row_ptr+1) will point to the second row. Also value access has to be **(row_ptr+1). There are however no pointers in memory.Peal
T
2

p is an array of int, matrix[0] is a pointer..

Tetratomic answered 6/3, 2013 at 21:11 Comment(2)
@Kelcey *(matrix[0]) is an int, you can't assign an int to an int arrayTetratomic
now I get it ! I've printed *p and data was correct, but it was only pointer to single intKelcey
K
1

matrix itself is the nearest thing you can get to a column of the array, inasmuch as (matrix + 1)[0][0] is the same as matrix[1][0].

Karyogamy answered 6/3, 2013 at 21:13 Comment(0)
B
1

Here's a program which builds a 10x10 array and prints the second column:

#include <iostream>

using namespace std;

int main()
{
   int aa[10][10];

   for(int i = 0; i<10; i++)
       for(int j = 0; j<10; j++)
           aa[i][j] = i*10+j;
   
   int col = 2;

   // pointer to a length-10 1d array
   int (*p)[10] = (int (*)[10])&(aa[0][col]);

   for(int i =0; i<10; i++)
      cout << *(p[i]) << endl;

   return 0;
}

The difference from aa[row][2] is using a pointer to a length-10 1d int array int (*p)[10], For more context about int (*p)[10], see this answer

p saves the address of 1d array {2, 3, 4, 5, 6, 7, 8, 9, 10, 11} . And p+1 saves the address of 1d array {12, 13, 14, 15, 16, 17, 18, 19, 20, 21}. *(p[1]) or *(*(p+1)) access the first value of 1d array.

Baltic answered 19/12, 2022 at 13:47 Comment(1)
It would be nice to give a brief explanation of how this works / how it solves the problem, and how it's different than existing answers.Embalm
E
1

C++23 solution using drop & stride views, to create a view on the column elements.

#include <ranges>
#include <print>
#include <vector>

int main()
{
    const auto nrColumns = 3;
    const auto nrRows = 3;
    const int matrix[nrRows][nrColumns] = { 1, 2, 3, 11, 22, 33, 111, 222, 333 };
    const auto values = std::span(matrix[0], nrRows * nrColumns);

    const auto columnIndex = 1;
    const auto columnView = values | std::views::drop(columnIndex) | std::views::stride(nrColumns);

    for(const auto& value : columnView)
    {
        std::print("{0}, ", value);
    }
}

Returns 2, 22, 222,

Try it yourself: https://godbolt.org/z/bG5Md4zs7

Evered answered 15/2 at 19:42 Comment(0)
S
0

If you want your matrix to contiguous locations, declare it as a one dimensional array and perform the row and column calculations yourself:

int contiguous_matrix[81];

int& location(int row, int column)
{
  return contiguous_matrix[row * 9 + column];
}

You can also iterate over each column of a row:

typedef void (*Function_Pointer)(int&);

void Column_Iteration(Function_Pointer p_func, int row)
{
  row = row * MAXIMUM_COLUMNS;
  for (unsigned int column = 0; column < 9; ++column)
  {
    p_func(contiguous_matrix[row + column]);
  }
}
Sides answered 6/3, 2013 at 21:45 Comment(0)
C
0

For static declared arrays you can access them like continuous 1D array, p = matrix[0] will give you the 1st column of 1st row. Then the 1D array can be accessed like p[i], *(p+i), or p[current_raw * raw_size + current_column).

The things are getting tricky if a 2D array is represented with **p as it will be interpreted as an array of pointers to 1D arrays.

Cervelat answered 26/7, 2017 at 8:26 Comment(0)
B
0

I don't know if this is a efficient solution but by doing this way I'm able to get the column,

int arr[9][2] = { {2,  57}, {3,  66}, {4,  73}, {5,  76}, {6,  79}, {7,  81}, {8,  90}, {9,  96}, {10, 100}};

int c[18];
int co = 0;
for (auto & i : arr) {
    for (int j : i) {
        c[co++] = j;
    }
}

for (int i = 0; i < co; ++i) {
    if (i % 2 != 0)
        std::cout << c[i] << " ";
}
Berghoff answered 27/7, 2021 at 7:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.