0

I have come across an instance where memory is allocated dynamically to a char pointer within a struct in a way that does not make much sense to me, but - of course - works. A similar question has been posted before. The answers, however, did not help me understand what is actually happening in the allocation process.

Here is the code example I found:

struct a_structure {
   char *str;
   struct a_structure *next;
};

Memory has been allocated in the following way:

ptr_start=(struct a_structure *)malloc(sizeof (struct a_structure *));
...
char *some_words="How does this work?";
ptr_start->str=(char *)malloc(strlen(some_words)+1);
strcpy(ptr_start->str, some_words);
ptr_start->next=(struct a_structure *)malloc(sizeof(struct a_structure *));
...

I don't understand why malloc is used with the size of a pointer here. ptr_start is a pointer of type struct a_structure. That would mean it needs memory of size sizeof(struct a_structure) + the size of my string that hasn't been specified in the structure declaration. In the above example, however, malloc returns the address of yet another pointer pointing to a structure of type a_structure, am I right?

N. Krebs
  • 13
  • 1
  • *"I don't understand why malloc is used with the size of a pointer here"* - I do. It means the author made a mistake when writing it. Probably because they don't write idiomatic C often. – StoryTeller - Unslander Monica Feb 26 '18 at 11:08
  • _I don't understand why malloc is used with the size of a pointer here. ptr_start_: nor do I, it's probably wrong and should probably be `sizeof (struct a_structure)`. Where did you find that code? – Jabberwocky Feb 26 '18 at 11:09
  • BTW, if you read [this Q&A](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc), you'll learn how to avoid such mistakes, among other things. – StoryTeller - Unslander Monica Feb 26 '18 at 11:10
  • I found that in a book about the C programming language called "C von A bis Z" (German) by Jürgen Wolf. – N. Krebs Feb 26 '18 at 13:40
  • I'm guessing the author didn't know the alphabet. It goes: B, BCPL, C, C++, D, Java, J++, C#. – Lundin Feb 26 '18 at 16:06
  • this code also highlights the joy of `strdup`. `ptr_start->str = strdup(some_words)` – pm100 Feb 26 '18 at 16:07
  • @pm100 Joy until porting the code to a standard C compiler, perhaps. – Lundin Feb 26 '18 at 16:08
  • @Lundin - I will bet a whole $1 that any platform this is ported to is POSIX compliant – pm100 Feb 26 '18 at 16:11
  • @pm100 What is POSIX? I program C all day and rarely ever encounter POSIX. Because there's embedded systems. You can donate the $1 to charity, please :) – Lundin Feb 26 '18 at 16:21
  • @Lundin - I bet about the OPs code, not yours. You know yr tools inside out. No $1 – pm100 Feb 26 '18 at 16:28

2 Answers2

0

Given that you have struct a_structure* ptr_start, this code is incorrect and does not work:

ptr_start=(struct a_structure *)malloc(sizeof (struct a_structure *));

It should have been:

ptr_start = malloc(sizeof *ptr_start);

The reason why it "seems to work" is because you invoked undefined behavior, and anything can happen. The program could seem to work one moment, then crash at another time.

This does however just allocate the struct itself. The pointers inside it will, like all pointers, point at memory allocated somewhere else. The following code with malloc for the string and strcpy() is one way to do so.

The last line is however incorrect for the same reason as pointed out above.

user2736738
  • 30,591
  • 5
  • 42
  • 56
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Could you explain why you use "sizeof *ptr_start" and not "sizeof struct a_structure"? – N. Krebs Feb 26 '18 at 13:49
  • @N.Krebs It means the same thing. `*ptr_start` gives an item of type `struct a_structure`. The operand of `sizeof` is not evaluated so it doesn't matter that the pointer points nowhere at this point. This is a commonly used trick to ensure that the correct type is used, to avoid exactly the kind of bugs you have here. – Lundin Feb 26 '18 at 13:57
0

I don't understand why malloc is used with the size of a pointer here. ptr_start is a pointer of type struct a_structure. That would mean it needs memory of size sizeof(struct a_structure) + the size of my string that hasn't been specified in the structure declaration

You are right. To create structure a_structure in order to manipulate it we need to allocate memory for whole structure. (Unless the object has been ALREADY created and for whatever reason we need a dynamically allocated pointer holding pointer to that object).

but - of course - works.

The presented fragment of the program cannot work properly for the stated above reasons.

In the above example, however, malloc returns the address of yet another pointer pointing to a structure of type a_structure, am I right?

Yes, you are right.

This is also problematic:

ptr_start->next=(struct a_structure *)malloc(sizeof(struct a_structure *));

ptr_start->next can hold a pointer already. We typically do not need to allocate a pointer here. We would assign a pointer to the existing structure or we would allocate memory for the whole structure.

See example:

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

struct a_structure {
   char *str;
   struct a_structure *next;
};

struct a_structure * allocatePointer(void)
{
    // ptr ptrToObj1Allocated points to allocted memory which can hold a ponter   
    struct a_structure * ptrToObj1Allocated = malloc(sizeof (struct a_structure *)); 
    return ptrToObj1Allocated;
}

int main(){       
    // 1.
    struct a_structure obj1;    //  structure a_structure has been allocated on the stack 

    struct a_structure * ptrToObj1 = & obj1; // points to the existing structure

    char *some_words = "How does this work?";
    ptrToObj1->str = malloc(strlen(some_words)+1);
    if(ptrToObj1->str == NULL){printf("No enough memory\n"); return -1;}

    strcpy(ptrToObj1->str, some_words); // copy the string
    // now obj1 has its own copy of the string.

    // 2.
    // dynamically allocate another structure on the heap
    // we want to allocate memory for the structure not just a memory to keep the pointer to the structure.

    struct a_structure *obj2 = malloc( sizeof (struct a_structure));  // memory has been allocated to hold struct a_structure with 2 pointers
    if(obj2 == NULL){printf("No enough memory\n"); return -2;}

    char *words = "More words..";
    obj2->str = malloc(strlen(words)+1);
    if(obj2->str == NULL){printf("No enough memory\n"); return -3;}

    strcpy(obj2->str, words);  // copy the string

    obj2->next = ptrToObj1;    // points to the already existing object

     //----
    printf("String in obj1 is: %s\n", ptrToObj1->str);
    printf("String in obj2 is: %s\n", obj2->str);          
    printf("obj2->next points to structure with string: %s\n", obj2->next->str );  

    // free the allocated  memory:   
    free(ptrToObj1->str);

    free(obj2->str);     
    free(obj2);    

    return 0;
}

Output:

String in obj1 is: How does this work?
String in obj2 is: More words..
obj2->next points to structure with string: How does this work?
sg7
  • 6,108
  • 2
  • 32
  • 40