initialize a struct array in c - 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 };

Related

Struct Initialization differnece

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.

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}, };
}

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;
}

Initialize sized, static string lists in C

I want to create string lists with a discoverable size and am not sure if I have the right method/syntax. Here is my attempt:
typedef struct {
unsigned int size;
char** list;
} STRLIST;
static STRLIST listMediaType = {
.size = 7,
.list = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
},
};
Is this the right approach? Note that I do not want to hardcode the size into the structure because I want to use the same type to define many different lists. For example, imagine the following function:
void printList( STRLIST* pList ){
for( int x = 0; x < pList->size; x++ ) printf( "%s\n", pList->list );
}
It can be done with C99 compound-literals and a slight change:
http://coliru.stacked-crooked.com/a/4497d2645ad21b74
typedef struct STRLIST{
unsigned int size;
char** list;
} STRLIST;
static STRLIST listMediaType = {
.size = 7,
.list = (char*[]){
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
},
};
Alternative for C90 (thus without compound-literals and designated initializers): http://coliru.stacked-crooked.com/a/5cc95d25afc18c91
static char* list[] = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
};
static STRLIST listMediaType = {
sizeof list / sizeof *list,
// Used sizeof to avoid manually typing the lists length
list,
};
As an aside, an array with a sentinel-NULL is far simpler than a counted array.
Does not even need a new type.
static char* list[] = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal",
0
};
void printList(char** pList){
while(*pList) printf( "%s\n", *pList++);
}
You may check this code:
#include <stdio.h>
typedef struct {
unsigned int size;
char* list[];
} STRLIST;
static STRLIST listMediaType = {
7,
{
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
}
};
int main() {
printf("struct size: %d\n", listMediaType.size);
int i;
for (i = 0; i < listMediaType.size; i++)
printf("struct elem[%d] = \"%s\"\n",
i,
listMediaType.list[i]);
return 0;
}
I think there are 2 problems in your approach:
Is TYPEDEF syntactic correct in C? I think you should write it in lowercase.
If you want to initialize a struct, just use the brace and without .attributes
Hope this one will help.
Thanks

sizeof reporting wrong value

I'm trying to get a "column" elements count from my own structure using sizeof(_test.header.columns)/sizeof(struct _column). Unfortunately I'm always getting it as 0, because the sizeof(_test.header.columns) is always 4. Here is the code:
struct _column{
char title[40];
int length;
};
struct test_struct{
struct{
struct _column* columns;
}header;
struct{
struct _column* columns;
}details;
struct{
struct _column* columns;
}end;
};
struct test_struct _test = {
.header = {
.columns = {
{
"a",
1,
},
{
"ab",
2,
},
},
},
.details = {
.columns = {
{
"b",
2,
},
{
"bc",
3,
},
},
},
.end = {
.columns = {
{
"c",
3,
},
{
"cd",
4,
},
},
},
};
void testme(){
char buff[20];
itoa(sizeof(_test.header.columns)/sizeof(struct _column),buff,sizeof(buff));
MessageBoxA(NULL,buff,NULL,NULL);
}
please help me to resolve the problem, thanks. Any help would be appreciated.
You might try to do an approach like the following in which you do the same kind of initialization however you include as part of it the column count itself.
struct _column{
char title[40];
int length;
};
struct test_struct{
struct{
struct _column* columns;
int nColumns;
}header;
struct{
struct _column* columns;
int nColumns;
}details;
struct{
struct _column* columns;
int nColumns;
}end;
};
struct _column headerColumns [] = {
{
"a",
1
},
{
"ab",
2
}
};
struct _column detailColumns[] = {
{
"b",
2
},
{
"bc",
3
},
};
struct _column endColumns [] = {
{
"c",
3
},
{
"cd",
4
}
};
struct test_struct _test = {
{ headerColumns, sizeof(headerColumns)/sizeof(headerColumns[0])},
{ detailColumns, sizeof(detailColumns)/sizeof(detailColumns[0])},
{ endColumns, sizeof(endColumns)/sizeof(endColumns[0])}
};
The reason it fails is that you're checking the sizeof on a pointer, which returns the size of the pointer, NOT of the actual Array the memory address points to.
If you know the maximum length of the array, you can declare it as such:
_column[ integerSize ]
But then if you knew the size, you wouldn't be querying it using sizeof, I'd think ;-) You could extend the struct by adding another property of an int type that describes the size of the columns array ?

Resources