0

Here's my code:

typedef struct{

double (*a)[2];
} my_struct;


void update(my_struct* struct1){

struct1 -> a = malloc ( 2*sizeof(struct1->a) );

struct1 -> a[0][0] = 5.0;
struct1 -> a[0][1] = 10.0;
struct1 -> a[1][0] = 3.0;
struct1 -> a[1][1] = 4.0;

printf("%f %f %f\n", struct1->a[0][0], struct1->a[0][1], struct1->a[1][1]);

}


int main(){

my_struct struct1;

update(&struct1);

printf("%f %f %f\n", struct1.a[0][0], struct1.a[0][1], struct1.a[1][1]);


return 0;
}

So basically what I want to do is to have a structure with a matrix (I really want to use this definition of matrix with [r][c] and thus the way I make the allocation).

As you can see I have two printfs to see what's happening.

In the command line what is printed is the following:

5.000000 10.000000 3.000000
5.000000 10.000000 0.000000

So why one of the values printed in main() is zero???

ajcoelho
  • 15
  • 5

2 Answers2

0

I can see two problems.

1) Incorrect malloc size

struct1->a is a pointer so sizeof(struct1->a) is the size of a pointer. What you want is the size of the first element. So use sizeof(struct1->a[0]) (or sizeof(*struct1->a))

2) Index out of range

Your code (after correcting malloc size) is creating a 2x2 matrix. So this access struct1 -> a[1][2] is out of range

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • The second problem no longer applies, I made an EDIT in my post, it was a typo. The first problem Thanks, you solved it! – ajcoelho Oct 03 '18 at 11:59
  • Btw, do you know if there is any way of making the complete allocation inside the function update? So inside the struct I would only have double `*a` – ajcoelho Oct 03 '18 at 12:13
  • @ajcoelho If you want a correct allocated 2D array (aka array of array) your method is correct. It can't be done using `double **a;` However, you can use a `double **a;` as an array of pointers and then let each of those pointers point to an array of doubles. The memory layout will not be the same as 2D array but you can use the `a[r][c]` syntax. – Support Ukraine Oct 03 '18 at 12:21
  • @ajcoelho Read this https://stackoverflow.com/a/42094467/4386427 for further info. Maybe the section **What is the pointer-to-pointer thing, if not an array?** is exactly what you are looking for. – Support Ukraine Oct 03 '18 at 12:24
0

After adding the necessary includes of <stdio.h> and <stdlib.h>, we can run the code under Valgrind to see what's wrong:

valgrind -q --leak-check=full ./52626203   
==1409== Invalid write of size 8
==1409==    at 0x10919F: update (52626203.c:16)
==1409==    by 0x109209: main (52626203.c:28)
==1409==  Address 0x4a39050 is 0 bytes after a block of size 16 alloc'd
==1409==    at 0x48357BF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1409==    by 0x10915A: update (52626203.c:12)
==1409==    by 0x109209: main (52626203.c:28)
==1409== 
==1409== Invalid write of size 8
==1409==    at 0x1091B6: update (52626203.c:17)
==1409==    by 0x109209: main (52626203.c:28)
==1409==  Address 0x4a39058 is 8 bytes after a block of size 16 alloc'd
==1409==    at 0x48357BF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1409==    by 0x10915A: update (52626203.c:12)
==1409==    by 0x109209: main (52626203.c:28)
==1409== 
==1409== Invalid read of size 8
==1409==    at 0x1091C6: update (52626203.c:19)
==1409==    by 0x109209: main (52626203.c:28)
==1409==  Address 0x4a39058 is 8 bytes after a block of size 16 alloc'd
==1409==    at 0x48357BF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1409==    by 0x10915A: update (52626203.c:12)
==1409==    by 0x109209: main (52626203.c:28)
==1409== 
5.000000 10.000000 4.000000
==1409== Invalid read of size 8
==1409==    at 0x109212: main (52626203.c:30)
==1409==  Address 0x4a39058 is 8 bytes after a block of size 16 alloc'd
==1409==    at 0x48357BF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1409==    by 0x10915A: update (52626203.c:12)
==1409==    by 0x109209: main (52626203.c:28)
==1409== 
5.000000 10.000000 4.000000
==1409== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1409==    at 0x48357BF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1409==    by 0x10915A: update (52626203.c:12)
==1409==    by 0x109209: main (52626203.c:28)
==1409== 

This shows us that it's the attempt to assign to struct1->a[1][0] that's at fault, suggesting that we allocated only enough space for a[0] and not also a[1].

That takes us right to the allocation line, where we see we missed a dereference in the argument to sizeof. It should be

struct1->a = malloc(2 * sizeof *struct1->a);
//                             ^

We were allocating space for two pointers to double array, rather than enough for two double arrays of two elements each.

BTW, in real code, don't forget to check the pointer returned from malloc() before you try to use it, and to free() it when you're done.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103