2

I am attempting to create a structure (2nd) in a structure (1st) with dynamic memory allocation. For the sequence of steps below (case 1), where I call malloc for a pointer to the 2nd structure before calling realloc for the 1st structure, I see garbage when printing the value of the member (str[0].a1) in the first structure. If I place the same realloc code before malloc (case 2), there are no issues.

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

typedef struct string2_t {
    int a2;
} string2;

typedef struct string1_t {
    int a1;
    string2 * b;
} string1;


string1 * str = NULL;
int size = 0;

string1 test(int val){

    // case 2
    //str = (string1 *) realloc(str, size*sizeof(string1));

    string1 S;
    S.a1 = val;
    size += 1;
    S.b = (string2 *) malloc(2*sizeof(string2));
    S.b[0].a2 = 11;
    S.b[1].a2 = 12;

    // case1
    str = (string1 *) realloc(str, size*sizeof(string1));
    
    return S;
}

int main() {
    size += 1;
    str = (string1 *) malloc(size*sizeof(string1));
    str[0] = test(10);
    printf("value of a:%d\n",str[0].a1);
    str[1] = test(20);
    printf("value of a:%d\n",str[0].a1);
    return(0);
}

I can see that memory location changes for case 1, but I don't quite understand why doesn't pointer point to the right contents (str[0].a1 shows junk). I haven't returned the address of 1st structure before realloc, so I feel it should have worked. Could someone explain why it's pointing to garbage?

12
  • You shouldn't increment size in both main() and test(). Commented Dec 21, 2022 at 23:25
  • 1
    don't cast malloc Commented Dec 21, 2022 at 23:27
  • printf("Address of S:%p\n",S);? Compiler says: "warning: format '%p' expects argument of type 'void *', but argument 2 has type 'string1' {aka 'struct string1_t'} [-Wformat=]". Did you mean: printf( "Address of S:%p\n", (void *) &S ); ? Oh, and that is the address of a local variable that is destroyed at fcn exit. Commented Dec 21, 2022 at 23:28
  • 1
    I think you may have undefined behavior due to reassigning str inside test(), and then using that function call when assigning to str[0]. And even if not, it's really confusing that you manage str allocation in both main() and test(). Commented Dec 21, 2022 at 23:31
  • 1
    @AjithCNarayanan True, but not relevant here. string1 S is a struct that is being returned by value, so there is no attempt to return its address. The issue here is that realloc can change the address of the memory block and there is apparently no guaranteed ordering between main evaluating the str based address to place the result and test() calling realloc on str in test. A simple fix would be to assign the result of test to a local in main and then assign that value to the right position in the str pointed to array. Other approach would be to move the realloc of str from test to main. Commented Dec 22, 2022 at 15:58

1 Answer 1

1

As has been stated by several in the comments, lines like this cause undefined behavior:

str[0] = test(10);

The test() function reallocates str, and this is not sequenced with retrieving the address of str[0] as the location to store the result. It's very likely to be compiled as if it had been written

string1 *temp = str;
temp[0] = test(10);

temp caches the old address of str from before the realloc(), and this is invalid after the function returns.

Change your code to:

string1 temp = test(10);
str[0] = temp;

Better design would be to reorganize the code so that all maintenance of the str array is done in one place. test() should be a black box that just allocates the string1 object, while main() allocates and reallocates str when assigning to it.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.