Reputation: 11
I have this situation:
I'm trying to obfuscate some data in this way
/* item.h */
typedef struct ItemStruct *Item;
/*item.c*/
#include "item.h"
struct ItemStruct
{
char word[MAXSTRING];
int number;
};
Item ItemGet()
{
Item i;
i = (Item) malloc (sizeof(*i));
if (i == NULL)
{
fprintf ( stderr, "Error: insufficient memory for new element.\n");
return NULL;
}
return i;
}
Well, I used this malloc from a friend's solution:
i = (Item) malloc (sizeof(*i));
But at first I wrote this:
i = (Item*) malloc (sizeof(Item));
That gives me an "Incomplete type" error at every 'sizeof' I use for allocations.
I'm asking you why, because I don't understand this.
Upvotes: 1
Views: 1103
Reputation: 231
Either declaring the object visible in the interface to the module to an incomplete structure, or defining it to be a pointer to an incomplete structure are viable ways of information hiding. You should get an error regarding the incomplete type when code that does not have the definition of the structure elements tries to do somthing that requires knowing the size of that structure. (Declare a variable being most common). A common bug in this type of code is mistyping the name of the structure tag differently between its use in the typedef, and its use to declare the actual structure, this often results in errant errors about incomplete types in the implementation code.
Two sets of code follow. The files pitem.c pitem.h and pmain.c compile under gcc with -Wall with no warnings using the pointer approach. The files item.c item.h and main.c compile similarly using the incomplete structure approach.
Personally, I prefer the incomplete structure approach. The user of the interface knows they are dealing with a pointer in this approach. They have additional flexibility to initialize it to NULL as seen in main.c. Preference for this approach (as opposed to concealing the fact that the interface visible object is a pointer) is probably what tristopia's comment is referring to.
pitem.h
typedef struct ItemStruct *Item;
Item ItemGet();
pitem.c
#include "pitem.h"
#include <stdio.h>
#include <stdlib.h>
#define MAXSTRING 32
struct ItemStruct
{
char word[MAXSTRING];
int number;
};
Item ItemGet()
{
Item i;
i = (Item) malloc (sizeof(*i));
if (i == NULL)
{
fprintf ( stderr, "Error: insufficient memory for new element.\n");
return NULL;
}
return i;
}
pmain.c
#include "pitem.h"
int main(int argc , char **argv)
{
Item item;
(void) argc; /* not being used*/
(void) argv; /* not beign used*/
item = ItemGet();
(void)item; /* not being used */
return(0);
}
item.h
typedef struct ItemStruct Item;
Item *ItemGet();
item.c
#include "item.h"
#include <stdio.h>
#include <stdlib.h>
#define MAXSTRING 32
struct ItemStruct
{
char word[MAXSTRING];
int number;
};
Item *ItemGet()
{
Item *i;
i = (Item *) malloc (sizeof(*i));
if (i == NULL)
{
fprintf ( stderr, "Error: insufficient memory for new element.\n");
return NULL;
}
return i;
}
main.c
#include "item.h"
#include <stdlib.h>
int main(int argc , char **argv)
{
Item *pItem=NULL;
(void) argc; /* not being used*/
(void) argv; /* not beign used*/
pItem = ItemGet();
(void)pItem; /* not being used */
return(0);
}
Upvotes: 0
Reputation: 679
Your Item
is a pointer type. Your sizeof(Item)
returns the number of bytes required by that pointer. That's not the amount of memory you want to allocate. You want to allocate enough memory to store the pointed struct. And you're casting the result to a pointer to a pointer type, which makes little sense.
Each time you've got something like:
T* myPointer;
You have to allocate memory as:
myPointer = (T*)malloc(num_of_Ts * sizeof(T));
Equivalent to:
myPointer = (T*)malloc(num_of_Ts * sizeof *myPointer);
In your case, Item is your T*, and you want to allocate only 1 struct so:
i = (Item)malloc(sizeof(ItemStruct));
Equivalent to:
i = (Item)malloc(sizeof *i);
Note that you do not need to cast malloc's result in C (and it would be a good practice not to do that), whilst you are obliged to do that in C++.
Upvotes: 0
Reputation: 106052
Item
is defined as new type pointer to structure ItemStruct
. sizeof(Item)
will give the size of pointer to structure ItemStruct
, not the size of structure it self. Try this
i = malloc (sizeof(ItemStruct)); // or malloc (sizeof(*i))
About casting, malloc
returns void *
and itcan be assigned to any pointer without an explicit cast and never cast the return value of malloc
.
Upvotes: 2