Initialize an empty nested struct using a function - c

I have to initialize tCoworking coworking by implementing init_coworking function that is declared at the end.
/* Constants *********************************************************/
#define nWorkSpaces 50
#define unlimited 2000
/* Types *************************************************************/
typedef enum {tableFlex, tableFix, officeFix} rate;
typedef char string[55];
typedef struct {
int reservationId;
float monthPayment;
} tContractAnnex;
typedef struct {
int id;
string name;
int discount;
} tPartner;
typedef struct {
int id;
float surface;
rate rateType;
} tWorkspace;
typedef struct {
int partnerId;
int month;
int year;
tContractAnnex annex;
} tContract;
typedef struct {
tWorkspace workSpace[nWorkSpaces];
tContract contract[unlimited];
tPartner partner[unlimited];
} tCoworking;
/* Function declaration */
void init_coworking(tCoworking *coworking);
As you can see the problem I have is that tCoworking is a nested struct with array of stucts as data types..
So far I'm doing this in order to initialize it but it must be a better way to do it.
void init_coworking(tCoworking *coworking){
coworking = malloc(sizeof(tCoworking));
coworking->partner[0].id = 0;
coworking->partner[0].discount = 0;
strcpy(coworking->partner[0].name, "");
coworking->workSpace[0].id = 0;
coworking->workSpace[0].rateType = 0;
coworking->workSpace[0].surface = 0;
coworking->contract[0].partnerId = 0;
coworking->contract[0].year = 0;
coworking->contract[0].month = 0;
coworking->contract[0].annex.monthPayment = 0;
coworking->contract[0].annex.reservationId = 0;
}

void init_coworking(tCoworking *coworking) {
coworking && memset( coworking, 0, sizeof( tCoworking ) );
}
memset initializes a block of memory - of specifiable length - to a single byte value. Your example indicates that you desire zero-initialization of the entire object, so memset serves this purpose well.
NULL-check your input argument.
I recommend you not malloc or calloc in your function because your function signature implies that the caller is the owner of the tCoworking. If you malloc within your init_coworking() function, then you'll have created a new heap-allocated instance of a tCoworking with no clear ownership. You can try keep track of newly-allocated objects in some type of container, but that's going far beyond the scope of your question -- keep it simple.

The simplest way is to use calloc. Like malloc it allocates memory for you but it also sets all the memory to zero.
However - more important is that your current function doesn't make sense. The memory you allocate is simply lost. The caller of init_coworking will never get the allocated and initialized memory.
Either you should:
Not do any malloc(or calloc)
or
Return the malloced pointer.
Since the prototype suggest that you get a tCoworking pointer, the most likely thing is that it's already allocated (in some way), i.e. you want option 1.
So just do:
void init_coworking(tCoworking *coworking){ // NO malloc
memset(coworking, 0, sizeof(tCoworking));
}
In case you only want the first array member set to zero (like your code indicates) you may get a little performance improvement by:
void init_coworking(tCoworking *coworking){ // NO malloc
memset(&coworking->partner[0], 0, sizeof(coworking->partner[0]));
... similar for the other arrays ...
}
but I doubt that's worth the trouble...

Related

How can I return different address of structs?

I have a array of structs in the main function and I would like to save data of few structs. I'm using a function that receive the wanted data and put it into struct that is defined into the function.
At the end of the process I return the address of this struct.
But if I call to this function few times ,it always defines the same address of the struct so I am losing a data of the previous call.
#include<stdio.h>
struct data {
int day;
};
struct data* Dates(int val);
int main() {
struct data* Dates1[3];
int array[] = { 12, 15, 2021 };
for (int i = 0; i < 3; i++) {
Dates1[i] = Dates(array[i]);
}
}
struct data* Dates(int val) {
struct data Date;
Date.day = val;
return &Date; ///AFTER EVERY CALL TO THIS FUNCTION IT RETURN THE SAME ADDRESS!!!
}
When you call a function, it creates a stack frame. Local variables to that function are allocated within that stack frame. When the function exits, the stack frame is "destroyed". That memory can be reused.
You're seeing this behavior because each time you call the function in your loop, it reuses the same memory space.
You cannot rely on the validity of an address to a variable allocated on the stack outside of the current function call. If you need a value to live on after the function call, you need to dynamically allocate it - typically with malloc. Just don't forget to free that memory when you're done with it.
You have to write you function as something like this:
struct data* Date = (struct data*) malloc(sizeof(struct data))
Date->day = val;
return Date;
Afterwards you have to call free() on the pointer when it is no longer used. (if not this is called a memory leak)
When you are confused keep in mind the simple rule that you can only return pointers up to that call level where the variable pointing too was created.
If you want to learn why this is, you should read up on what a call stack is and how stack variables work.
If you don't want to use malloc, an alternative is have the function take in a pointer to the uninitialized value, void Dates(struct data *, int);, then the caller is responsible for the memory.
#include <stdio.h>
#include <assert.h>
struct data {
int day;
};
static void Dates(struct data *const data, const int val) {
assert(data); /* Defensive debug. */
data->day = val;
}
int main(void) {
int array[] = { 12, 15, 2021 };
struct data dates1[sizeof array / sizeof *array];
for(int i = 0; i < sizeof dates1 / sizeof *dates1; i++)
{
Dates(dates1 + i, array[i]);
printf("%d: %d\n", i, dates1[i].day);
}
}
This can be better suited for when one wants a memory-allocation-agnostic function; in this example, I've reserved memory on the heap instead of dynamically.

Segmentation Fault while trying to fill a list [duplicate]

Suppose I have the following struct and function returning a pointer:
typedef struct {
int num;
void *nums;
int size;
} Mystruct;
Mystruct *mystruct(int num, int size)
{
//Is the following correct? Is there a more efficient way?
Mystruct mystruct;
mystruct.num = num;
mystruct.size = size;
mystruct.nums = malloc(num*sizeof(size));
Mystruct *my;
*my = mystruct;
return my;
}
I want to define any Mystruct pointer using the above function. Should I declare a Mystruct variable, define the properties of Mystruct, assign a pointer to it, and return the pointer or define the properties of a mystruct property through a pointer immediately?
Should I declare a Mystruct variable,
define the properties of Mystruct,
assign a pointer to it, and return the
pointer
Definitely not, because the variable defined in the function (in "auto" storage class) will disappear as the function exits, and you'll return a dangling pointer.
You could accept a pointer to a Mystruct (caller's responsibility to allocate that) and fill it in; or, you can use malloc to create a new one (caller's responsibility to free it when it's done). The second option at least lets you keep the function signature you seem to be keen on:
Mystruct *mystruct(int num, int size)
{
Mystruct *p = malloc(sizeof(MyStruct));
....
return p;
}
but it's often an inferior one -- since the caller has to have responsibilities anyway, may as well go with the first option and potentially gain performance (if the caller can use an auto-class instance because it knows the scope of use is bounded).
You can't use the variable because it will be deallocated when the function exits. For example:
Mystruct *mystruct(int num, int size)
{
MyStruct x;
x.num = 1;
...
return &x;
}
Will give a segmentation fault or access violation because the memory for x is deallocated as soon as you exit. So you have to allocate memory for the struct (and be sure to free it up later) or declare a global that will stay around for ever. Example for the latter...
Mystruct *mystruct(int num, int size)
{
MyStruct *x;
x = (MyStruct*)malloc( sizeof( MyStruct ) );
x->num = 1;
...
return x;
}
If you are writing generic code and you don't know how it may be used, it's good to provide both options:
int mystructm(Mystruct *storage, int num, int size)
{
int rv = 0;
storage->num = num;
storage->size = size;
storage->nums = malloc(num*sizeof(size));
if (!storage->nums)
return -1;
return 0;
}
Mystruct *mystruct(int num, int size)
{
Mystruct *mp = (Mystruct *)malloc(sizeof(Mystruct));
if (mp)
{
if (mystructm(mp, num, size) == -1)
{
free(mp);
mp = NULL;
}
}
return mp;
}
The idea is that as a library writer, you shouldn't dictate policy (such as that each Mystruct must be dynamically allocated) but should let the application writer decide that.
It's important to remember that the pointer is not something you assign to the structure, but rather the pointer indicates the location in memory that you wish to treat as a structure. Based on your question, you really want to allocate the memory to hold the data structure. This gives you a pointer to the memory location allocated. Once you have that, you can return it.
EDIT (after edit to original question)
Looking at your edit to the question, you definitely will have problems with the "my" pointer. This is uninitialised, and may point to anywhere in memory. When you attempt to copy the structure to it, you'll probably get a seg-fault.
Allocating a new Mystruct and returning a pointer to it would usually look more or less like this:
Mystruct *mystruct(int num, int size)
{
Mystruct *result;
result = malloc(sizeof(MyStruct));
if (!result)
return NULL;
result->num = num;
...
return result;
}
Later, when you are done with the Mystruct allocated here with malloc, it should be freed again with free().
Just declaring a local variable and returning a pointer to that local variable will not work. The local variable goes out of scope at the end of the function and the memory where it was stored is most likely reused for other purposes. The returned pointer will still point to the memory location where the local variable once was, but since that variable doesn't exist anymore, that pointer wouldn't be of much use.
One more way to do it..
int mystruct(Mystruct *mystruct, int num, int size){
if(mystruct == NULL)
return -1;
mystruct->num = num;
mystruct->size = size;
::
return 0;
}
int main(){
Mystruct my;
if(mystruct(&my, 3, 4) != 0){
fprintf(stderr, "Cannot init!\n");
exit(0);
}
::
}

Creating an Instance of a struct

I have this struct
struct FluxCapacitor{
unsigned char* c_string;
unsigned int value;
};
Now I need to create an instance of this struct. I googled this problem and found that I have to use something like this
typedef struct FluxCapacitor{
unsigned char* c_string
unsigned int value;
};
But I dont really understand the next step with malloc(). Can someone explain it to me?
You do not need malloc() to create an instance of a struct. And I would recommend that you avoid typedefing structures merely to reduce keystrokes. The extra keystrokes would only be saved in declarations and function prototypes (and maybe if you need to cast something), since you don't need the struct keyword elsewhere; the advantage is that when you see struct FluxCapacitor, you know exactly what it is. If you only see FluxCapacitor alone, you don't know if it is a typedef for a struct, or a union, or an integer type or what.
Note that the posted code was missing the semicolon at the end of the declaration. Also, it is unclear why you have unsigned char* c_string;. This may not allow assignment to a string literal. I have changed this in the code below. You can create a single struct like this:
struct FluxCapacitor
{
char *c_string;
unsigned int value;
};
...
struct FluxCapacitor fcap_1;
You can then assign values to the fields of fcap_1:
fcap_1.c_string = "McFly";
fcap_1.value = 42;
Note that you could also use designated initializers at the point of declaration:
struct FluxCapacitor fcap_2 = { .c_string = "Biff",
.value = 1985
};
If you need an array of FluxCapacitor structures, just declare one:
struct FluxCapacitor fcaps[2];
You can assign to the fields of each array member in a loop:
struct FluxCapacitor fcaps[2];
char *somestrings[] = { "McFly", "Biff" };
unsigned somevalues[] = { 42, 1985 };
for (size_t i = 0; i < 2; i++) {
fcaps[i].c_string = somestrings[i];
fcaps[i].value = somevalues[i];
}
Alternatively, you can use designated initializers here too:
struct FluxCapacitor fcaps[2] = { { .c_string = "McFly", .value = 42 },
{ .c_string = "Biff", .value = 1985}
};
Using malloc()
Since OP seems determined to use malloc(), it would be good to first recall that memory allocated with malloc() must later be deallocated with free(). Also note that malloc() can fail to allocate memory, returning a null pointer. Thus the result of a call to malloc() must be checked before attempting to dereference this pointer. The additional complexity should be avoided in favor of the above approaches unless OP has good reason to do manual allocation.
In the code below, the function create_flux_cap() takes a string and an unsigned int as arguments, and returns a pointer to a newly allocated FluxCapacitor structure with the arguments assigned to the appropriate fields. Note that since the FluxCapacitor structure is accessed through a pointer, the arrow operator is used instead of the dot operator.
Inside the function, the return value from the call to malloc() is checked before attempting assignment. If the allocation has failed, no assignment is made and a null pointer is returned to the calling function. Note that in the call to malloc(), the result is not cast, since there is no need for this in C and it needlessly clutters the code. Also observe that an identifier is used instead of an explicit type with the sizeof operator. This is less error-prone, easier to maintain if types change in the future, and is much cleaner code. That is, instead of this:
new_fcap = (struct FluxCapacitor *)malloc(sizeof (struct FluxCapacitor));
use this:
new_fcap = malloc(sizeof *new_fcap);
In main(), the return values from the calls to create_flux_cap() are checked. If an allocation has failed, the program exits with an error message.
The stdlib.h header file has been included for the function prototypes of malloc() and exit(), and also for the macro EXIT_FAILURE.
#include <stdio.h>
#include <stdlib.h>
struct FluxCapacitor
{
char* c_string;
unsigned value;
};
struct FluxCapacitor * create_flux_cap(char *, unsigned);
int main(void)
{
struct FluxCapacitor *fcap_1 = create_flux_cap("McFly", 42);
struct FluxCapacitor *fcap_2 = create_flux_cap("Biff", 1985);
/* Check for allocation errors */
if (fcap_1 == NULL || fcap_2 == NULL) {
fprintf(stderr, "Unable to create FluxCapacitor\n");
exit(EXIT_FAILURE);
}
/* Display contents of structures */
printf("%s, %u\n", fcap_1->c_string, fcap_1->value);
printf("%s, %u\n", fcap_2->c_string, fcap_2->value);
/* Free allocated memory */
free(fcap_1);
free(fcap_2);
return 0;
}
struct FluxCapacitor * create_flux_cap(char *str, unsigned val)
{
struct FluxCapacitor *new_fcap;
new_fcap = malloc(sizeof *new_fcap);
if (new_fcap != NULL) {
new_fcap->c_string = str;
new_fcap->value = val;
}
return new_fcap;
}
You need malloc for dynamic allocation of memory.In your case, both the types char and int are known to the compiler, it means the compiler can know the exact memory requirement at compile time.
For e.g. you can create a struct object like in the main function
#include<stdio.h>
#include<stdlib.h>
struct FluxCapacitor{
unsigned char* c_string;
unsigned int value;
};
int main() {
FluxCapacitor x;
x.c_string = "This is x capacitor"
x.value = 10
}
The x is of value type. You can make a copy and pass around this value. Also, observe we are using . notation to access its member variables.
But this doesn't happen at all time. We are not aware of future FluxCapacitor requirement and so above program will need more memory as while it is running and by using the malloc we can ask the compiler to provide us requested memory. This is a good place to use malloc, what malloc does is, it returns us a pointer to a piece of memory of the requested size. It is dynamic memory allocation.
Here's a simple example: let suppose if you need struct declaration of FluxCapacitor but don't know how many you will need, then use malloc
#include<stdio.h>
#include<stdlib.h>
typedef struct FluxCapacitor {
unsigned char* c_string;
int value;;
} flux;
// typedef is used to have the alias for the struct FluxCapacitor as flux
int main() {
flux *a = malloc(sizeof(flux)); // piece of memory requested
a -> c_string = "Hello World"; // Pointer notation
a -> value = 5;
free(a); // you need to handle freeing of memory
return 0;
}
.

How do I access nested structures to and access their contents to be used?

I'm trying to learn how to use nested structures and am doing a "pthread producer and consumer" like example.
I have these initialized:
int MAILBOX_SIZE = 10;
typedef struct Message {
int bytes;
void *data;
} Message;
typedef struct Mailbox {
Message *queue;
int in; //place to add next element in buffer
int out; //place to remove next element in buffer
int cnt; //number of elements in buffer
} Mailbox;
void mb_init(Mailbox *sb, int size);
Now I want to create this initialization function to be able to access the queue.
My approach for it may be wrong, but what I was thinking was this:
void mb_init(Mailbox *sb, int size){
sb->queue=(Message*)malloc(sizeof(Message));
sb->queue->bytes = size;
printf("%i\n", sb->queue->bytes);
}
int mb_put(Mailbox *sb, Message *msg){
//actions of the producer
}
int mb_get(Mailbox *sb, Message *msg){
//actions of the consumer
}
And my main (pseudo code because I have alot more in main) is this:
int main() {
struct Mailbox *myMailbox;
mb_init(myMailbox, MAILBOX_SIZE);
}
I end up getting a "segmentation fault", and I know it is coming from my "mb_init" function, because I'm not quite sure how to handle nested structures.
How can I set the size of the message from this init function using nested structures?
Any help is appreciated.. I am learning C; I'm sorry if some things aren't the "most efficient" way to be done.
Compiler warnings (-Wall) point at the problem.
test.c:27:12: warning: variable 'myMailbox' is uninitialized when used here [-Wuninitialized]
mb_init(myMailbox, MAILBOX_SIZE);
^~~~~~~~~
1 warning generated.
You're passing in myMailbox and using it without having allocated memory for it. In general, don't pass in a pointer to an initialization function, return one.
You also shouldn't initialize an empty message in the Mailbox, just init the Mailbox. Let whomever is adding the messages initialize the Message and pass it in.
Mailbox *mb_init(int size){
Mailbox *sb = malloc(sizeof(Mailbox));
sb->queue = NULL;
sb->in = 0;
sb->out = 0;
sb->cnt = 0;
return sb;
}
This brings us to our next problem: you only allocated space in your queue for one message. And it's not storing pointers to messages, it will have to copy them and they can get huge.
Instead, use an array of Message pointers.
const size_t MAILBOX_SIZE = 10;
typedef struct {
size_t bytes;
void *data;
} Message;
typedef struct {
Message **queue;
size_t in; //place to add next element in buffer
size_t out; //place to remove next element in buffer
size_t cnt; //number of elements in buffer
size_t max_size;
} Mailbox;
Mailbox *mb_init(size_t size){
Mailbox *mb = malloc(sizeof(Mailbox));
mb->queue = malloc(sizeof(Message*) * size);
mb->in = 0;
mb->out = 0;
mb->cnt = 0;
mb->max_size = size;
return mb;
}
void mb_destroy( Mailbox *mb ) {
free(mb->queue);
free(mb);
}
I've made a few other changes. The most obvious is switching to size_t to store the size of things. This avoids bumping into the integer limit.
I added a destructor, you should always write an initializer and a destructor for all your structs.
And Mailbox now stores its max size. It'll need to know that to avoid adding too many messages. Later versions of this would switch to a linked list or reallocate the queue as needed.
I've also made sure to always use the typedefs, not the underlying struct types, and went so far as to remove the names from the struct so they cannot be referenced directly. Now there's only one way to refer to the struct, which is easier to read. It also provides stronger encapsulation should there be a radical change to the type, like switching to an integer which indexes other storage (not likely, but you never know).
As i already said, your problem is passing by value instead of by reference.
There are so many ways to do this. You can try this one
in Main
Mailbox myMailbox; // memory allocated on the stack, life span till the *return*
mb_init(&myMailbox, MAILBOX_SIZE); // pass the address here
// and don't forget to free the queue memory when you are done with it
//Main ends here
/* In your code if you don't return a pointer to the memory allocated here on the heap.
You will not get those changes when the function return from the stack.
It is best practice to return a pointer to the allocated heap memory
before the function returns. */
void mb_init(Mailbox *sb, int size){
......
......
}

User defined types with dynamic size in C

I want to define a new data type consisting of an array with a size inputted by the user. For example if the user inputs 128, then my program should make a new type which is basically an array of 16 bytes. This structure's definition needs to be global since I am going to use that type thereafter in my program. It is necessary to have a dynamic size for this structure because I will have a HUGE database populated by that type of variables in the end.
The code I have right now is:
struct user_defined_integer;
.
.
.
void def_type(int num_bits)
{
extern struct user_defined_integer
{
int val[num_bits/sizeof(int)];
};
return;
}
(which is not working)
The closest thing to my question, I have found, is in here:
I need to make a global array in C with a size inputted by the user
(Which is not helpful)
Is there a way to do this, so that my structure is recognized in the whole file?
When doing:
extern struct user_defined_integer
{
int val[num_bits/sizeof(int)];
};
You should get the warning:
warning: useless storage class specifier in empty declaration
because you have an empty declaration. extern does not apply to user_defined_integer, but rather the variable that comes after it. Secondly, this won't work anyway because a struct that contains a variable length array can't have any linkage.
error: object with variably modified type must have no linkage
Even so, variable length arrays allocate storage at the point of declaration. You should instead opt for dynamic memory.
#include <stdlib.h>
typedef struct
{
int num_bits;
int* val;
} user_defined_integer;
void set_val(user_defined_integer* udi, int num_bits)
{
udi->num_bits = num_bits;
udi->val = malloc(num_bits/sizeof(int));
}
What you need is a VLA member, as asked about here. Basically, you declare a struct with a size field and one element's worth of storage as last member, and over-allocate it.
Imported from that question :
typedef struct Bitmapset {
int nwords;
uint32 words[1];
} Bitmapset;
Bitmapset *allocate(int n) {
Bitmapset *p = malloc(offsetof(Bitmapset, words) + n * sizeof *p->words);
p->nwords = n;
return p;
}
I want to define a new data type consisting of an array with a size inputted by the user. For example if the user inputs 128, then my program should make a new type which is basically an array of 16 bytes.
This is not possible in C, because C types are a compile-time thing and don't exist at all at run-time.
However, with a C99 conforming compiler, you might use flexible array member. You'll need a struct containing some members and ending with an array without any given dimension, e.g.
struct my_flex_st {
unsigned size;
int arr[]; // of size elements
};
Here is a way to allocate it:
struct my_flex_st *make_flex(unsigned siz) {
struct my_flex_st* ptr
= malloc(sizeof(struct my_flex_st) + siz * sizeof(int));
if (!ptr) { perror("malloc my_flex_st"); exit(EXIT_FAILURE); };
ptr->size = siz;
memset (ptr->arr, 0, siz*sizeof(int));
return ptr;
}
Don't forget to free it once you don't use it anymore.
Of course, you'll need to use pointers in your code. If you really want to have a global variable, declare it as e.g.
extern struct my_flex_st* my_glob_ptr;
Try this method-
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
struct user_defined_integer
{
int *val;
}user_int;
void memory_allocate(int num_bit)
{
int result;
result = (num_bit+CHAR_BIT-1)/CHAR_BIT; // since 8 bit =1 byte
user_int.val=malloc(result*sizeof(int));
if(user_int.val == NULL){
printf("Failed to allocate memory\n");
return ;
}
else
printf("Allocated %d bytes for val\n",result);
}
int main()
{
int num_bit;
printf("Enter the number of bits\n");
scanf("%d",&num_bit);
memory_allocate(num_bit);
// do your stuff here
free(user_int.val); // free the memory at the end;
return 0;
}

Resources