2

I create a 2-dimensional Array in C via malloc like this:

double **x;     
x = malloc(rows * sizeof(double*));
for (n = 0; n < rows; n++){
    x[n] = malloc(columns * sizeof(double));
    memset(x[n], 0, columns * sizeof(double));
}

I also check if malloc failed but for better readibility I posted that version. It actually works fine.

Now I have a function which is qsorting the elements row-wise:

double qsort_row_wise(double points[], int points_count)

Which I can call for a specific row(number 3 / 4th row) with 4+1 columns by:

my_qsort(x[3], 4);

This function is receiving a normal array and is also working well.

Now I want to use this function to qsort a column. That's why I am searching for something like this(which is not working):

my_qsort(x[][3], 4);

x[][3] here means a vector of all elements of the column 3.

If possible I would like to do a "vector"-like operation, not selecting everything step by step(for loop) for best performance.

12
  • 3
    Where did you found vector in C. Commented Dec 1, 2015 at 9:45
  • "a vector of all elements of the column 3". There is no such thing in the language or the standard library. Commented Dec 1, 2015 at 9:49
  • 1
    To add another phrase "matrix": What your 1st code snippet creates isn't a matrix, nor a 2d-array, but one 1d-array of pointers, with each element pointing to a 1d-array of doubles. Such a construct sometimes is called a "scattered" array, as it consists of "number of rows"+1 not necessarily continuous blocks of memory. Commented Dec 1, 2015 at 10:01
  • 1
    @alk: Why isn't that a matrix? The number of entries in each row is the same and the element can be accessed with x[row][col]. Whether the matrix is stored a contiguous 2darray or as flat 1d array with pointer into it or as shown here is an implementation detail. As fas as I know, "matrix" isn't a C term, but a term in the problem domain. Commented Dec 1, 2015 at 10:06
  • 1
    It's a matrix in the mathematical sense, yes. But it isn't by it's "physical" layout. @MOehm Commented Dec 1, 2015 at 10:08

3 Answers 3

4

Since you want a 2D array, it is better to allocate it as a single contiguous block:

double *x = calloc(rows * columns, sizeof(double)); // does zero init

Now you can index using arithmetic, so your my_qsort function should be declared like this:

void my_qsort(double *start, size_t count, size_t stride);

Now to sort row 3 you can do this:

my_qsort(x + 3 * columns, columns, 1);

And to sort column 5 you can do this:

my_qsort(x + 5, rows, columns);

During the sort, the elements you need to access are start[ii * stride], where ii goes from 0 to count. And start of course is simply the first cell in the 2D array that you wish to sort--typically either the leftmost cell in a row or the top cell in a column. It is also possible to use the same function to sort part of a row or column, or to sort an arbitrary "line" through the matrix, e.g. the diagonal of a square matrix:

my_qsort(x, rows, columns + 1);

Having a single allocation to store your 2D array not only makes "strided" operations easier, it is also more efficient, because it reduces the number of allocations, improves spatial locality, and on Linux, increases the chances that the memory will be instantly reclaimed when you free it, because "large" allocations are done via mmap rather than sbrk.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks John! I didnt know this is even faster. Would you also prefer that for huge datasets (>10GB)? Even with much more dimensions?
@TimFinnegan: Generally yes. There are special cases such as "jagged" arrays (rows have varying lengths) or subsetting/combining where the array-of-pointers approach can save space, but you'll know those cases if/when they appear.
Perfect! Thanks again! You helped me quite a lot!
2

Well, you need to create an array the size of how many rows you have since a columns consists of n rows.

double *cols = malloc(nofrows * sizeof(double));

then loop through the 2 dimensional array over the rows and use the column index as a constant:

int whichcolumn = 1;
for (int i = 0; i < rows; i++)
  cols[i] = x[i][whichcolumn];

then pass cols to the qsort function

qsort_row_wise(cols, nofrows);

1 Comment

It's not clear that you are only describing the extraction and sorting part, maybe it would be better to make this more explicit, and maybe also to add the integration part after the sort placeholder. Just an idea...
1

If possible I would like to do a vector-operation, not selecting everything step by step(for loop) for best performance.

This is not possible.

What your 1st code snippet creates isn't a 2D-array, but one 1D-array of pointers, with each element pointing to a 1D-array of doubles. Such a construct sometimes is called a "scattered" array, as it consists of "number of rows"+1 not necessarily continuous blocks of memory.

Concluding from the latter fact, you cannot extract a column, as the elements are distributed throughout the memory and cannot be addressed by a single operation.

3 Comments

Thanks alk! That helped a lot!
@TimFinnegan: You are welcome and I surely appreciate your comment. However as you mention, you were new at SO: Here we say "Thank you!" by up-voting an answer. ;-)
Takes me 4 more reputation points to be allowed to up-vote ;) But I will come back ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.