C: malloc() doesn't just allocate memory

  • Thread starter Thread starter nobahar
  • Start date Start date
  • Tags Tags
    Memory
Click For Summary

Discussion Overview

The discussion revolves around the behavior of the malloc() function in C, particularly in the context of allocating memory for structures and linked lists. Participants explore how malloc() allocates memory and the implications of pointer types and structure definitions on memory usage.

Discussion Character

  • Technical explanation
  • Conceptual clarification
  • Debate/contested

Main Points Raised

  • Some participants explain that malloc() allocates a specified number of bytes and returns a void pointer, which can be cast to any pointer type in C, while noting that this is not the case in C++.
  • One participant argues that the structure definition determines how the allocated memory is treated, and that malloc() does not inherently "know" about the structure's members.
  • Another participant suggests that when memory is allocated for a structure, it is as if the space is "partitioned" according to the structure's definition, which is contested by others.
  • Some participants clarify that while the compiler knows the offsets of structure members, no additional operations are needed on the allocated memory to use it as a structure.
  • There is a discussion about the necessity of initializing structure members, with some asserting that it is not required in C, while others point out that it is a common practice to avoid undefined behavior.
  • Participants discuss the differences in memory management between C and C++, particularly regarding the use of constructors in C++ for non-POD classes.

Areas of Agreement / Disagreement

Participants express differing views on whether malloc() inherently partitions memory according to structure definitions. While some agree that the compiler handles offsets, others maintain that the concept of "partitioning" is misleading. There is no consensus on the necessity of initializing structure members, with varying opinions on best practices.

Contextual Notes

Some participants note that the behavior of allocated memory can vary depending on compiler settings, with allocated memory potentially containing random values or being initialized in debug modes. Additionally, the discussion touches on the implications of using malloc() in C++ versus C.

nobahar
Messages
482
Reaction score
2
Hello,

Another (probably obvious) question:
malloc() assigns memory space in bytes; e.g. malloc(100) assigns 100 bytes of space and returns a pointer.

However, in creating a linked list, I can allocate space a assign it to a pointer and the structure already exists?
For example:
Code:
//Create structure
struct happy
{
     int x;
     struct happy *h_ptr;
};

int main( void )
{
     //Pointers for assigning head to link to first structure and a pointer for creating new links
     struct happy *head = NULL;
     struct happy *newlink = NULL;
     
     //Assign memory for structure and assign address of space to head pointer
     head = malloc(sizeof(struct happy));

     //Make the pointer in happy, h_ptr, point to NULL, since it is the last (and only) element
     head->h_ptr = NULL;

     ...
     return 0;
}

If malloc() only assigned space in memory, then why does head->h_ptr = NULL work? malloc() set aside the correct amount of space, but it doesn't "know" what for, the structure type hasn't been placed there. Does the pointer type - that malloc is set to point to a structure of type happy - mean that the structure type is created because of the pointer? I have seen typecasts, e.g. head = (struct happy *)malloc(sizeof(struct happy)), used, but also read that they are not necessary in C. If the typecast was used, I can imagine that it tells the malloc() function to "divide up" the space into a happy structure type; does the pointer type, by pointing to a happy structure type, do the same thing?

Any help appreciated,
Thanks in advance.
 
Technology news on Phys.org
malloc returns a void* pointer. A type cast is not needed because void* converts to any pointer type without a cast -- in C, that is. This is not the case in C++ (but you should never use malloc in C++).

It doesn't hurt to add the cast; it doesn't cost anything. A typecast results in zero assembly code when converting from one pointer type to another.
 
In a way the structure of happy is "always there".

Pointer is just an address of a place in memory. Structure definition tells your program how to treat whatever data happens to be at the address variable sits in memory. You don't have to do anything for the structure to "exist". However, you have to initialize it with a correct data if you want the structure to make sense in your program. Memory allocated by malloc() can contain anything, and the content may even accidentally make sense.

Note: depending on the complier and mode it is working in, allocated memory can be either completely random, or initialized with some values (like 0xCDCDCDCD). This often makes debugging easier, but it sometimes means release version of the code behaves differently than the debug version (which usually means you forgot to initialize something in your code, and the debug version worked correctly by accident).
 
D H said:
A type cast is not needed because void* converts to any pointer type without a cast

Is it in any way accurate to understand this to mean something like the following:

I have my structure happy as before.

I declare a pointer that points to a structure of type happy.
Code:
struct happy *h_ptr = NULL;

When I assign space in memory using malloc() it would simply set aside that space, but by assigning the space to a pointer which is "set-up" to point to a happy-type structure, the space is "partitioned" to match the structure and its members: happy has members that perform specific functions, e.g. a pointer, this means the space in memory for this pointer has to be known to be separate from the other member, int x, and to be of type pointer. Its not simply setting aside, say, 12 bytes, but 4 for int and 8 for the pointer. I can immediately use the memory set aside as though this partition exists:
Code:
head = malloc(16);
head->h_ptr = NULL;
If on the other-hand I declared malloc(16), and assigned the return value to a char * pointer, it would set-aside the correct space for a string, and
Code:
head->h_ptr = NULL;
would not work.

I hope this makes sense; if so, is it in anyway accurate?
Thanks borek and DH for the help so far.
 
nobahar said:
by assigning the space to a pointer which is "set-up" to point to a happy-type structure, the space is "partitioned" to match the structure and its members

No, it is not. That's what I tried to tell you. "Space partitioning" is defined by the structure definition. malloc doesn't care about internal structure, all it does is it allocates sizeof(happy) bytes. It will do exactly the same operation for every other structure that happens to occupy exactly the same number of bytes.

nobahar said:
If on the other-hand I declared malloc(16), and assigned the return value to a char * pointer, it would set-aside the correct space for a string, and
Code:
head->h_ptr = NULL;
would not work.

You can easily make it work by casting a pointer. There is no such thing as a "correct space for string", there are 16 bytes of memory.
 
nobahar said:
the space is "partitioned" to match the structure and its members

No operation needs to be done when the program is running for this "partitioning".

happy has members that perform specific functions, e.g. a pointer, this means the space in memory for this pointer has to be known to be separate from the other member, int x, and to be of type pointer. Its not simply setting aside, say, 12 bytes, but 4 for int and 8 for the pointer.

That is correct, and that is known to the compiler when the program is compiled. A structure is a contiguous block of memory starting at some address x. The compiler knows that field a is at a fixed offset from the beginning of the structure, and it knows that field b is at another fixed offset from the beginning of the structure. So your expression "x->a" is compiled to something like "take address from variable x and add offset_a bytes to it; this is the address where the field is". Likewise, "x->b" is compiled to "take address from x and add offset_b bytes to it; this is the address where the field is". offset_a and offset_b are compile-time constants (you could even obtain them with some creative use of C).

The point of that is NOTHING needs to be done to the memory allocated by malloc() to use it as a structure.

This is markedly different in C++. In C++, something MAY need to be done; this is why malloc() is deprecated in C++ and operator new should be used whenever possible.
 
voko said:
The point of that is NOTHING needs to be done to the memory allocated by malloc() to use it as a structure. This is markedly different in C++. In C++, something MAY need to be done; this is why malloc() is deprecated in C++ and operator new should be used whenever possible.
Whether something needs to be done or not normally depends on the structure (or class), not if it's C or C++. In this case, a pointer within the structure needs to be initialized to NULL. In C++, this is done via "constructor" code for the struct or class, in C, it needs to be done "manually" in code every time a new instance of a struct is allocated, and a function to allocate and initialized a struct could be used if wanted.
 
rcgldr said:
Whether something needs to be done or not normally depends on the structure (or class), not if it's C or C++.

In C, a structure needn't be initialized to be used. That's not part of the language spec.

In C++, non-POD classes need initialization, which is part of the language spec.

In this case, a pointer within the structure needs to be initialized to NULL.

No. This is up to the programmer. It makes sense, ordinarily, but that is not a requirement.

In C++, this is done via "constructor" code for the struct or class

Even in C++ it is perfectly fine not to initialize members which are POD.
 
Borek said:
You can easily make it work by casting a pointer. There is no such thing as a "correct space for string", there are 16 bytes of memory.

I should have tried this earlier; I didn't have the confidence because I wouldn't be happy that what I did was a correct method to test anything! I decided to assign the address returned from malloc() to a char * pointer and then assign the address from the char * pointer to the struct pointer and then proceed from there, accessing the structure's pointer. I think this is a correct test.

voko said:
No operation needs to be done when the program is running for this "partitioning".



That is correct, and that is known to the compiler when the program is compiled. A structure is a contiguous block of memory starting at some address x. The compiler knows that field a is at a fixed offset from the beginning of the structure, and it knows that field b is at another fixed offset from the beginning of the structure. So your expression "x->a" is compiled to something like "take address from variable x and add offset_a bytes to it; this is the address where the field is". Likewise, "x->b" is compiled to "take address from x and add offset_b bytes to it; this is the address where the field is". offset_a and offset_b are compile-time constants (you could even obtain them with some creative use of C).

The point of that is NOTHING needs to be done to the memory allocated by malloc() to use it as a structure.

This is markedly different in C++. In C++, something MAY need to be done; this is why malloc() is deprecated in C++ and operator new should be used whenever possible.

Thanks voko, I appreciate Borek's response - it certainly helped - but yours is what made it "click"! Many thanks!
 

Similar threads

  • · Replies 4 ·
Replies
4
Views
3K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 19 ·
Replies
19
Views
3K
  • · Replies 17 ·
Replies
17
Views
3K
  • · Replies 6 ·
Replies
6
Views
8K
  • · Replies 17 ·
Replies
17
Views
3K
  • · Replies 1 ·
Replies
1
Views
11K
  • · Replies 6 ·
Replies
6
Views
3K
  • · Replies 3 ·
Replies
3
Views
1K