accessing a struct

M

Michael Goerz

Hi,

What is the error in the code below? The output is:
DEBUG: matrix.b[0] is 2.000000
DEBUG: matrix->b[0] is 0.000000
In other words, the struct is empty after it is passed to the
solve_tridiag function. How can I fix this? I didn't see this in the
FAQ, although I have the feeling that I'm missing something basic here.

Many Thanks,
Michael Goerz


#include <stdio.h>

struct Tridiag{
// represents a tridiagonal matrix like this:
// b1 c1 0 0 0 ...
// a2 b2 c2 0 0 ...
// 0 a3 b3 c3 0 ...
// ... ...
double *a;
double *b;
double *c;
};


struct Tridiag create_matrix(){
struct Tridiag matrix;
double b[5] = { 2.0, 2.0, 2.0, 2.0, 2.0};
double a[5] = { 0.0, -1.0, -1.0, -1.0, -1.0};
double c[5] = {-1.0, -1.0, -1.0, -1.0, 0.0};
matrix.b = b;
matrix.a = a;
matrix.c = c;
return matrix;
}

void solve_tridiag( struct Tridiag *matrix, double *r){
printf("DEBUG: matrix->b[0] is %f\n", matrix->b[0]);
// ...
}


int main(){
double r[] = {0.0 , 1.0, 2.0, 3.0, 4.0};
struct Tridiag matrix = create_matrix();
printf("DEBUG: matrix.b[0] is %f\n", matrix.b[0]);
solve_tridiag(&matrix, r);
return 0;
}
 
M

marora

Michael said:
Hi,

What is the error in the code below? The output is:
DEBUG: matrix.b[0] is 2.000000
DEBUG: matrix->b[0] is 0.000000
In other words, the struct is empty after it is passed to the
solve_tridiag function. How can I fix this? I didn't see this in the
FAQ, although I have the feeling that I'm missing something basic here.

Many Thanks,
Michael Goerz


#include <stdio.h>

struct Tridiag{
// represents a tridiagonal matrix like this:
// b1 c1 0 0 0 ...
// a2 b2 c2 0 0 ...
// 0 a3 b3 c3 0 ...
// ... ...
double *a;
double *b;
double *c;
};


struct Tridiag create_matrix(){
struct Tridiag matrix;
double b[5] = { 2.0, 2.0, 2.0, 2.0, 2.0};
double a[5] = { 0.0, -1.0, -1.0, -1.0, -1.0};
double c[5] = {-1.0, -1.0, -1.0, -1.0, 0.0};
matrix.b = b;
matrix.a = a;
matrix.c = c;
return matrix;
}
So you saved the address of local arrays a, b and c onto data members
of matrix. Do you expect that the data these arrays point to after the
execution of this function will also be saved?
DEBUG: matrix->b[0] is 0.000000

void solve_tridiag( struct Tridiag *matrix, double *r){
printf("DEBUG: matrix->b[0] is %f\n", matrix->b[0]);
// ...
}


int main(){
double r[] = {0.0 , 1.0, 2.0, 3.0, 4.0};
struct Tridiag matrix = create_matrix();
printf("DEBUG: matrix.b[0] is %f\n", matrix.b[0]);

"DEBUG: matrix.b[0] is 2.000000"
Since you can access the saved data here, doesn't really means that
this data will be there for ever. After you finished executing
'create_matrix()' function, the memory used by these arrays is up for
grabs, your OS may use it as it needs it.
solve_tridiag(&matrix, r);
return 0;
}

I believe if you address these issues, your program should start
behaving.

Regards,
Manish
 
J

Jens Thoms Toerring

Michael Goerz said:
What is the error in the code below? The output is:
DEBUG: matrix.b[0] is 2.000000
DEBUG: matrix->b[0] is 0.000000
In other words, the struct is empty after it is passed to the
solve_tridiag function. How can I fix this? I didn't see this in the
FAQ, although I have the feeling that I'm missing something basic here.
#include <stdio.h>
struct Tridiag{
double *a;
double *b;
double *c;
};
struct Tridiag create_matrix(){
struct Tridiag matrix;
double b[5] = { 2.0, 2.0, 2.0, 2.0, 2.0};
double a[5] = { 0.0, -1.0, -1.0, -1.0, -1.0};
double c[5] = {-1.0, -1.0, -1.0, -1.0, 0.0};
matrix.b = b;
matrix.a = a;
matrix.c = c;

Now matrix.a, matrix.b and matrix.c are pointers to memory that is
local to this function. And once the function has ended they point
to memory you don't own anymore since the three arrays have gone
out of scope.
return matrix;
}
void solve_tridiag( struct Tridiag *matrix, double *r){
printf("DEBUG: matrix->b[0] is %f\n", matrix->b[0]);
}
int main(){

Better make that

int main( void )
double r[] = {0.0 , 1.0, 2.0, 3.0, 4.0};
struct Tridiag matrix = create_matrix();
printf("DEBUG: matrix.b[0] is %f\n", matrix.b[0]);

This only works by accident. Probably the data of the three arrays
the elements of matrix point to still are undisturbed on the stack,
so it may look as everything is fine, but you're just unlucky. If
you would try the same program on a different machine it could al-
ready give you an "unexpected" result here.
solve_tridiag(&matrix, r);

And now calling another function overwrites things on the stack and
you finally find out about the errors of your way;-) Bugs where one
uses memory that one doesn't own can be hard to find since it can
look like nothing bad happened for a long time, only to result in
a weird problem somewhere else, seemingly completely unrelated to
where the original error was.
return 0;
}
Regards, Jens
 
E

Eric Sosman

Michael said:
Hi,

What is the error in the code below? The output is:
DEBUG: matrix.b[0] is 2.000000
DEBUG: matrix->b[0] is 0.000000
In other words, the struct is empty after it is passed to the
solve_tridiag function. How can I fix this? I didn't see this in the
FAQ, although I have the feeling that I'm missing something basic here.

It's Question 7.5a, but somewhat disguised. The FAQ's
example has a function returning a pointer value that points
to one of the function's auto variables, and since the variable
ceases to exist when the function returns the pointer is no
good to the caller. You're not doing exactly that, but ...
#include <stdio.h>

struct Tridiag{
// represents a tridiagonal matrix like this:
// b1 c1 0 0 0 ...
// a2 b2 c2 0 0 ...
// 0 a3 b3 c3 0 ...
// ... ...
double *a;
double *b;
double *c;
};


struct Tridiag create_matrix(){
struct Tridiag matrix;
double b[5] = { 2.0, 2.0, 2.0, 2.0, 2.0};
double a[5] = { 0.0, -1.0, -1.0, -1.0, -1.0};
double c[5] = {-1.0, -1.0, -1.0, -1.0, 0.0};

All of b, a, c will cease to exist when create_matrix()
returns, just as in the FAQ's example.
matrix.b = b;
matrix.a = a;
matrix.c = c;
return matrix;

There's nothing wrong with returning the struct value
`matrix', but matrix.b, matrix.a, matrix.c are pointing to
b, a, c, which are about to expire ...

Solution: You need the struct elements to point to storage
that will survive after create_matrix() has been and gone, and
for as long as you still need the values. One possibility is
to use static storage, as illustrated in the FAQ. Another is
to call malloc() to obtain dynamic storage that will hold the
values provided by create_matrix(); it would be a good idea to
write a companion destroy_matrix() to free() the dynamic memory
when you're done with it. Hard to say which approach is more
suitable; in the "toy" program you've shown static storage is
easier, but I imagine you have more involved applications in
mind.
 
L

loic-dev

Hello Michael,
What is the error in the code below? The output is:
DEBUG: matrix.b[0] is 2.000000
DEBUG: matrix->b[0] is 0.000000
In other words, the struct is empty after it is passed to the
solve_tridiag function. How can I fix this? I didn't see this in the
FAQ, although I have the feeling that I'm missing something basic here.

struct Tridiag create_matrix(){
struct Tridiag matrix;
double b[5] = { 2.0, 2.0, 2.0, 2.0, 2.0};
double a[5] = { 0.0, -1.0, -1.0, -1.0, -1.0};
double c[5] = {-1.0, -1.0, -1.0, -1.0, 0.0};
matrix.b = b;
matrix.a = a;
matrix.c = c;
return matrix;
}

Here is your problem. The pointer matrix.b,matrix.a,matrix.c of your
Tridiag structure point to the *local* variables (ie. located on the
stack) b,a,c resp. The life of those variables is only limited to the
function create_matrix(). And soon as the function returns, the values
are undefined. That's actually the effect your are seeing.

You can fix your code as follow. You can declare the variable b,a,c in
create_matrix() as static. Or you can allocate with malloc()/calloc()
enough room for matrix.b,matrix.a,matrix.c and you copy the contents of
b,a,c as appropriate with memcpy().

HTH,
Loic.
 

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,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top