4

In the following code, I initialize a struct array that is inside another struct. After initializing the array, I can print all the values without problem in loop #1.

However, if I try to change the values, as in Loop #2, I get a segmentation fault when when trying to access the element exactly at the middle of the array (i.e. when j==points/2, or 50 in this particular case).

Why is it that accessing the element to print it works but trying to change it causes a segmentation fault?

#include <stdio.h>
#include <stdlib.h>

struct flux{
  double *intense;
  double *tau;
};

struct radius_struct{
  int id;
  struct flux *flux;
};

int main(int argc, const char * argv[]) {
    
    int i,j, ichan, points,nchan;
    points = 100;
    nchan = 20;
    
    struct radius_struct radius_struct;
    radius_struct.id = 99;
    radius_struct.flux = malloc(sizeof(double) * points);
    
    
    for(i = 0; i < points; i++){
      radius_struct.flux[i].intense= malloc(sizeof(double) * nchan);
      radius_struct.flux[i].tau= malloc(sizeof(double) * nchan);

      for(ichan=0;ichan<nchan;ichan++){
        radius_struct.flux[i].intense[ichan] = ichan;
        radius_struct.flux[i].tau[ichan] =ichan;
      }
    }
    
    //Loop #1
    for(j = 0; j < points; j++){
      for(ichan=0; ichan<nchan; ichan++){
         printf("%f %f\n", radius_struct.flux[j].intense[ichan],  radius_struct.flux[j].tau[ichan]);
      }
    }
    
    //Loop #2
    for(j = 0; j < points; j++){
      for(ichan=0; ichan<nchan; ichan++){
          radius_struct.flux[j].intense[ichan] = 123.456;
          radius_struct.flux[j].tau[ichan] = 123.456;
      }
    }

    return 0;
}
egarciab
  • 41
  • 3
  • 5
    `radius_struct.flux = malloc(sizeof(double) * points);`? [**Why is it safer to use sizeof(*pointer) in malloc**](https://stackoverflow.com/questions/17258647/why-is-it-safer-to-use-sizeofpointer-in-malloc) – Andrew Henle Feb 10 '21 at 17:46
  • 5
    `radius_struct.flux = malloc(sizeof(double) * points)`: `(sizeof(double)` is wrong because `radius_struct.flux` is not a `double` but a `struct flux`. It should be `malloc(sizeof(*radius_struct.flux) * points)` instead – Jabberwocky Feb 10 '21 at 17:49
  • @Jabberwocky That fixed the problem, thank you so much! Just to get a better understanding, since the allocation was done incorrectly, why doesn't it fail when accessing them in the initialization or when printing them before Loop #2? – egarciab Feb 10 '21 at 17:58
  • @egarciab be sure to read and understand the link in the second comment. – Jabberwocky Feb 10 '21 at 17:59
  • egarciab, Rather than asking "Why is it that accessing the element to print it works" without the true code posted, better to post the code used than only loosely refer to it. – chux - Reinstate Monica Feb 10 '21 at 18:42
  • @egarciab Rather than only "causes a segmentation fault?", it is more informative to also post the text of the segmentation fault and if available, the reference line of code of the fault. – chux - Reinstate Monica Feb 10 '21 at 18:43
  • @egarciab Next time you have such an issue, I advise you to start a debugger, not ask here. We have solved your problem but you didn't learn how to identify it. A debugger may even bring you some answers that we won't ever be able to bring, especially in this case of undefined behavior (we can only speculate). Some parts of your process memory might be [read-only](/q/59870800/7233423), other parts like the stack are r/w but not under your control ([time to learn what StackOverflow means](/q/40416516/7233423) ;-) – xhienne Feb 10 '21 at 19:03

2 Answers2

3

Avoid allocation sizing errors.

Allocate to the size of the referenced object. Easier to code right, review and maintain.

//                             v------------v wrong size 
// radius_struct.flux = malloc(sizeof(double) * points);
radius_struct.flux = malloc(sizeof *(radius_struct.flux) * points);
//                          ^--------------------------^ right size, even without looking up .flux type.

why doesn't it fail when accessing them in the initialization or when printing them before Loop #2? –

radius_struct.flux[i].intense and all following code is suspect and subject to undefined behavior as the prior allocation was not certainly sufficient. Some things might work, others might not. See also @CiaPan.


Robust code would also check the return pointer for allocation failure with a check against NULL.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

as pointed out in the comment, radius_struct.flux is of type "struct flux". so all you have to do is replace

radius_struct.flux = malloc(sizeof(double) * points);

with

radius_struct.flux = malloc(sizeof(struct flux) * points);
  • In comment it is also stated that `malloc(sizeof(type))` should be avoided in favor of `malloc(sizeof *pointer)`. Also, it may be interesting to address OP's question: "Why is it that accessing the element to print it works but trying to change it causes a segmentation fault?" – xhienne Feb 10 '21 at 18:26