I am writing a C-program where I need 2D-arrays (dynamically allocated) with negative indices or where the index does not start at zero. So for an array[i][j] the row-index i should take values from e.g. 1 to 3 and the column-index j should take values from e.g. -1 to 9.
For this purpose I created the following program, here the variable columns_start is set to zero, so just the row-index is shifted and this works really fine.
But when I assign other values than zero to the variable columns_start, I get the message (from valgrind) that the command "free(array[i]);" is invalid.
So my questions are:
Why it is invalid to free the memory that I allocated just before?
How do I have to modify my program to shift the column-index?
Thank you for your help.
#include <stdio.h>
#include <stdlib.h>
main()
{
int **array, **array2;
int rows_end, rows_start, columns_end, columns_start, i, j;
rows_start = 1;
rows_end = 3;
columns_start = 0;
columns_end = 9;
array = malloc((rows_end-rows_start+1) * sizeof(int *));
for(i = 0; i <= (rows_end-rows_start); i++) {
array[i] = malloc((columns_end-columns_start+1) * sizeof(int));
}
array2 = array-rows_start; //shifting row-index
for(i = rows_start; i <= rows_end; i++) {
array2[i] = array[i-rows_start]-columns_start; //shifting column-index
}
for(i = rows_start; i <= rows_end; i++) {
for(j = columns_start; j <= columns_end; j++) {
array2[i][j] = i+j; //writing stuff into array
printf("%i %i %d\n",i, j, array2[i][j]);
}
}
for(i = 0; i <= (rows_end-rows_start); i++) {
free(array[i]);
}
free(array);
}
When you shift column indexes, you assign new values to original array of columns: in
array2[i] = array[i-rows_start]-columns_start;
array2[i] and array[i=rows_start] are the same memory cell as array2 is initialized with array-rows_start.
So deallocation of memory requires reverse shift. Try the following:
free(array[i] + columns_start);
IMHO, such modification of array indexes gives no benefit, while complicating program logic and leading to errors. Try to modify indexes on the fly in single loop.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int a[] = { -1, 41, 42, 43 };
int *b;//you will always read the data via this pointer
b = &a[1];// 1 is becoming the "zero pivot"
printf("zero: %d\n", b[0]);
printf("-1: %d\n", b[-1]);
return EXIT_SUCCESS;
}
If you don't need just a contiguous block, then you may be better off with hash tables instead.
As far as I can see, your free and malloc looks good. But your shifting doesn't make sense. Why don't you just add an offset in your array instead of using array2:
int maxNegValue = 10;
int myNegValue = -6;
array[x][myNegValue+maxNegValue] = ...;
this way, you're always in the positive range.
For malloc: you acquire (maxNegValue + maxPosValue) * sizeof(...)
Ok I understand now, that you need free(array.. + offset); even using your shifting stuff.. that's probably not what you want. If you don't need a very fast implementation I'd suggest to use a struct containing the offset and an array. Then create a function having this struct and x/y as arguments to allow access to the array.
I don't know why valgrind would complain about that free statement, but there seems to be a lot of pointer juggling going on so it doesn't surprise me that you get this problem in the first place. For instance, one thing which caught my eye is:
array2 = array-rows_start;
This will make array2[0] dereference memory which you didn't allocate. I fear it's just a matter of time until you get the offset calcuations wrong and run into this problem.
One one comment you wrote
but im my program I need a lot of these arrays with all different beginning indices, so I hope to find a more elegant solution instead of defining two offsets for every array.
I think I'd hide all this in a matrix helper struct (+ functions) so that you don't have to clutter your code with all the offsets. Consider this in some matrix.h header:
struct matrix; /* opaque type */
/* Allocates a matrix with the given dimensions, sample invocation might be:
*
* struct matrix *m;
* matrix_alloc( &m, -2, 14, -9, 33 );
*/
void matrix_alloc( struct matrix **m, int minRow, int maxRow, int minCol, int maxCol );
/* Releases resources allocated by the given matrix, e.g.:
*
* struct matrix *m;
* ...
* matrix_free( m );
*/
void matrix_free( struct matrix *m );
/* Get/Set the value of some elment in the matrix; takes logicaly (potentially negative)
* coordinates and translates them to zero-based coordinates internally, e.g.:
*
* struct matrix *m;
* ...
* int val = matrix_get( m, 9, -7 );
*/
int matrix_get( struct matrix *m, int row, int col );
void matrix_set( struct matrix *m, int row, int col, int val );
And here's how an implementation might look like (this would be matrix.c):
struct matrix {
int minRow, maxRow, minCol, maxCol;
int **elem;
};
void matrix_alloc( struct matrix **m, int minCol, int maxCol, int minRow, int maxRow ) {
int numRows = maxRow - minRow;
int numCols = maxCol - minCol;
*m = malloc( sizeof( struct matrix ) );
*elem = malloc( numRows * sizeof( *elem ) );
for ( int i = 0; i < numRows; ++i )
*elem = malloc( numCols * sizeof( int ) );
/* setting other fields of the matrix omitted for brevity */
}
void matrix_free( struct matrix *m ) {
/* omitted for brevity */
}
int matrix_get( struct matrix *m, int col, int row ) {
return m->elem[row - m->minRow][col - m->minCol];
}
void matrix_set( struct matrix *m, int col, int row, int val ) {
m->elem[row - m->minRow][col - m->minCol] = val;
}
This way you only need to get this stuff right once, in a central place. The rest of your program doesn't have to deal with raw arrays but rather the struct matrix type.
Related
I am getting some weird pointer-related errors that I do not understand how can happen and how to solve it. Since I am new to C any good coding practice advice is also appreciated.
typedef struct matrix {
int n;
int m;
int **data;
int *inverses;
} Matrix;
Matrix m_new(int n, int m, int *inverses) {
int **data = malloc(n);
for (int k = 0; k < n; k++) {
int *row = malloc(m + 1);
*row++ = k;
*(data+k) = row;
// print_arr(*data); - introduced for debugging purposes
}
Matrix mat = {
.n = n,
.m = m,
.data = data,
.inverses = inverses,
};
return mat;
}
void print_arr(int *arr) {
int len = *(arr-1);
printf("len: %d\n", len);
}
Here, I am going to use this matrix for Gaussian Elimination over the integers mod some number, that's why I have the inverses array, and I use int **, so that I can swap rows easily later. For arrays represented as int * I use the -1th entry to store the length of the array. I got some weird bugs, so I wrote a small function to get the length of an array (print_arr) and check the first array in data. I got the following(for n=m=5):
len: 0
len: 0
len: 0
len: 0
len: -1219680380
Which I find really weird, because it seems like that something is changing in the last iteration, but I don't know why.
Your allocations are too small. You need to multiply the number of elements by the size of the elements to compute how much memory to allocate:
int **data = malloc(n * sizeof (int *));
int *row = malloc((m + 1) * sizeof (int));
With your current code, you overflow your too-small buffers and cause undefined behavior.
I'm working on a C implementation for Conway's game of life, I have been asked to use the following header:
#ifndef game_of_life_h
#define game_of_life_h
#include <stdio.h>
#include <stdlib.h>
// a structure containing a square board for the game and its size
typedef struct gol{
int **board;
size_t size;
} gol;
// dynamically creates a struct gol of size 20 and returns a pointer to it
gol* create_default_gol();
// creates dynamically a struct gol of a specified size and returns a pointer to it.
gol* create_gol(size_t size);
// destroy gol structures
void destroy_gol(gol* g);
// the board of 'g' is set to 'b'. You do not need to check if 'b' has a proper size and values
void set_pattern(gol* g, int** b);
// using rules of the game of life, the function sets next pattern to the g->board
void next_pattern(gol* g);
/* returns sum of all the neighbours of the cell g->board[i][j]. The function is an auxiliary
function and should be used in the following function. */
int neighbour_sum(gol* g, int i, int j);
// prints the current pattern of the g-board on the screen
void print(gol* g);
#endif
I have added the comments to help out with an explanation of what each bit is.
gol.board is a 2-level integer array, containing x and y coordinates, ie board[x][y], each coordinate can either be a 1 (alive) or 0 (dead).
This was all a bit of background information, I'm trying to write my first function create_default_gol() that will return a pointer to a gol instance, with a 20x20 board.
I then attempt to go through each coordinate through the 20x20 board and set it to 0, I am getting a Segmentation fault (core dumped) when running this program.
The below code is my c file containing the core code, and the main() function:
#include "game_of_life.h"
int main()
{
// Create a 20x20 game
gol* g_temp = create_default_gol();
int x,y;
for (x = 0; x < 20; x++)
{
for (y = 0; y < 20; y++)
{
g_temp->board[x][y] = 0;
}
}
free(g_temp);
}
// return a pointer to a 20x20 game of life
gol* create_default_gol()
{
gol* g_rtn = malloc(sizeof(*g_rtn) + (sizeof(int) * 20 * 20));
return g_rtn;
}
This is the first feature I'd like to implement, being able to generate a 20x20 board with 0's (dead) state for every coordinate.
Please feel free to criticise my code, I'm looking to determine why I'm getting the segmentation fault, and if I'm allocating memory properly in the create_default_gol() function.
Thanks!
The type int **board; means that board must contain an array of pointers, each of which points to the start of each row. Your existing allocation omits this, and just allocates *g_rtn plus the ints in the board.
The canonical way to allocate your board, supposing that you must stick to the type int **board;, is:
gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn->size = size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
for (int i = 0; i < size; ++i)
g_rtn->board[i] = malloc(size * sizeof **g_rtn->board);
This code involves a lot of small malloc chunks. You could condense the board rows and columns into a single allocation, but then you also need to set up pointers to the start of each row, because board must be an array of pointers to int.
Another issue with this approach is alignment. It's guaranteed that a malloc result is aligned for any type; however it is possible that int has stricter alignment requirements than int *. My following code assumes that it doesn't; if you want to be portable then you could add in some compile-time checks (or run it and see if it aborts!).
The amount of memory required is the sum of the last two mallocs:
g_rtn->board = malloc( size * size * sizeof **g_rtn->board
+ size * sizeof *g_rtn->board );
Then the first row will start after the end of the row-pointers (a cast is necessary because we are converting int ** to int *, and using void * means we don't have to repeat the word int):
g_rtn->board[0] = (void *) (g_rtn->board + size);
And the other rows each have size ints in them:
for (int i = 1; i < size; ++i)
g_rtn->board[i] = g_rtn->board[i-1] + size;
Note that this is a whole lot more complicated than just using a 1-D array and doing arithmetic for the offsets, but it was stipulated that you must have two levels of indirection to access the board.
Also this is more complicated than the "canonical" version. In this version we are trading code complexity for the benefit of having a reduced number of mallocs. If your program typically only allocates one board, or a small number of boards, then perhaps this trade-off is not worth it and the canonical version would give you fewer headaches.
Finally - it would be possible to allocate both *g_rtn and the board in the single malloc, as you attempted to do in your question. However my advice (based on experience) is that it is simpler to keep the board separate. It makes your code clearer, and your object easier to use and make changes to, if the board is a separate allocation to the game object.
create_default_gol() misses to initialise board, so applying the [] operator to it (in main() ) the program accesses "invaid" memory and with ethis provokes undefined behaviour.
Although enough memory is allocated, the code still needs to make board point to the memory by doing
gol->board = ((char*) gol) + sizeof(*gol);
Update
As pointed out by Matt McNabb's comment board points to an array of pointers to int, so initialisation is more complicate:
gol * g_rtn = malloc(sizeof(*g_rtn) + 20 * sizeof(*gol->board));
g_rtn->board = ((char*) gol) + sizeof(*gol);
for (size_t i = 0; i<20; ++i)
{
g_rtn->board[i] = malloc(20 * sizeof(*g_rtn->board[i])
}
Also the code misses to set gol's member size. From what you tell us it is not clear whether it shall hold the nuber of bytes, rows/columns or fields.
Also^2 coding "magic numbers" like 20 is bad habit.
Also^3 create_default_gol does not specify any parameters, which explictily allows any numberm and not none as you might perhaps have expected.
All in all I'd code create_default_gol() like this:
gol * create_default_gol(const size_t rows, const size_t columns)
{
size_t size_rows = rows * sizeof(*g_rtn->board));
size_t size_column = columns * sizeof(**g_rtn->board));
gol * g_rtn = malloc(sizeof(*g_rtn) + size_rows);
g_rtn->board = ((char*) gol) + sizeof(*gol);
if (NULL ! = g_rtn)
{
for (size_t i = 0; i<columns; ++i)
{
g_rtn->board[i] = malloc(size_columns); /* TODO: Add error checking here. */
}
g_rtn->size = size_rows * size_columns; /* Or what ever this attribute is meant for. */
}
return g_rtn;
}
gol* create_default_gol()
{
int **a,i;
a = (int**)malloc(20 * sizeof(int *));
for (i = 0; i < 20; i++)
a[i] = (int*)malloc(20 * sizeof(int));
gol* g_rtn = (gol*)malloc(sizeof(*g_rtn));
g_rtn->board = a;
return g_rtn;
}
int main()
{
// Create a 20x20 game
gol* g_temp = create_default_gol();
int x,y;
for (x = 0; x < 20; x++)
{
for (y = 0; y < 20; y++)
{
g_temp->board[x][y] = 10;
}
}
for(x=0;x<20;x++)
free(g_temp->board[x]);
free(g_temp->board);
free(g_temp);
}
main (void)
{
gol* gameOfLife;
gameOfLife = create_default_gol();
free(gameOfLife);
}
gol* create_default_gol()
{
int size = 20;
gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn = malloc(sizeof g_rtn);
g_rtn->size = size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
int i, b;
for (i = 0; i < size; ++i){
g_rtn->board[i] = malloc(sizeof (int) * size);
for(b=0;b<size;b++){
g_rtn->board[i][b] = 0;
}
}
return g_rtn;
}
Alternatively, since you also need to add a create_gol(size_t new_size) of custom size, you could also write it as the following.
main (void)
{
gol* gameOfLife;
gameOfLife = create_default_gol();
free(gameOfLife);
}
gol* create_default_gol()
{
size_t size = 20;
return create_gol(size);
}
gol* create_gol(size_t new_size)
{
gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn = malloc(sizeof g_rtn);
g_rtn->size = new_size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
int i, b;
for (i = 0; i < size; ++i){
g_rtn->board[i] = malloc(sizeof (int) * size);
for(b=0;b<size;b++){
g_rtn->board[i][b] = 0;
}
}
return g_rtn;
}
Doing this just minimizes the amount of code needed.
I'm trying to make a struct that generates a random matrix and am getting "error: expected â=â, â,â, â;â, âasmâ or â_attribute_â before âmatrixâ" when compiling. How can I get this to work effectively and efficiently?
I guess expected errors usually are caused by typos but I don't see any.
I'm very new to C so pointers and malloc are quite foreign to me. I really appreciate your help.
/* It's called RandomMatrixMaker.c */
#include <stdio.h>
#include <stdlib.h>
typdef struct {
char* name;
int MID;
int MRows;
int MCols;
long[][]* MSpace;
} matrix;
matrix makeRIDMatrix(char* name, int MID, int MRows, int MCols) {
matrix m;
static int i, j, r;
m.name = name;
m.MID = MID;
m.MRows = MRows;
m.MCols = MCols;
for (i=0; i<m.MRows; i++) {
for (j=0; i<m.MCols; j++) {
r = random(101);
*(m.MSpace[i][j]) = r;
}
}
return m;
}
int main(void) {
makeRIDMatrix("test", 1, 10, 10);
return 0;
}
There is indeed a typo. You misspelled typedef:
typdef struct {
should be:
typedef struct {
EDIT:
Also, there's no reason to use static here:
static int i, j, r;
You can just get rid of the static modifier.
int i, j, r;
As another poster mentioned, there's a typo, but even with that corrected, it wouldn't compile, due to the definition of matrix.MSpace.
Let's begin in makeRIDMatrix(). You've declared an automatic (stack) variable of type "matrix". At the end of the function, you return that object. Whilst this is permissible, it's not advisable. If the struct is large, you will be copying a lot of data unnecessarily. Better to pass a pointer to a matrix into makeRIDMatrix(), and have makeRIDMatrix() fill in the contents.
The test in the inner loop is against i, but should be against j.
Next, let's look at the definition of "matrix". The definition of "MSpace" is a mess, and wouldn't even compile. Even if it did, because you haven't defined the length of a row, the compiler would not be able to calcuate the offset to any given item in the array. You want a two-dimensional array without giving the row length, but you can't do that in C. You can in other languages, but not C.
There's a lot more I could point out, but I'd be missing the real point. The real point is this:
C Is Not Java.
(It's also not one of the interpreted languages such as JavaScript, PHP, Python, Ruby and so on.)
You don't get dynamically-expanding arrays; you don't get automatic allocation of memory; you don't get garbage collection of unreferenced memory.
What you need is something more like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
char* name;
int MID;
unsigned int MRows;
unsigned int MCols;
long *MSpace;
} matrix;
void makeRIDMatrix(matrix *pmx, char* name, int MID,
unsigned int MRows, unsigned int MCols) {
int i, j;
long *MSpace = malloc(sizeof(*MSpace)*MRows*MCols);
if (MSpace == NULL) {
return;
}
pmx->name = name;
pmx->MID = MID;
pmx->MRows = MRows;
pmx->MCols = MCols;
pmx->MSpace = MSpace;
srandom((unsigned int)time(NULL));
for (i=0; i<MRows; i++) {
for (j=0; i<MCols; j++) {
long int r = random() % 101L;
*(MSpace++) = r;
}
}
}
inline long * item_addr(const matrix *pmx,
unsigned int row, unsigned int col) {
if (pmx == NULL || pmx->MSpace == NULL
|| row >= pmx->MRows || col >= pmx->MCols) {
return NULL;
}
return &(pmx->MSpace[row * pmx->MCols + col]);
}
long get_item(const matrix *pmx, unsigned int row, unsigned int col) {
long *addr = item_addr(pmx, row, col);
return addr == NULL ? 0L : *addr;
}
void set_item(matrix *pmx,
unsigned int row, unsigned int col,
long val) {
long *addr = item_addr(pmx, row, col);
if (addr != NULL) {
*addr = val;
}
}
int main(void) {
matrix m;
makeRIDMatrix(&m, "test", 1, 10, 10);
return 0;
}
Note a few things here. Firstly, for efficiency, I fill the array as if it were one-dimensional. All subsequent get/set of array items should be done through the getter/setter functions, for safety.
Secondly, a hidden nasty: makeRIDMatrix() has used malloc() to allocate the memory - but it's going to be job of the calling function (or its successors) explciitly to free() the allocated pointer when it's finished with.
Thirdly, I've changed the rows/cols variables to unsigned int - there's little sense in definining an array with negative indices!
Fourthly: little error checking. For example, makeRIDMatrix() neither knows nor cares whether the parameter values are sensible (e.g. the matrix pointer isn't checked for NULLness). That's an exercise for the student.
Fifthly, I've fixed your random number usage - after a fashion. Another exercise for the student: why is the way I did it not good practice?
However - all of this is moot. You need to get yourself a good C textbook, or a good online course, and work through the examples. The code you've given here shows that you're punching above your weight at the moment, and you need to develop some more C muscles before going into that ring!
In relation to your question about "variable sized arrays", you could have something like:
/* can stick this into your struct, this is just an example */
size_t rows, cols;
long **matrix;
/* set the values of rows, cols */
/* create the "array" of rows (array of pointers to longs) */
matrix = (long**)malloc(rows * sizeof(long*));
/* create the array of columns (array of longs at each row) */
for (i = 0; i < rows; i++)
matrix[i] = (long*)malloc(cols * sizeof(long));
/* ... */
/* free the memory at the end */
for (i = 0; i < rows; i++)
free(matrix[i]);
free(matrix);
Then you can just access the dynamically allocated matrix similar to any other array of arrays.
ie. to set element at the first row (row 0) and fourth column (column 3) to 5:
matrix[0][3] = 5;
I have an array declared as a member of a struct in C. The array is declared as:
char mValue[MAXROWS][MAXCOLUMNS];
where MAXROWS and MAXROWS are 300. Is there a better way to do this? I mean, should I declare these as pointers instead?
Thanks!
As the previous poster suggested, a good way is to create a linear array and then "convert it to 2D". Many times, caching the 2D pointers greatly increases the speed of programs that use this array, like so:
mystruct *p = (mystruct*)calloc(ROWS * COLUMNS, sizeof(mystruct));
mystruct **p2 = (mystruct**)calloc(ROWS, sizeof(mystruct*));
for (int i = 0; i < ROWS; i++)
p2[i] = p + i*COLUMNS;
Then, you can simply access a 2D element with:
p2[row][column] = foo;
If all your rows are the same size, you should use a 1D array with the rows stored in sequence:
ABCDE
FGHIJ ---> ABCDEFGHIJKLMNO
KLMNO
The element at row i, column j will be at index i * ROW_LENGTH + j in the 1D array.
You can allocate the array using malloc(ROW_LENGTH * NUM_ROWS).
Another technique is to create a linear array and then convert it to 2d:
char *p = malloc(ROWS * COLUMNS);
// To access x, y
// This is in row-major ordr
*(p + (x * COLUMNS) + y);
I find that, for this kind of code, its better to create helper functions for accessing the elements. Depending on your profiling data, it may make sense to turn these into macros, but be extra careful.
#include <stdio.h> /* For printf */
/* This is the bit that would go in a header, like char2darray.h */
#include <stdlib.h> /* For calloc */
#include <assert.h> /* For assert */
struct Char2DArray
{
int rows;
int columns;
char *values;
};
/* This is the bit that would go in a source file, like char2darray.c */
void C2DA_initialize(struct Char2DArray *array, int rows, int columns)
{
assert(array != 0);
array->values = calloc(rows * columns, sizeof(char));
array->rows = rows;
array->columns = columns;
}
void C2DA_set(struct Char2DArray *array, int row, int column, int value)
{
assert(array != 0);
assert(array->values != 0);
assert(row < array->rows);
assert(row >= 0);
assert(column < array->columns);
assert(column >= 0);
array->values[(row * array->rows) + column] = value;
}
char C2DA_get(struct Char2DArray *array, int row, int column)
{
assert(array != 0);
assert(array->values != 0);
assert(row < array->rows);
assert(row >= 0);
assert(column < array->columns);
assert(column >= 0);
return array->values[(row * array->rows) + column];
}
void C2DA_free(struct Char2DArray *array)
{
free(array->values);
array->values = 0;
}
/* Here's a main.c to use it */
int main()
{
struct Char2DArray a;
C2DA_initialize(&a, 16, 16);
unsigned char c = 0;
int x, y;
for (x=0; x<16; x++) {
for (y=0; y<16; y++) {
C2DA_set(&a, x, y, (char)c);
c++;
}
}
printf("Character with hex value 0x55 is %c\n", C2DA_get(&a, 5, 5));
C2DA_free(&a);
return 0;
}
If the array needs to have a dynamic size, then you either need to make it a pointer or make the array the last member of the struct and play games when allocating the structure size.
Relevant comp.lang.c FAQ entries:
I came across some code that declared a structure like this...
How can I dynamically allocate a multidimensional array?
I found that changing my approach was very useful when faced with a similar problem.
A vector of vectors filled the same task, avoided memory allocation obstacles, and kept the same familiar shorthand. There may be other pitfalls, but I have not encountered them yet.
//Declaration of mValues, undefined size:
std::vector< std::vector<char> > mValues;
//Filling of mValues:
int max_x = 100 ;
int max_y = 100 ;
char char_foo = 'a';
for ( int x = 0; x <= max_x; ++x ) {
vector<char> temp;
for ( int y = 0; y <= max_y; ++y ) {
temp.push_back( char_foo );
}
mValues.push_back( temp );
}
// Referencing with familiar index notation:
mValues[a][b]; //The a-th row's b-th element
If you are struggling with arrays, but strongly desire the familiar indexing language, I have found this to be a good alternative.
Note that indexing order A then B is going to be critical for memory usage when recalling this data. Failure to call the information in an A,B order will be deeply problematic if performance is an issue.
Is there an easy way to reference a column in a 2-D array as a separate 1-D array in plain old C (not C++ or C#)? It's easy to do this for a row. Asssume I have 2 functions:
double doSomethingWithARow( double theRow[3] );
double doSomethingWithACol( double theCol[100] );
Then, I might use the first one like this:
double matrix[100][3];
double result;
// pass a single row to a function as an array
// this essentially passes the 3-element array at row 48 to the function
for( int i=0; i < 100; i++ )
{
result = doSomethingWithARow( matrix[i] );
}
What I want it a way to access a column easily.
for( int j=0; j < 3; j++ )
{
result = doSomethingWithACol( ??????????? );
}
The only thing I've come up with so far is transforming the matrix to swap the rows with the columns. But this code is supposed to be as efficient as possible in terms of memory and speed. With all of the convoluted ways to reference pointers in C, it seems like there should be a way to do this.
Well, you'd have to pass the size of a row, and the number of rows:
double doSomethingWithACol(double *matrix, size_t colID, size_t rowSize, size_t nRows);
Now you can make use of the fact that matrix[i][j] = matrix + i * rowSize + j;
Alternatively, you can also use the following signature:
double doSomethingWithACol(double *colPtr, size_t rowSize, size_t nRows);
Here, you'll have to pass the pointer to the first element of the column that you want to process, instead of the pointer to the first row.
Example code: This code sums the elements in the second column (compile with gcc -o main -Wall -Wextra -pedantic -std=c99 test.c):
#include <stdio.h>
#include <stdlib.h>
double colSum1(double *matrix, size_t colID, size_t rowSize, size_t nRows)
{
double *c = NULL, *end = matrix + colID + (nRows * rowSize);
double sum = 0;
for (c = matrix + colID; c < end; c += rowSize) {
sum += *c;
}
return sum;
}
double colSum2(double *colPtr, size_t rowSize, size_t nRows)
{
double *end = colPtr + (nRows * rowSize);
double sum = 0;
for (; colPtr < end; colPtr += rowSize) {
sum += *colPtr;
}
return sum;
}
int
main(void)
{
double matrix[4][3] = {
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
{9, 10, 11}
};
printf("%f\n", colSum1(*matrix, 1, 3, 4));
printf("%f\n", colSum2(&matrix[0][1], 3, 4));
printf("%f\n", colSum2(matrix[0] + 1, 3, 4));
return EXIT_SUCCESS;
}
A nice typesafe way to do this without specifying the dimensions as a separate parameters is as follows:
#define ROWS 100
#define COLUMNS 30
void doSomethingToAllRows(double (*row)[ROWS][COLUMNS], int col, double val)
{
for(size_t i = 0; i < ROWS; ++i)
(*row)[i][col] = val;
}
void doSomethingToAllColumns(double (*col)[ROWS][COLUMNS], int row, double val)
{
for(size_t i = 0; i < COLUMNS; ++i)
(*col)[row][i] = val;
}
int main(int argc, char **argv)
{
double matrix[ROWS][COLUMNS];
/* Modify each column of the 10th row with the value of 3 */
doSomethingToAllColumns(&matrix, 10, 3);
/* Modify each row of the 10th column with the value of 3 */
doSomethingToAllRows(&matrix, 10, 3);
return 0;
}
It is completely wrong to pass a double ** for this reason:
void test()
{
double **a;
int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*)
double matrix[ROWS][COLUMNS];
int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double)
}
If you passed in a double ** then accessed it like an array you would cause a crash, segfault or undefined behavior.
Since the "columns" as you call them are stored discontiguously in memory, there's no real way to pull this off directly.
You can, however, create an array of pointers, and store references to the indexes of the other array in that one. You'd need to loop through all of the elements in your array, so it's probably not a better solution than any other. Depending on how often you need to access the array by column it might be worthwhile, though.
You can't really do that, because arrays in C are stored such that the elements of each row are stored together. That means a row of an array is a continuous block of memory, and as far as C is concerned it might as well be an independent array itself. It doesn't work the same way with columns because the elements of a column are not continuous in memory; rather they are spaced at intervals of N bytes, where each row is N bytes long. This means that you could efficiently access the various elements of a column of a 2D array by using pointer arithmetic, but there's no way to actually make a column into an array itself other than by copying the elements over into a new array.
No, there isn't. There cannot be, since in C, an array is a consecutive part of memory, and it is trivial that rows and columns cannot be consecutive at the same time.
That being said, it is fairly easy to jump from one cell of a column to the next, if you know the length of the rows. Take the following example:
void processColumn(double *array, int colIdx, int rowLen, int rowCnt) {
for (int i = colIdx; i < rowCnt * rowLen; i += rowLen) {
// do whatever you want
}
}
#define N 5
#define M 10
double array[N*M];
processColumn(array, 3, N, M);