Struct Initialization differnece - c

Given a struct in C defined as follows:
struct Person {
const char *name;
int age;
}
What are the differences between the two declarations below? I was confused when the struct keyword would precede the initialization below:
int main() {
struct Person John = { .name = "John", .age = 10 };
Person Jane = { .name = "Jane", .age = 10 };
return 0;
}

If you define the struct in this way:
struct Person {
const char *name;
int age;
}
Then (1) compiles while (2) does not, since the type of the struct is struct Person, not Person. "struct" is required.
// (1)
struct Person John = { .name = "John", .age = 10 };
// (2)
Person Jane = { .name = "Jane", .age = 10 };
However, if you use typedef:
typedef struct person_t {
const char *name;
int age;
} Person;
Then you can use both struct person_t and Person as the latter is an alias of the former.

Related

munmap_chunk(): invalid pointer while freeing a struct in an array

So I wrote a program where I have to realloc an array of structs whenever I want to add something to it.
But when I try to free the array, I free every element individually but I get a munmap_chunk(): invalid pointer at some point.
Here is the full code :
#include <stdlib.h>
#include <string.h>
struct Date {
int day;
int month;
int year;
};
struct Person {
char *name;
char *surname;
struct Date birth;
};
struct Directory {
int size;
struct Person *array;
};
struct Date create_date() {
struct Date date = {
.day = 0,
.month = 0,
.year = 0
};
return date;
}
struct Directory create_directory() {
struct Directory directory = {
.size = 0,
.array = NULL
};
return directory;
}
struct Person *create_person() {
struct Person *person_ptr = (struct Person *) malloc(sizeof(struct Person));
person_ptr->name = NULL;
person_ptr->surname = NULL;
return person_ptr;
}
void copy_date(struct Date *dest, struct Date *src) {
dest->day = src->day;
dest->month = src->month;
dest->year = src->year;
}
void initialize_person(struct Person *person_ptr, char *name, char *surname, struct Date *birth) {
if (name != NULL && surname != NULL && birth != NULL) {
person_ptr->name = realloc((*person_ptr).name, (strlen(name) * sizeof(char)) + 1);
strcpy(person_ptr->name, name);
person_ptr->surname = realloc((*person_ptr).surname, (strlen(surname) * sizeof(char)) + 1);
strcpy(person_ptr->surname, surname);
copy_date(&person_ptr->birth, birth);
}
}
void copy_person(struct Person *dest, struct Person *src) {
dest->name = realloc((*dest).name, (strlen(src->name) * sizeof(char)) + 1);
dest->surname = realloc((*dest).surname, (strlen(src->surname) * sizeof(char)) + 1);
struct Date date = create_date();
dest->birth = date;
strcpy(dest->name, src->name);
strcpy(dest->surname, src->surname);
copy_date(&dest->birth, &src->birth);
}
int add_person(struct Directory *directory_ptr, const struct Person *new_person_ptr) {
int return_code = 0;
directory_ptr->size++;
directory_ptr->array = realloc(directory_ptr->array, (directory_ptr->size * sizeof(struct Person)));
if (directory_ptr->array) {
copy_person(&directory_ptr->array[directory_ptr->size - 1], (struct Person *) new_person_ptr);
} else {
return_code = 1;
}
return return_code;
}
int add_multiple_persons(struct Directory *directory_ptr, const struct Person **persons_ptr, int nb_persons) {
for (int i = 0; i < nb_persons; i++) {
add_person(directory_ptr, (persons_ptr[i]));
}
return 0;
}
void destroy_person(struct Person *person_ptr) {
free(person_ptr->name);
person_ptr->name = NULL;
free(person_ptr->surname);
person_ptr->surname = NULL;
free(person_ptr);
person_ptr = NULL;
}
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
for (int i = 0; i < directory_ptr->size; i++) {
destroy_person(&directory_ptr->array[i]);
}
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
int main(void) {
struct Directory directory = create_directory();
struct Person *person1 = create_person();
struct Person *person2 = create_person();
struct Person *person3 = create_person();
struct Date date = {
.day = 17,
.month = 04,
.year = 1999};
initialize_person(person1, "Marcel", "Juan", &date);
initialize_person(person2, "Albin", "Michel", &date);
initialize_person(person3, "Suzerain", "Bernard", &date);
const struct Person *array[] = {
person1,
person2,
person3
};
add_multiple_persons(&directory, array, 3);
destroy_person(person1);
destroy_person(person2);
destroy_person(person3);
destroy_directory(&directory);
return 0;
}
I've been on this error for more than a week, and it keeps bugging me.
How can I fix this ?
In the destroy_directory function, you freed the persons contained by the array. But in this array you didn't put pointers to structures but the structures themselves. Therefore you must free the space you allocated for the array and nothing else :
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
free(directory_ptr->array); //<==== Here
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
person_ptr is a part of the memory allocated at directory_ptr->array. You need to remove this line.
As a rule of gold, memory responsible is the same while allocation and while freeing. In your code, the person holder is the array inside directory_ptr, which is allocated by add_person. Despite its name, it is a directory manager, so freeing its memory should be done only on directory destroyer.

Warning from gcc: braces around scalar initializer, how to fix?

At rewriting kernel driver I got this warning:
msm-cirrus-playback.c:545:2: warning: braces around scalar initializer
Read that this warning appears when I am declaring one structure's field in {}:
struct random_struct test = {
{ .name = "StackOverflow" },
{ .name = "StackExchange" },
};
But my structure have 2-3 fields in {}:
static struct device_attribute *opalum_dev_attr = {
{
.attr->name = "temp-acc",
.show = opsl_temp_acc_show,
.store = opsl_temp_acc_store,
},
{
.attr->name = "count",
.show = opsl_count_show,
.store = opsl_count_store,
},
{
.attr->name = "ambient",
.show = opsl_ambient_show,
.store = opsl_ambient_store,
},
{
.attr->name = "f0",
.show = opsl_f0_show,
.store = opsl_f0_store,
},
{
.attr->name = "pass",
.show = opsl_pass_show,
},
{
.attr->name = "start",
.show = opsl_cali_start,
},
};
This structure:
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
How can I fix this warning? Qualcomm kernels are building with -Werror flag, so this warning is critical.
static struct device_attribute *opalum_dev_attr means declare opalum_dev_attr as static pointer to struct device_attribute
Your code is trying to initialize a static array of struct device_attribute
What you want is: static struct device_attribute opalum_dev_attr[] which means declare opalum_dev_attr as static array of struct device_attribute
It is because you initialize the pointer to the struct not the struct itself.
you need to assign the reference to the struct for example by using compound literals
struct x
{
int a,b,c;
}a = {1,2,3};
void foo()
{
struct x a = {1,2,3};
struct x *b = {1,2,3}; // wrong warning here
struct x *x = &(struct x){1,2,3}; // correct reference to the struct assigned (using compound literal
struct x *y = (struct x[]){{1,2,3}, {4,5,6}, {4,5,6}, };
struct x z[] = {{1,2,3}, {4,5,6}, {4,5,6}, };
}

initialize a struct array in c

Can I initialize a stuct in C in the following way:
struct database {
char* Name;
char* Title;
char* DOB;
int EmployeeNo;
} people[100];
people[0] = { "Jon", "Manager", "1-1-1990", 12345 };
people[1] = { "Bob", "Accountant", "1-1-1990", 54321 };
I am using gcc version 9.2.1 20191130 (Debian 9.2.1-21)
No, the correct way is:
struct database {
char* Name;
char* Title;
char* DOB;
int EmployeeNo;
} people[100]={ { "Jon", "Manager", "1-1-1990", 12345 },
{ "Bob", "Accountant", "1-1-1990", 54321 }
};
This is usable in C89, C90, C94, C99, C11, C17 — and pre-standard C if the initialization is done at file scope.
No, do it like this:
struct database {
char* Name;
char* Title;
char* DOB;
int EmployeeNo;
};
struct database ppl[5] = {
{ .Name = "Jon", .Title = "Manager", .DOB = "1-1-1990", .EmployeeNo = 12345 },
{ .Name = "Ravi", .Title = "Manager", .DOB = "1-1-1990", .EmployeeNo = 12345 },
{.....},
{.....},
{.....},
};
Initialization and definition must be done at the same time — otherwise, you're assigning, not initializing.
Can I initialize a stuct in C in the following way:
Not quite.
There are other ways to initialize as provided by other answers.
You can assign within a function with a compound literal.
people[0] =
(struct database){ "Jon", "Manager", "1-1-1990", 12345 };
people[1] =
(struct database){ "Bob", "Accountant", "1-1-1990", 54321 };

Pointers to functions casting

I have the following structs:
struct mtmFlix_t {
List usersList;
List seriesList;
};
struct User_t {
int age;
char* username;
MtmFlix mtmFlix;
};
These are the typedefs in list.h :
typedef void* ListElement;
typedef ListElement(*CopyListElement)(ListElement);
typedef void(*FreeListElement)(ListElement);
These are the typedefs in user.h and MtmFlix.h :
typedef struct User_t *User;
typedef struct mtmFlix_t* MtmFlix;
I would like to use the following function in mtmflixCreate, but I can't seem to figure out how to cast the UserCreate and UserFree to (*void) ?
List listCreate(CopyListElement copyElement, FreeListElement freeElement);
MtmFlix mtmFlixCreate()
{
MtmFlix newMtmFlix = malloc(sizeof(*newMtmFlix));
if (newMtmFlix == NULL) {
return NULL;
}
newMtmFlix->seriesList=listCreate(?????);
newMtmFlix->usersList=listCreate(?????);
}
The following functions appear in user.h :
User UserCreate(MtmFlix mtmFlix, const char* username,int age);
Void UserFree(User user);
You don't. You have to create functions that have the needed types. Something like this:
ListElement CopyUserListElement(ListElement elem) {
// (ListElement) is not necessary here, but included for completeness
return (ListElement)CopyUser((User_t*)elem);
}
void FreeUserListElement(ListElement elem) {
UserFree((User_t*)elem);
}

How can I pass a generic struct to a function in C?

I'm beginner in C programming and I have a doubt about to pass a generic struct to a function in C.
Here is what I have:
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
And I want to do something like this:
void changeName(struct *s, newName[20]) {
strcpy(s->name, newName);
}
If someone has already asked that, please disconsider this and sends me the issue link.
Someone can help me?
Thanks.
Using a union
One approach would be to add a structure containing a union, itself containing pointers to product and category structures, as well as an enum to identify the type of data in the struct. This union, or a pointer to it, could be passed to a change_name() function.
Here is an example that would work in C11. It uses an unnamed union member, so this is not valid C99 code:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
product *prod;
category *cat;
};
} generic;
void change_name(generic *gen, const char *new_name);
int main(void)
{
product prod_a = { .name = "widget", .price = 1.99 };
category cat_a = { .name = "general", .type = 1 };
generic gen_prod_a = { .type = PRODUCT, .prod = &prod_a };
generic gen_cat_a = { .type = CATEGORY, .cat = &cat_a };
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
change_name(&gen_prod_a, "gadget");
change_name(&gen_cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
return 0;
}
void change_name(generic *gen, const char *new_name)
{
switch (gen->type) {
case PRODUCT:
strcpy(gen->prod->name, new_name);
break;
case CATEGORY:
strcpy(gen->cat->name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
This could be made to work in C99 by naming the union:
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
product *prod;
category *cat;
} data; // named for C99
} generic;
/* ... */
generic gen_prod_a = { .type = PRODUCT, .data.prod = &prod_a };
generic gen_cat_a = { .type = CATEGORY, .data.cat = &cat_a };
/* ... */
void change_name(generic *gen, const char *new_name)
{
switch (gen->type) {
case PRODUCT:
strcpy(gen->data.prod->name, new_name);
break;
case CATEGORY:
strcpy(gen->data.cat->name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
Alternatively, one struct type could hold an enum identifier and a union containing the product and category structures. This approach may seem a bit more streamlined:
#include <stdio.h>
#include <string.h>
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
struct {
char name[20];
float price;
} prod;
struct {
char name[20];
int type;
} cat;
} data;
} record;
void change_name(record *rec, const char *new_name);
int main(void)
{
record prod_a = { .type = PRODUCT };
change_name(&prod_a, "widget");
prod_a.data.prod.price = 1.99;
record cat_a = { .type = CATEGORY };
change_name(&cat_a, "general");
cat_a.data.cat.type = 1;
printf("prod_a.name = %s\n", prod_a.data.prod.name);
printf("cat_a.name = %s\n", cat_a.data.cat.name);
change_name(&prod_a, "gadget");
change_name(&cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.data.prod.name);
printf("cat_a.name = %s\n", cat_a.data.cat.name);
return 0;
}
void change_name(record *rec, const char *new_name)
{
switch (rec->type) {
case PRODUCT:
strcpy(rec->data.prod.name, new_name);
break;
case CATEGORY:
strcpy(rec->data.cat.name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
Using a type-generic macro
Both of the above approaches are a little bit awkward. Another solution, available for C11 only, is to use the _Generic keyword in a type-generic macro. Here, functions are written for each expected data type, and a macro selects which function definition is to be used based on type. A virtue of this approach is that as new types are added, only new functions and updates to the type-generic macro are needed to handle them.
#include <stdio.h>
#include <string.h>
#define change_name(S, N) _Generic ((S), \
prod_ptr: change_name_prod, \
cat_ptr: change_name_cat \
)((S), (N))
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
typedef product *prod_ptr;
typedef category *cat_ptr;
void change_name_prod(product *prod, const char *new_name);
void change_name_cat(category *cat, const char *new_name);
int main(void)
{
product prod_a = { .name = "widget", .price = 1.99 };
category cat_a = { .name = "general", .type = 1 };
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
change_name(&prod_a, "gadget");
change_name(&cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
return 0;
}
void change_name_prod(product *prod, const char *new_name)
{
strcpy(prod->name, new_name);
}
void change_name_cat(category *cat, const char *new_name)
{
strcpy(cat->name, new_name);
}
All of the above programs have the same output:
prod_a.name = widget
cat_a.name = general
prod_a.name = gadget
cat_a.name = specific
You have already typedef-ed the structures. You can use these other names.
For example, if the name is product, first create a variable and call the function
product var={"name", 1.2};
changeName(&var, "AnotherName");
Then pass this variable to a function
void changeName(product *s, char newName[])
{
strcpy(s->name, newName);
}
Generic programming, which implies type-safety just doesn't really exist in C. But there are ways around that.
What I understand from your question, is 'Can I define a function that can be applied to common elements of different structures?
Let's expand you example a bit, to have items which share a common trait.
struct info
{
char name[20];
int id;
};
struct product
{
Info info;
int price;
};
struct category
{
Info info;
int type;
};
You can now define a function that would work safely on the traits shared by both product and category.
void changeName(info* p, const char* name)
{
strcpy_s(info->name, sizeof(info->name), name);
}
int main()
{
category cat;
product prod;
memset(&cat, 0, sizeof(cat));
memset(&prod, 0, sizeof(prod));
changeName(&cat.info, "Category 1");
changeName(&prod.info, "blue product");
return 0;
}

Resources