0

I tried to find the proper way to dynamically allocate memory for a structure that looks like this:

typedef struct myThread {
    unsigned int threadId;
    char threadPriority;
    unsigned int timeSlice;
    sem_t threadSem;
} myThread;

I remember, but I'm not sure, that, in some school paper, I saw that the proper way to allocate memory for this case is this one:

myThread *node = (myThread *)malloc(sizeof(myThread *));

I tried that and it worked, but I didn't understand why. Sizeof pointer for my architecture is 8 bytes, so by writing the instruction above, I'm allocating 8 bytes of continuous memory, not enough to hold the information needed in my structure. So I tried to allocate 1 byte of memory, like this:

myThread *node = (myThread *)malloc(1);

And it's still working. I tried to find the answer for this behavior but I didn't succeed. Why is this working? Besides that, I have few more questions:

  • Which is the right way to dynamically allocate memory for a structure?
  • Is that cast necessary?
  • How is the structure stored in memory? I know that (*node).threadId is equivalent to node->threadId and this confuses me a bit because by dereferencing the pointer to the structure, I get the whole structure, and then I have to access a specific field. I was expecting to access fields knowing the address of the structure in this way: *(node) it's the value for the first element, *(node + sizeof(firstElement)) it's the value for the second and so on. I thought that accessing structure fields it's similar to accessing array values.

Thank you

Later Edit: Thank you for your answers, but I realized that I didn't explained myself properly. By saying that it works, I mean that it worked to store values in those specific fields of the structure and use them later. I tested that by filling up the fields and printing them afterwards. I wonder why is this working, why I can fill and work with fields of the structure for which I allocated just one byte of memory.

10
  • myThread *node = (myThread *)malloc(sizeof(myThread *)); must be myThread *node = (myThread *)malloc(sizeof(myThread)); and the cast is useless so finally myThread *node = malloc(sizeof(myThread)); Commented May 3, 2020 at 10:13
  • a.b is the syntax for accessing field named b in a struct object a Commented May 3, 2020 at 10:14
  • 5
    T *p = malloc( sizeof *p ); is a good pattern Commented May 3, 2020 at 10:14
  • 1
    Why is this working? Undefined behaviour, anything can happen (including "code working") Commented May 3, 2020 at 10:15
  • Either sizeof(myThread) or sizeof(*node). The latter is more "robust" in the sense that it allows you to change the type of *node without changing this assignment. Commented May 3, 2020 at 10:21

4 Answers 4

3

The below works in that they allocate memory - yet the wrong size.

myThread *node = (myThread *)malloc(sizeof(myThread *));// wrong size,s/b sizeof(myThread) 
myThread *node = (myThread *)malloc(1);                 // wrong size 

Why is this working?

When code attempts to save data to that address, the wrong size may or may not become apparent. It is undefined behavior (UB).

C is coding without training wheels. When code has UB like not allocating enough memory and using it, it does not have to fail, it might fail, now or later or next Tuesday.

myThread *node = (myThread *)malloc(1);  // too small
node->timeSlice = 42;  // undefined behavior

Which is the right way to dynamically allocate memory for a structure? @M.M

The below is easy to code right, review and maintain.

p = malloc(sizeof *p);  //no cast, no type involved.
// or
number_of_elements = 1;
p = malloc(sizeof *p * number_of_elements);

// Robust code does error checking looking for out-of-memory
if (p == NULL) {
  Handle_error();
}

Is that cast necessary?

No. Do I cast the result of malloc?

How is the structure stored in memory?

Each member followed by potential padding. It is implementation dependent.

unsigned int
maybe some padding
char
maybe some padding
unsigned int
maybe some padding
sem_t
maybe some padding

I wonder why is this working, why I can fill and work with fields of the structure for which I allocated just one byte of memory.

OP is looking for a reason why it works.

Perhaps memory allocation is done in chunks of 64-bytes or something exceeding sizeof *p so allocating 1 had same effect as sizeof *p.

Perhaps the later memory area now corrupted by code's use of scant allocation will manifest itself later.

Perhaps the allocater is a malevolent beast toying with OP, only to wipe out the hard drive next April 1. (Nefarious code often takes advantage of UB to infect systems - this is not so far-fetched)

Its all UB. Anything may happen.

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

4 Comments

Thank you for your answer, please take a look at the edit and try to answer afterwards, I realized that I didn't explain myself properly
What OP and UB means?
@Andrei Deatcu OP: Original poster - that is you in this case.
@AndreiDeatcu "It is undefined behavior (UB)." UB details referenced in link above.. In effect: code breaks the rules, compiler can do what ever it wants.
1

Since memory allocation in C is quite error prone I always define macro functions NEW and NEW_ARRAY as in the example below. This makes memory allocation more safe and succinct.

#include <semaphore.h> /*POSIX*/
#include <stdio.h>
#include <stdlib.h>

#define NEW_ARRAY(ptr, n) \
    { \
        (ptr) = malloc((sizeof (ptr)[0]) * (n)); \
        if ((ptr) == NULL) { \
            fprintf(stderr, "error: Memory exhausted\n"); \
            exit(EXIT_FAILURE); \
        } \
    }

#define NEW(ptr) NEW_ARRAY((ptr), 1)

typedef struct myThread {
    unsigned int threadId;
    char threadPriority;
    unsigned int timeSlice;
    sem_t threadSem;
} myThread;

int main(void)
{
    myThread *node;
    myThread **nodes;
    int nodesLen = 100;

    NEW(node);
    NEW_ARRAY(nodes, nodesLen);
    /*...*/
    free(nodes);
    free(node);
    return 0;
}

9 Comments

I would not call using macros for allocation "clearly expressed" but I guess its own preference :)
@TonyTannous The point is that you don't have to fiddle with the sizeof operator each time you allocate dynamic memory.
"more safe" --> A corner weakness to this approach is when the size is more complex that an n. Consider int r; int c; NEW_ARRAY(nodes, r*c); performs the r*c multiplication using int math. With large r,c this may overflow whereas sizeof (ptr)[0] * r *c might not. r,c,n as size_t avoids this as well as re-ordering macro's multiplication sizeof (ptr)[0] * n or having an explicit NEW_ARRAY_2D(nodes, r, c); with sizeof (ptr)[0] * (r) * (c).
@chux-ReinstateMonica Thanks for pointing this out. I have now corrected the order of the multiplication in the malloc parameter.
@AugustKarlstrom Er. the order of (sizeof (ptr)[0]) * (n) vs. (n) * (sizeof (ptr)[0]) makes not difference as the () forces the int multiplication. The idea of sizeof (ptr)[0] * n, with the ()` would cause NEW_ARRAY(nodes, r*c) to multiply the ``sizeof (ptr)[0] * r` first. In general I see no win-win approach with in the corner case and thus prefer code vs. macro. Yet I do like ideas about the macro.
|
0

malloc reserves memory for you to use.

When you attempt to use more memory than you requested, several results are possible, including:

  • Your program accesses memory it should not, but nothing breaks.
  • Your program accesses memory it should not, and this damages other data that your program needs, so your program fails.
  • Your program attempts to access memory that is not mapped in its virtual address space, and a trap is caused.
  • Optimization by the compiler transforms your program in an unexpected way, and strange errors occur.

Thus, it would not be surprising either that your program appears to work when you fail to allocate enough memory or that your program breaks when you fail to allocate enough memory.

Which is the right way to dynamically allocate memory for a structure?

Good code is myThread *node = malloc(sizeof *node);.

Is that cast necessary?

No, not in C.

How is the structure stored in memory? I know that (*node).threadId is equivalent to node->threadId and this confuses me a bit because by dereferencing the pointer to the structure, I get the whole structure, and then I have to access a specific field. I was expecting to access fields knowing the address of the structure in this way: *(node) it's the value for the first element, *(node + sizeof(firstElement)) it's the value for the second and so on. I thought that accessing structure fields it's similar to accessing array values.

The structure is stored in memory as a sequence of bytes, as all objects in C are. You do not need to do any byte or pointer calculations because the compiler does it for you. When you write node->timeSlice, for example, the compiler takes the pointer node, adds the offset to the member timeSlice, and uses the result to access the memory where the member timeSlice is stored.

Comments

0

you do not allocate the right size doing

myThread *node = (myThread *)malloc(sizeof(myThread *));

the right way can be for instance

myThread *node = (myThread *)malloc(sizeof(myThread));

and the cast is useless so finally

myThread *node = malloc(sizeof(myThread));

or as said in remarks to your question

myThread *node = malloc(sizeof(*node));

The reason is you allocate a myThread not a pointer to, so the size to allocate is the size of myThread

If you allocate sizeof(myThread *) that means you want a myThread ** rather than a myThread *

I know that (*node).threadId is equivalent to node->threadI

yes, -> dereference while . does not

Having myThread node; to access the field threadId you do node.threadId, but having a pointer to you need to deference whatever the way


Later Edit: ...

Not allocating enough when you access out of the allocated block the behavior is undefined, that means anything can happen, including nothing bad visible immediately

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.