I've forgotten my C: passing 2-D matrices

J

J Krugman

There was a time when all I programmed was C. I thought I'd never
forget it; not the basics anyway. Therefore I find it very upsetting
that this is giving me a segfault:

#include <stdio.h>
double foo[ 2 ][ 3 ] = {{1., 2., 3.}, {4., 5., 6.}};
int main( void ) {
int i, j;
double **r;
r = foo;
for ( i = 0; i < 2; ++i ) {
for ( j = 0; j < 3; ++j ) {
printf( "%f\t", r[ i ][ j ] );
}
printf( "\n" );
}
return 0;
}

More generally, I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols), but either bar(foo, 2, 3)
or bar((double **)foo, 2, 3) result in another segfault. I realize
that I am making an elementary mistake, but for the life of me I
can no longer see it. Please someone remind me of what I should
do.

TIA!

jill
 
N

No Such Luck

More generally, I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols), but either bar(foo, 2, 3)
or bar((double **)foo, 2, 3) result in another segfault. I realize
that I am making an elementary mistake, but for the life of me I
can no longer see it. Please someone remind me of what I should
do.

I've had little luck unless I declare foo as:

double **foo;

and malloc the appropriate rows and columns. This data structure is
then easily passed to a function expecting a paramter of type double **

Example:

foo = (double **)malloc((height) * sizeof(double*));
for(i=0; i<height; i++)
{
foo = (double *)malloc((width) * sizeof(double));
}

The values of matrix are accessible by 'foo[y][x]' (y ranges from 0 to
height-1, x ranges from 0 to width-1)

foo is also passable to function bar.

....waiting for the gurus here to slice me down... =)
 
C

Chris Torek

double foo[ 2 ][ 3 ] = [snippage] ...
[and now] I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols) ...

See the comp.lang.c FAQ, in particular question 6.18.
 
M

Mark

J Krugman said:
There was a time when all I programmed was C. I thought I'd never
forget it; not the basics anyway. Therefore I find it very upsetting
that this is giving me a segfault:

#include <stdio.h>
double foo[ 2 ][ 3 ] = {{1., 2., 3.}, {4., 5., 6.}};
int main( void ) {
int i, j;
double **r;
r = foo;
for ( i = 0; i < 2; ++i ) {
for ( j = 0; j < 3; ++j ) {
printf( "%f\t", r[ i ][ j ] );
}
printf( "\n" );
}
return 0;
}

More generally, I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols), but either bar(foo, 2, 3)
or bar((double **)foo, 2, 3) result in another segfault. I realize
that I am making an elementary mistake, but for the life of me I
can no longer see it. Please someone remind me of what I should
do.

double (*r)[3];
 
J

J Krugman

In said:
double foo[ 2 ][ 3 ] = [snippage] ...
[and now] I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols) ...
See the comp.lang.c FAQ, in particular question 6.18.

Thank you.

What I ended up doing is

#define M 2
#define N 3

/* double foo[ M ][ N ] as before */

int i;
double **dummy;
dummy = ( double ** ) calloc( ( size_t ) M,
( size_t ) sizeof( double * ) );
for ( i = 0; i < M; ++i ) dummy[ i ] = foo[ i ];

bar( dummy, M, N );

Is this the typical way to pass a 2-D array to a function that
takes a pointer-to-pointer, or is there a more clueful approach?

jill
 
K

Keith Thompson

No Such Luck said:
More generally, I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols), but either bar(foo, 2, 3)
or bar((double **)foo, 2, 3) result in another segfault. I realize
that I am making an elementary mistake, but for the life of me I
can no longer see it. Please someone remind me of what I should
do.

I've had little luck unless I declare foo as:

double **foo;

and malloc the appropriate rows and columns. This data structure is
then easily passed to a function expecting a paramter of type double **

Example:

foo = (double **)malloc((height) * sizeof(double*));
for(i=0; i<height; i++)
{
foo = (double *)malloc((width) * sizeof(double));
}

The values of matrix are accessible by 'foo[y][x]' (y ranges from 0 to
height-1, x ranges from 0 to width-1)

foo is also passable to function bar.


Casting the result of malloc() is unnecessary and can mask errors.

Here's a better way to do the same thing:

double **foo;

foo = malloc(height * sizeof *foo);
for(i=0; i<height; i++)
{
foo = malloc(width * sizeof *(foo));
}

Note that I've also changed the arguments to the sizeof operators so
they refer to what the destination pointer points to rather than using
the name of the type. This means that if you later decide to use a
type other than double, the malloc() calls will continue to work. If
you change the declaration of foo to "int **foo", but forget to change
"sizeof(double)" to "sizeof(int)", Bad Things can happen.)
 
B

Barry Schwarz

There was a time when all I programmed was C. I thought I'd never
forget it; not the basics anyway. Therefore I find it very upsetting
that this is giving me a segfault:

#include <stdio.h>
double foo[ 2 ][ 3 ] = {{1., 2., 3.}, {4., 5., 6.}};
int main( void ) {
int i, j;
double **r;
r = foo;
for ( i = 0; i < 2; ++i ) {
for ( j = 0; j < 3; ++j ) {
printf( "%f\t", r[ i ][ j ] );
}
printf( "\n" );
}
return 0;
}

More generally, I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols), but either bar(foo, 2, 3)

This should result in a syntax error. If it doesn't, you need to up
the warning level of your compiler.
or bar((double **)foo, 2, 3) result in another segfault. I realize

A segfault is one of the better results when you lie to the compiler.
This code says foo[0] is a pointer. It isn't.
that I am making an elementary mistake, but for the life of me I
can no longer see it. Please someone remind me of what I should
do.

TIA!

jill



<<Remove the del for email>>
 
B

Barry Schwarz

In said:
double foo[ 2 ][ 3 ] = [snippage] ...
[and now] I want to pass foo as the argument to a function
bar(double **, int n_rows, int n_cols) ...
See the comp.lang.c FAQ, in particular question 6.18.

Thank you.

What I ended up doing is

#define M 2
#define N 3

/* double foo[ M ][ N ] as before */

int i;
double **dummy;
dummy = ( double ** ) calloc( ( size_t ) M,
( size_t ) sizeof( double * ) );

Don't cast the result of calloc or its cousins. It can never help but
can mask a failure to have a prototype in scope for the function.
There is also no need to cast the parameters. The compiler will
coerce them into the correct form if the prototype is in scope.
Furthermore, sizeof evaluates to a size_t so that cast is completely
redundant.

Since you immediately assign values to the area allocated in the next
code, using calloc wastes machine cycles initializing the area to
all-bits-zero. This bit value is not necessarily a valid value for a
pointer but you don't use it anyway.

The recommended idiom is
dummy = malloc(M * sizeof *dummy);
for ( i = 0; i < M; ++i ) dummy[ i ] = foo[ i ];

bar( dummy, M, N );

Is this the typical way to pass a 2-D array to a function that
takes a pointer-to-pointer, or is there a more clueful approach?

Assuming that such an event can be called typical, this looks like a
reasonable way to do it.


<<Remove the del for email>>
 
N

No Such Luck

Note that I've also changed the arguments to the sizeof operators so
they refer to what the destination pointer points to rather than using
the name of the type. This means that if you later decide to use a
type other than double, the malloc() calls will continue to work. If
you change the declaration of foo to "int **foo", but forget to change
"sizeof(double)" to "sizeof(int)", Bad Things can happen.)

Thanks for the more optimized approach. I'll give it a try...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top