How to dynamically allocate memory for an array of structs - c

I am fairly new to C, and am having trouble figuring out how to allocate contiguous memory to an array of structs. In this assignment, we are given a shell of the code, and have to fill in the rest. Thus, I cannot change the variable names or function prototypes. This is what has been given to me:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct student {
int id;
int score;
};
struct student *allocate() {
/* Allocate memory for ten students */
/* return the pointer */
}
int main() {
struct student *stud = allocate();
return 0;
}
I'm just not sure how to go about doing what those comments say in the allocate function.

The simplest way to allocate and initialize the array is this:
struct student *allocate(void) {
/* Allocate and initialize memory for ten students */
return calloc(10, sizeof(struct student));
}
Notes:
calloc(), unlike malloc() initializes the memory block to all bits zero. Hence the fields id and score of all elements in the array are initialized to 0.
It would be a good idea to pass the number of students as an argument to the function allocate().
It is considered good style to free() allocated memory when you no longer need it. Your instructor did not hint that you should call free(stud); before returning from main(): while not strictly necessary (all memory allocated by the program is reclaimed by the system when the program exits), it is a good habit to take and makes it easier to locate memory leaks in larger programs.

Related

dynamic allocation of struct with Malloc

Iam begginner in C and dynamic allocation,
i would like to allocate a memory for a structure.
struct MusicTitle has the list of a music title and the signer structure has the name of the songs and number of album that he made.
struct musicTitle() // structure of music title
{
Char* nameofsong;
char* Singer_name;
Char * release_year; }
musicTitle* allocteMusicTitle(){ // function to allocate memory for the music title struct
musicTitle* musicTitlePtr= (musicTitle*)malloc(sizeof(musicTitle*));
return musicTitlePtr;
}
struct singer{ // each singer has musictitle and albums
musicTitle* musicTitleofsigner
int* nbrAlbum;
}
singerMusic* allocateSingerMusic {
singerMusic* singerMusicPtr= (singerMusic*)malloc(sizeof(singerMusic*)); //allocate memory for singerMusic struct
}
my question is, do i need to allocate memory for nbrAlbum of the singer structure? or it gonna be done with allocateSingerMusic function ?
Thank you
There are few syntax and logical problems with this code. For example
Missing semicolon.
musicTitle* musicTitleofsigner
and allocating memory with size of pointer rather than size of struct.
singerMusic* singerMusicPtr= (singerMusic*)malloc(sizeof(singerMusic*));
I hope, you will correct those mistakes. Answer to your main question is that you need to allocate memory for nbrAlbum. This is the power and beauty of C language that no dynamic memory will be allocated automatically unless it is done explicitly.

calloc sometimes gives double the amount of memory asked

I came across something I don't understand why and I'd like to hear an explanation about it.
I have this struct:
typedef struct Student {
int age;
char *name;
} Student;
int main()
{
Student **test1 = calloc(2, sizeof(*test1));
Student **test2 = calloc(2, sizeof(**test2));
return 0;
}
I've noticed that test1 gets 2 memory allocations (as it should) while test2 gets 4. Why is that and which is the correct usage? I assume its the first one but i'm not sure why.
Thanks!
sizeof(*test1) is the size of a pointer Student*, while sizeof(**test) is the size of a structure Student.The structure has a pointer, so its size should be larger than the size of a pointer.
Student **test1 = calloc(2, sizeof(*test1));
Is the typical usage. This is allocating 2-element array of Student* and assigning the pointer to its first element to test1.
Two things here:
You're allocating two different amounts of memory here. In the first case, you allocate space for 2 objects of type Student *, while in the second case you allocate space for 2 objects of type Student. The latter is likely larger than the former, so you'll be able to put more object of type Student * there.
You don't show how you're verifying how much memory you've gotten, but it's undefined behavior to read or write past the bounds of allocated memory. Your program might crash, or it might not.
sizeof(*test) is a size in bytes of the pointer to Student. It will be on most systems 4 or 8.
sizeof(**test)gives you the size of the Student. The allocation (test2) makes no sense at all.
You can easily test it yourself by printing the sizes:
#include <stdio.h>
#include <malloc.h>
typedef struct Student {
int age;
char *name;
double somedata[100];
} Student;
int main()
{
Student **test1;
Student **test2;
printf("%zu\n", sizeof(*test1));
printf("%zu\n", sizeof(**test2));
return 0;
}
https://godbolt.org/z/W6e8YzKKf

Dynamic memory allocation for structs in c

I am trying to initialise a struct by allocating memory to it and it's pointer members using malloc:
typedef struct {
char *name;
prob_t *prob;
} name_t;
I understand that I need to allocate memory to the pointers separately once the struct is initialised:
name_t
*init_name_dict() {
name_t *name_dict;
name_dict = (name_t*)malloc(MAX_LINES*sizeof(*name_dict));
name_dict->name = (char*)malloc(MAX_LEN*sizeof(*name_dict->name));
name_dict->prob = (prob_t*)malloc(MAX_PROB*sizeof(*name_dict->prob));
return name_dict;
}
But when I do so, it allocates memory to the struct, but not to either of its member pointers (they just point to junk).
What am I doing wrong? Thanks
As explained here, malloc doesn't "clean" the memory, that then can be full of garbage (because for example the same memory was returned by another call to malloc(), used and then free()). The three classical solutions are:
Live with it. Set manually all the members of the struct (if you are
using the malloc to allocate a struct) before using the struct (or in general set the all the obtained memory to the value you want)
Use memset to zero all the memory before using it
Use calloc instead of malloc (note that it has a slightly different signature). calloc is similar to malloc + memset. As an example:
name_t *init_name_dict() {
name_t *name_dict;
name_dict = calloc(MAX_LINES, sizeof(*name_dict));
name_dict->name = calloc(MAX_LEN, sizeof(*name_dict->name));
name_dict->prob = calloc(MAX_PROB, sizeof(*name_dict->prob));
return name_dict;
}
As a sidenote, in C you don't need/shouldn't cast a pointer returned by malloc/calloc (but if in truth you are using a C++ compiler then you have to cast it...).
If you want cleared memory (as opposed to memory with junk in it), you need calloc
instead of malloc, but that's trivial.
You're bigger problems are:
1) no error checking
2) possibly needless malloc calls
3) you're allocating MAX_LINES of theses name_t structure but initializing
only one of them
If the .name and .prob fields won't be reallocated, you should change your name_t
definition to
typedef struct { char name[MAX_LEN]; prob_t prob[MAX_PROB]; } name_t;
and allocate all MAX_LINES name_t's in one go: calloc(MAX_LINES, sizeof(name_t)).
If you need the original name_t structure, then I'd have an initializer for one:
int init_name_dict (name_t *this)
{
if(0==(this->name=calloc(MAX_LEN, sizeof *this->name))) return -1;
if(0==(this->prob=calloc(MAX_PROB, sizeof *this->prob))){ free(this->name); return -1; }
return 0;
}
a destructor for it
void destroy_name_dict(name_t *this) { free(this->name); free(this->prob); }
and then an initializing allocator for the whole array:
name_t* new_name_dicts(void)
{
name_t *r = malloc(MAX_LINES*sizeof *r);
if(!r) return r;
int i;
for(i=0; i<MAX_LINES; i++)
if(0>init_name_dict(&r[i])) goto fail;
return r;
fail:
for(--i; i>=0; --i)
destructor_name_dict(&r[i]);
return NULL;
}
(Basically what would amount to a C++ vector constructor that picks up the constructor for the
cell type.)
Struct
typedef struct {
char *name;
prob_t *prob;
} name_t;
has two pointers as members. So on 32 bit OS, sizeof(name_t) is 8 bytes.
Dynamic creation of instance of name_t struct
name_t *name_dict = (name_t*)malloc(sizeof(name_dict));
allocates only 8 bytes to store two pointers. As xanatos said allocated memory is garbage and pointers will point random locations. You can use calloc() when allocation name_dict or manually nullify them name_dict->name = NULL;name_dict->prob = NULL;. You can also don't bother yourself by content of pointers and in next code line allocate memory to members
name_dict->name = (char*)malloc(MAX_LEN*sizeof(char));
name_dict->prob = (prob_t*)malloc(sizeof(prob_t));
You can also check if memory was allocated good and both pointers don't ppoint to NULL.
To sum up, properly written init_name_dict() method
name_t * init_name_dict()
{
name_t *name_dict = (name_t*)malloc(sizeof(name_t));
if (name_dict != NULL)
{
name_dict->name = (char*)malloc(MAX_LEN*sizeof(char)));
name_dict->prob = (prob_t*)malloc(sizeof(prob_t));
}
return name_dict;
}
Errors in your code was
MAX_LINES here(assume that you want to create only one structure here)
name_dict = (name_t*)malloc(MAX_LINES*sizeof(*name_dict));
MAX_PROB here (assume that you want to create only one structure
here)
name_dict->prob = (prob_t*)malloc(MAX_PROB*sizeof(*name_dict->prob));

What is the difference between using malloc to allocate memory to a struct pointer and pointing a struct pointer to a struct's memory address?

What is the difference between these two snippets of code?
// Structure
struct file {
int fileSize;
};
int main(void) {
// Variables
struct file *pFile = (struct file*) malloc(sizeof(struct file)); // Declare pointer of type struct file and allocate enough room
pFile->fileSize = 5;
free(pFile);
return 0;
}
and
// Structure
struct file {
int fileSize;
} file1;
int main(void) {
// Variables
struct file *pFile = &file1; // Declare pointer of type struct file and point to file1 struct
pFile->fileSize = 5;
return 0;
}
Is there something big I'm missing here? I'm thinking maybe face value wise these are the same but the underlying memory allocation is different? I just can't grasp it.
There are several differences here:
With malloc you can repeat the call multiple times, and get new valid memory area for your struct; there is only one statically allocated struct
Memory obtained through malloc needs to be freed at the end; statically allocated memory does not need freeing
Statically allocated struct is visible from multiple functions inside the translation unit; memory from malloc is not shared with other functions unless you pass a pointer to them explicitly.
In your first snippet pFile points to dynamically-allocated memory.
In your second snippet, pFile points to a global variable.
Other than the fact that you need to free the dynamic one yourself (which you haven't by the way), the way you interact with the struct is exactly the same in either case.

Mallocing an Array in C

I have the following piece of code which I would expect to fail but seems to be working correctly. I'm confused by why this is not causing some sort of segmentation fault.
#include <stdio.h>
#include <stdlib.h>
struct entry {
int foo;
};
struct table {
int size;
struct entry* entries;
};
typedef struct table *Table;
typedef struct entry Entry;
int main() {
Table table = malloc(sizeof(struct table));
table->entries = malloc(sizeof(struct entry) * 1);
(table->entries)[5].foo = 5;
for (int i = 0; i < 10; i++) {
printf("Entry #%d: %d\n",i,(table->entries)[i].foo);
}
}
I would have expected that since I only malloced enough space for one entry in table->entries, accessing any index other than 0 would be out of bounds. But when I run this program it prints out 5 for as the foo value of the entry at index 5, and the rest as 0, which is the correct behavior. Why is this not failing?
Someone else will say it better, but Undefined Behavior is undefined.
It's not defined. It might work. It might not.
It all depends what is in those memory locations.
You wrote one bad location. You read some others. You happened to not hit anything
too important.
You wrote one word well past your malloc'ed area. Perhaps if you did more computations
that would cause trouble because you wrote into malloc's data structures. Maybe not.
You are accessing out of bounds, but that merely invokes 'undefined behaviour'. Anything may happen when you invoke 'undefined behaviour'. One possibility is that the program crashes; another is that the program does not crash and appears to be OK. Either is possible; it is even possible for it sometimes to crash and sometimes not crash.
If you tried more memory allocation, or tried freeing memory, you'd be more likely to see that things have gone wrong. However, even that's not guaranteed; you may have missed all the sensitive information (the bytes that are used by malloc() et al to determine which memory is allocated and which is not).
You can write:
table->entries[i].foo
You don't need the parentheses around (table->entries)[i].foo, though they're harmless except that they suggest a neophyte was coding.
Its not failing because despite you are writing to unallocated memory, this memory is perfectly inside the legal HEAP space. But sinse you didn't declare to the memory manager that you are using that memory space, a future malloc() may try to alloc to the same area, and you will get overlapping buffers and undefined behaviour.
This is undefined behavior that you are accessing memory location which is not 'yours'. You have writern some thing in memory which is not allocated by you, corrupting that memory location.
#include <stdio.h>
#include <stdlib.h>
struct entry {
int foo;
};
struct table {
int size;
struct entry* entries;
};
typedef struct table *Table;
typedef struct entry Entry;
int main() {
Table table =(table)malloc(sizeof(struct table));
table->entries =(entry*)malloc(sizeof(struct entry) * 10);
(table->entries)[5].foo = 5;
for (int i = 0; i < 10; i++) {
printf("Entry #%d: %d\n",i,(table->entries)[i].foo);
}
}
First, you need to convert the (void*) type into the pointer type you want when using malloc. Second, you only allocate entries pointers, which means, when you use (table->entries)[5].foo, you might access memory illegal, so it's a dangerous behavior. Finally, you need to initialize foo before you print it. You need to obey the rules, do not write codes like that.

Resources