I often find myself spending a lot of time figuring out how I should properly size a malloc when I have a non-obvious type. Here is an example:
typedef struct {
char* key;
char* value;
} hash_item;
typedef struct {
int size; // max size of the table
int count; // how many items are currently in the table
hash_item** items; // will have size * hash_items in the array
} hash_table;
Now, when I create a new hashtable, I'll do something like this:
hash_table *table = malloc(sizeof(hash_table));
table->items = malloc(sizeof(*hash_item) * size); // this is tricky for me
Is that 'sizing' correct? And how do I know that sizeof(*hash_item) is the correct unit-size, and not for example:
sizeof(hash_item)
sizeof(table->items[0])
sizeof(*(table->items))
Is there a good rule of tumb for how to size a malloc when it's referring to a non-primitive data-type?
You generally do not need to use types in the malloc size, and you should avoid it. You can use a “sample object” instead:
PointerToThing = malloc(NumberOfThings * sizeof *PointerToThing);
So that is very simple: *PointerToThing is the type of thing being pointed to, so its size is what you want.
Further, it reduces the chances of certain errors:
If you try typing a type description for what PointerToThing points to, you can make a mistake. *PointerToThing is simple, so people are less likely to make a mistake with it, especially once it becomes habit.
If you are modifying the program in the future and change the type of PointerToThing, you have to remember to also search for everywhere that type is used and change it there too. With the method above, the type does not appear, so it cannot be overlooked—there is no change to make when the type changes; the sizeof adapts automatically to whatever type *PointerToThing is.
And PointerToThing does not have to be a simple variable. It can be an expression, such as table->items, for which you could use malloc(NumberOfItems * sizeof *table->items).
Related
I am trying to write "any" kind of struct to a void array (Basically I'm trying to define an arraylist in C for any kind of datatype. I know that implementations already exist but I'm trying to learn because I'm kind of a beginner in C). I know how big the "data to add" is and I have the location in memory and know where the data should be placed. This is the current function that I came up with it but it doesn't work:
void addData(List *c, void* Item) {
c->data = realloc(c->data, c->amountOfItems+1);
((char*)c->data)[c->dataTypeInBytes * c->amountOfItems - c->dataTypeInBytes] = Item;
c->amountOfItems++;
}
c-> Data is a void malloc pointer. void* Item is the item to be added.
Basically, I try to put the Item value at the last (char*) location in c->data.
What exactly am I doing wrong? Also, what would be the best approach to get the data again from the allocated memory? My approach would be to convert c->data to a char* array and go to c->data[c->dataTypeInBytes * c->amountOfItems - c->dataTypeInBytes] and get c->dataTypeInBytes bytes. put each of those bytes in a char array with c->dataTypeInBytes length and return a void pointer to that, which then gets casted to the correct datatype outside the function. Would there be a better way to do that or straight up "define" a datatype with a specific size in Bits?
I have, roughly speaking, a function prototype like this:
init_superstruct(const char *name, Superstruct **super, int num_substructs) {...
where superstruct looks like
typedef struct superstruct {
char *name,
Substruct **substructs,
int num_substructs;
} Superstruct
The function is supposed to
1) allocate memory for (and initialize) super, by...
2) ...assigning the name field of super enough memory to hold the name argument, and...
3) ...assigning the substructs field enough memory to hold an array pointers to Substructs (of size num_substructs).
My question: will the following code accomplish these goals?
*super = malloc(sizeof(*super));
*super->name = malloc(sizeof(strlen(name) + 1)));
*super->substructs = calloc(num_substructs, sizeof(Substruct));
This is literally my first foray into dynamic memory allocation. Any advice you have would be helpful for me!
First:
*super = malloc(sizeof(*super));
You want sizeof(**super). *super is a pointer, with type Superstruct *, so this won't allocate enough memory.
Really, you should probably allocate the structure normally, then assign it to the pointer separately. This will make your code much easier to write:
Superstruct *r = malloc(sizeof *r);
r->name = …
*super = r;
Second:
*super->name = malloc(sizeof(strlen(name) + 1)));
This is wrong. sizeof(strlen(name) + 1) is sizeof(int) (or perhaps sizeof(size_t); either way it's not what you want) -- strlen() won't even be called! Remove the sizeof() from this expression to make it correct.
Third: to allocate a single array of Substruct objects, define the structure member as Substruct *substructs, and allocate it using the exact code you've got right now. You don't need a double pointer unless you want an array of pointers to the structures, which is more complicated than you need.
If you really think you do need an array of pointers here (you probably don't), you need to allocate the array using sizeof(Substruct *) as the size argument to calloc(), not sizeof(Substruct).
The CoreAudio framework uses a struct that is declared like this:
struct AudioBufferList
{
UInt32 mNumberBuffers;
AudioBuffer mBuffers[1]; // this is a variable length array of mNumberBuffers elements
};
typedef struct AudioBufferList AudioBufferList;
As far as I can tell, this is basically a variable length collection of AudioBuffer structs. What is the 'correct' way to malloc such a struct?
AudioBufferList *list = (AudioBufferList *)malloc(sizeof(AudioBufferList));
Would this work?
I've seen all kinds of examples around the internet, like
calloc(1, offsetof(AudioBufferList, mBuffers) +
(sizeof(AudioBuffer) * numBuffers))
or
malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * (numBuffers - 1))
That's not a variable length array; it's a 'struct hack'. The standard (since C99) technique uses a 'flexible array member', which would look this:
struct AudioBufferList
{
UInt32 mNumberBuffers;
AudioBuffer mBuffers[]; // flexible array member
};
One of the advantages of the FAM is that your questions are 'irrelevant'; the correct way to allocate the space for numBuffer elements in the mBuffers array is:
size_t n_bytes = sizeof(struct AudioBufferList) + numBuffer * sizeof(AudioBuffer);
struct AudioBufferList *bp = malloc(nbytes);
To answer your question, in practice both the malloc() and the calloc() will allocate at least enough space for the job, but nothing in any C standard guarantees that the code will work. Having said that, compiler writers know that the idiom is used and usually won't go out of their way to break it.
Unless space is incredibly tight, it might be simplest to use the same expression as would be used with a FAM; at worst, you have a little more space allocated than you absolutely need allocated. It will continue to work when you upgrade the code to use a FAM. The expression used in the calloc() version would also work with a FAM member; the expression used in the malloc() version would suddenly be allocating too little space.
Work out how much memory you need and malloc that amount. For example if you want 9 more AudioBuffers then
list = malloc( sizeof *list + 9 * sizeof list->mBuffers[0] );
This entire construct is non-portable by the way (the behaviour is undefined if they access beyond the bound of mBuffers, which is 1), but it used to be reasonably common.
Note that you should not cast the value returned by malloc. There's no benefit to be gained by doing so, but there is harm that can be done.
There is a standard construct which is similar; if you remove the 1 from the definition of AudioBufferList (and malloc one more unit). This is called "flexible array member".
The preferred way to do this is to use the Apple-provided CAAudioBufferList::Create function from CAAudioBufferList.cpp in the Core Audio Utility Classes. You can download the sources here:
https://developer.apple.com/library/mac/samplecode/CoreAudioUtilityClasses/Introduction/Intro.html
Here is their implementation:
AudioBufferList* CAAudioBufferList::Create(UInt32 inNumberBuffers)
{
UInt32 theSize = CalculateByteSize(inNumberBuffers);
AudioBufferList* theAnswer = static_cast<AudioBufferList*>(calloc(1, theSize));
if(theAnswer != NULL)
{
theAnswer->mNumberBuffers = inNumberBuffers;
}
return theAnswer;
}
void CAAudioBufferList::Destroy(AudioBufferList* inBufferList)
{
free(inBufferList);
}
UInt32 CAAudioBufferList::CalculateByteSize(UInt32 inNumberBuffers)
{
UInt32 theSize = SizeOf32(AudioBufferList) - SizeOf32(AudioBuffer);
theSize += inNumberBuffers * SizeOf32(AudioBuffer);
return theSize;
}
I am having a problem with creating a function that will add (copy) structure from parameter to resized array.
Here is my simplified code:
typedef struct User
{
char FirstName[32];
char LastName[32];
}
User;
User * Users
unsigned short UsersNum = 0;
void AddUser(User * NewUser)
{
Users = (User *) realloc(Users, (UsersNum + 1) * sizeof(User));
memcpy(Users[UsersNum], NewUser, sizeof(User));
UsersNum++;
}
With this I'm getting:
error: incompatible type for argument 1 of `memcpy'
I've also tried
memcpy(Users + UsersNum, NewUser, sizeof(User));
But got SEGFAULT.
How can i copy NewUser to the end of Users?
First, please don't cast the return value of malloc() in C.
Second, why do you feel you must use memcpy() here? The memcpy() function is great, but it's a rather blunt tool meant to "blindly" copy large areas of memory that have no further structure that the program is aware of. In your case, you know that the bytes you're copying make up an instance of the User type, i.e. it's simply a value of type User.
Values are typically moved around by assignment, so use that instead:
void AddUser(const User *NewUser)
{
User *UsersGrown = realloc(Users, (UsersNum + 1) * sizeof *Users);
if(UsersGrown != NULL)
{
Users = UsersGrown;
Users[UsersNum] = *NewUser;
++UsersNum;
}
}
You can see that I also made the argument const, and added some basic error-checking since realloc() can fail.
It would be a good idea to separate the allocated size of the Users array from the length of the array, so that you can grow them at different speeds and cut down on the number of calls to realloc(). In other words, allocate room for e.g. 8 elements at first, and when that is hit, double the size and realloc(), and so on. This gives much better performance if you expect many insertions.
You should ask yourself what type is User[UsersNum] ... that is User, and memcpy operates on pointers. To get address of it there is & operand. So it should be
memcpy(&Users[UsersNum], NewUser, sizeof(User));
Also please note the you are using very very inefficient way to implement the functionality. Copying/moving stuff around so much should be avoided.
is it possible to 'dynamically' allocate file pointers in C?
What I mean is this :
FILE **fptr;
fptr = (FILE **)calloc(n, sizeof(FILE*));
where n is an integer value.
I need an array of pointer values, but I don't know how many before I get a user-input, so I can't hard-code it in.
Any help would be wonderful!
You're trying to implement what's sometimes called a flexible array (or flex array), that is, an array that changes size dynamically over the life of the program.) Such an entity doesn't exist among in C's native type system, so you have to implement it yourself. In the following, I'll assume that T is the type of element in the array, since the idea doesn't have anything to do with any specific type of content. (In your case, T is FILE *.)
More or less, you want a struct that looks like this:
struct flexarray {
T *array;
int size;
}
and a family of functions to initialize and manipulate this structure. First, let's look at the basic accessors:
T fa_get(struct flexarray *fa, int i) { return fa->array[i]; }
void fa_set(struct flexarray *fa, int i, T p) { fa->array[i] = p; }
int fa_size(struct flexarray *fa) { return fa->size; }
Note that in the interests of brevity these functions don't do any error checking. In real life, you should add bounds-checking to fa_get and fa_set. These functions assume that the flexarray is already initialized, but don't show how to do that:
void fa_init(struct flexarray *fa) {
fa->array = NULL;
fa->size = 0;
}
Note that this starts out the flexarray as empty. It's common to make such an initializer create an array of a fixed minimum size, but starting at size zero makes sure you exercise your array growth code (shown below) and costs almost nothing in most practical circumstances.
And finally, how do you make a flexarray bigger? It's actually very simple:
void fa_grow(struct flexarray *fa) {
int newsize = (fa->size + 1) * 2;
T *newarray = malloc(newsize * sizeof(T));
if (!newarray) {
// handle error
return;
}
memcpy(newaray, fa->array, fa->size * sizeof(T));
free(fa->array);
fa->array = newarray;
fa->size = newsize;
}
Note that the new elements in the flexarray are uninitialized, so you should arrange to store something to each new index i before fetching from it.
Growing flexarrays by some constant multiplier each time is generally speaking a good idea. If instead you increase it's size by a constant increment, you spend quadratic time copying elements of the array around.
I haven't showed the code to shrink an array, but it's very similar to the growth code,
Any way it's just pointers so you can allocate memory for them
but don't forget to fclose() each file pointer and then free() the memory