0

Imagine I've the following struct

struct Memory {
    int type;
    int prot;
};

typedef struct Memory *Memory;

How would I initialise it using malloc()?

Memory mem = malloc(sizeof(Memory));

or

Memory mem = malloc(sizeof(struct Memory));

What is the correct way to allocate that?

moeseth
  • 1,855
  • 5
  • 23
  • 47
  • 5
    Your `typedef` is wrong on so many levels... it's an accident waiting to happen, really. Either way, write `struct memory { };` then allocate like so `struct memory *mem = malloc(sizeof *mem);` – Elias Van Ootegem Apr 07 '15 at 08:37
  • How much memory do you think you need to allocate an object? Maybe the size of the type of the object you want to allocate? – juanchopanza Apr 07 '15 at 08:38
  • @EliasVanOotegem thanks. so what's the correct size it should be? is it 8 bytes or 4 bytes? – moeseth Apr 07 '15 at 08:45
  • @juanchopanza, that's what i'm not sure of. I would to use my struct as pointer i.e. mem->type = 1; instead of mem.type = 1. So my struct should be 8 bytes or 4 bytes? – moeseth Apr 07 '15 at 08:46
  • You really should spend some time learning what struct and pointers are, because you seem to hace some misconceptions. You can't "use my struct as pointer". – juanchopanza Apr 07 '15 at 08:48
  • @moeseth: I've posted an answer. Basically, It's not that easy to predict the size of the memory that'll be allocated (do a google search about data alignment). It depends on the architecture, the compiler (and certain directives), the size of `int` (according to the standard it's _at least_ 2 bytes, it generally is 4) and a couple of other things... – Elias Van Ootegem Apr 07 '15 at 08:49
  • @moeseth: your struct will be the same size, whether you've allocated it on the heap or on stack. The way you access it (directly or through a pointer) does not affect its size at all. The size of a pointer is a constant (4 on 32 bit 8 on 64bit systems). As I've explained before: the size of the struct depends on a number of things, but whether it's in stack or heap, its size will be the same – Elias Van Ootegem Apr 07 '15 at 08:51

3 Answers3

10

Your struct declaration is a bit muddled up, and the typedef is wrong on many levels. Here's what I'd suggest:

//typedef + decl in one
typedef struct _memory {
    int type;
    int prot;
} Memory;

Then allocate like so:

Memory *mem = malloc(sizeof *mem);

Read the malloc call like so: "Allocate the amount of memory required to store whatever type mem is pointing to". If you change Memory *mem to Memory **mem, it'll allocate 4 or 8 bytes (depending on the platform), as it now stands it'll probably allocate 8 bytes, depending on the size of int and how the compiler pads the struct check wiki for more details and examples.

Using sizeof *<the-pointer> is generally considered to be the better way of allocating memory, but if you want, you can write:

Memory *mem = malloc(sizeof(Memory));
Memory *mem = malloc(sizeof(struct _memory));

They all do the same thing. Mind you, if you typedef a struct, that's probably because you want to abstract the inner workings of something, and want to write an API of sorts. In that case, you should discourage the use of struct _memory as much as possible, in favour of Memory or *<the-pointer> anyway

If you want to typedef a pointer, then you can write this:

typedef struct _memory {
    int type;
    int prot;
} *Memory_p;

In which case this:

Memory_p mem = malloc(sizeof *mem);

might seem counter intuitive, but is correct, as is:

Memory_p mem = malloc(sizeof(struct _memory));

But this:

Memory_p mem = malloc(sizeof(Memory_p));

is wrong (it won't allocate the memory required for the struct, but memory to store a pointer to it).

It's a matter of personal preference, perhaps, but I personally find typedefs obscure certain things. In many cases this is for the better (ie FILE*), but once an API starts hiding the fact you're working with pointers, I start to worry a bit. It tends to make code harder to read, debug and document...

Just think about it like this:

int *pointer, stack;

The * operator modifies a variable of a given type, a pointer typedef does both. That's just my opinion, I'm sure there are many programmers that are far more skilled than me who do use pointer typedefs.
Most of the time, though, a pointer typedef is accompanied by custom allocator functions or macro's, so you don't have to write odd-looking statements like Memory_p mem = malloc(sizeof *mem);, but instead you can write ALLOC_MEM_P(mem, 1); which could be defined as:

#define ALLOC_MEM_P(var_name, count) Memory_p var_name = malloc(count * sizeof *var_name)

or something

jmcnamara
  • 38,196
  • 6
  • 90
  • 108
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • 1
    Even in the case of abstraction - hiding struct members by using incomplete/opaque type, I would still not hide the pointer inside the typedef. Because if you do, the user will treat the variable of that type as a chunk of data and not as a pointer. And in case of incomplete/opaque type, you'd leave the allocation to a "member function" of that code module, and not to the user. [Here is an example](http://stackoverflow.com/questions/13032015/how-to-implement-a-class-in-c/13032531#13032531). – Lundin Apr 07 '15 at 09:48
  • @Lundin: I completely agree. I don't think pointer typedefs are a good idea, I thought I made that clear (if not, I'll edit my answer). And I also agree with you that, if you `typedef` an incomplete type in a header somewhere, you need to offer a complete API anyway, including allocation functions as is the case with [the lib I'm currently working with](https://github.com/edenhill/librdkafka) which does **not** use pointer typedefs but does use incomplete types – Elias Van Ootegem Apr 07 '15 at 10:45
2

Both

 typedef struct Memory * Memory;

and

 Memory mem = malloc (sizeof (Memory));

are wrong. The correct way to do it is :

typedef struct memory
{
     int type;
     int prot;
} *MEMPTR;

or

struct memory
{
     int type;
     int prot;
};

typedef struct memory *MEMPTR;

The name of the structure should be different than the name of a pointer to it.

Bregalad
  • 634
  • 7
  • 15
2

This construction

struct {
    int type;
    int prot;
} Memory;

defines an object with name Memory that has type of unnamed structure.

Thus the next construction

typedef struct Memory *Memory;

defined 1) a new type struct Memory that has nothing common with the definition above and the name Memory. and 2) another new type name Memory that is pointer to struct Memory.

If the both constructions are present in the same compilation unit then the compiler will issue an error because name Memory (the name of the pointer) in the typedef declaration tries to redeclare the object of the type of the unnamed structure with the same name Memory.

I think you mean the following

typedef struct Memory {
    int type;
    int prot;
} Memory;

In this case you may use the both records of using malloc like

Memory *mem = malloc( sizeof( Memory ) );

and

struct Memory *mem = malloc( sizeof( struct Memory ) );

or

Memory *mem = malloc( sizeof( struct Memory ) );

or

struct Memory *mem = malloc( sizeof( Memory ) );

because now the two identifiers Memory are in two different name spaces, The first one is used with tag struct and the second is used without tag struct.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335