I'm working on a problem involving the code below, and I'm a bit lost.
What is "class[]" doing, and how does that change how I would print the members? I've never seen an initialization like this before.
int main(){
struct Student {
char Initials2[2];
int id;
struct Student *teammate;
};
typedef struct Student SType;
#define XYpt &class[0]
#define ABpt &class[1]
#define RSpt &class[2]
#define CDpt &class[3]
#define JVpt &class[4]
#define RYpt &class[5]
SType class[6] = {
{{'X','Y'},123, RSpt},
{{'A','B'},23, RYpt},
{{'R','S'},11, XYpt},
{{'C','D'},44, JVpt},
{{'J','V'},42, CDpt},
{{'R','Y'},457, ABpt}
};
return 0;
}
What the code does:
struct Student is a bit special, as it is containing a pointer to an object of the same type struct Student *teammate. This is possible by using a pointer to an object with the "struct tag" Student, which acts as a form of forward declaration.
typedef struct Student SType; just hides away the struct keyword, which is a coding style matter. It would have been cleaner to write the whole thing like this:
typedef struct Student {
char Initials2[2];
int id;
struct Student *teammate;
} SType;
SType class[6] = { {{'X','Y'},123, RSpt}, .... is just an array of 6 structs, each initialized. The bunch of macros expand to variable addresses of the same array named "class". This is poor style - the programmer used this as a dirty way to "name" each item in the array. The postfix "pt" seems to mean pointer.
How the code could have been written:
Rather than using ugly macros, it is possible to associate each item of an array with an identifier, by using a union. For example:
typedef union
{
struct foo
{
int foo;
int bar;
} foo;
int array [2];
} foobar;
Here, an object foobar fb; can be accessed as fb.foo.foo or fb.array[0] and it means the same item 0 of the array. With modern standard C, we can drop the inner struct name (anonymous struct) and just access the objects as fb.foo.
Also, this can be combined with designated initializers to initialized certain named members of the struct by their name: foobar fb { .foo = 1, .bar = 2 };.
Rewriting your example by using unions, anonymous struct and designated initializers, we get this instead:
typedef struct student {
char initials [2];
int id;
struct student *teammate;
} s_type;
typedef union
{
struct
{
s_type XY;
s_type AB;
s_type RS;
s_type CD;
s_type JV;
s_type RY;
};
s_type array [6];
} class_t;
class_t class =
{
.XY = { .initials={'X','Y'}, .id=123, .teammate = &class.RS},
.AB = { .initials={'A','B'}, .id= 23, .teammate = &class.RY},
.RS = { .initials={'R','S'}, .id= 11, .teammate = &class.XY},
.CD = { .initials={'C','D'}, .id= 44, .teammate = &class.JV},
.JV = { .initials={'J','V'}, .id= 42, .teammate = &class.CD},
.RY = { .initials={'R','Y'}, .id=457, .teammate = &class.AB},
};
This is much easier to read and understand. Plus we can still use it as an array with class.array[i] if we want.
Related
I read a tutorial in which there is this struct:
struct
{
char Name[25];
int Age;
float SkillRating;
} Employee;
defines a new aggregate, called Employee, containing fields called Name (of type character), Age (of type integer), and SkillRating (of type float).
In contrast, the C statement:
struct EmployeeType
{
char Name[25];
int Age;
float SkillRating;
};
does not define a new aggregate variable, but defines a new aggregate type,
EmployeeType.
This new data type could then be used to declare variables in the
same way as a primitive data type. That is, in the same way that C allows the
variable x to be declared as an integer using the statement
I am confused here. Does the distinction exist if place 'Emplyee` on different position?
I guess they are identical.
In the first case, the struct is unnamed and Employee is a variable of that unnamed struct. You can directly modify it like this:
int main()
{
Employee.Age = 100;
return 0;
}
In the second case, EmployeeType is just a type, but you didn't make any instance of it yet. You can make any amount of instances:
int main()
{
struct EmployeeType a; // employee on the stack
a.Age = 100;
struct EmployeeType *b = malloc(sizeof(struct EmployeeType)); // employee on the heap
if (b) { // set the age of b if the allocation succeeded
b->Age = 100;
}
free(b); // malloc-allocated memory must be freed afterwards
return 0;
}
You can even do both at once:
struct EmployeeType
{
char Name[25];
int
Age;
float SkillRating;
} Employee;
Here, Employee is one instance of it, but you can make additional instances:
int main()
{
Employee.Age = 100;
struct EmployeeType a; // employee on the stack
a.Age = 100;
return 0;
}
struct A_s { int memb; }; // declares a struct A_s
struct A_s a; // declares a variable a of type struct A_s
now you can combine struct declaration with variable declaration:
// declares struct A_s and in the same line declares variable a
struct A_s { int memb; } a;
Now you can create an anonymous struct by omitting the structure tag name:
// declares anonymous struct and in the same line declares variable a
struct { int memb; } a;
Now structure declaration can be really put anywhere:
int func(int a, struct A_s { int memb; } b);
struct A_s { int memb; } func(int a);
struct B_s {
int memb1;
struct A_s {
int memb2;
} a;
};
I think the description of the C code of the field "name" in your post is invalid. The field name inside "aggregate" (read as: structure) has the type "array of 25 characters", not character type.
struct keyword in C can be used to declare aggregate datatypes, aggregate data objects or both.
In your first declaration (and definition), a tag name is missing, so an anonymous object 'Employee' is created. 'Employee' remains the only object of this struct. You cannot create more objects from this struct anywhere else in the code.
In your second declaration, you have created a struct type which can be instantiated many times (i.e., multiple instances of this struct can exist) as shown below -
struct EmployeeType employee_1;
struct EmployeeType employee_2;
Both these syntax are useful depending on the use case.
i'm looking for creating a function in C language that allows me to receive different structures type as parameters.
For example, if I create 3 different structures
struct a{
struct datatype0{
char test1[10];
}datatype;
struct a *next;
};
struct b{
struct datatype1{
int test1;
char test2[20];
int test3;
}datatype;
struct b *next;
};
struct c{
struct datatype2{
char test1;
char test2;
float test3;
int test4;
int test5;
}datatype;
struct c *next;
};
I wanna create a function that can receives one of theese three different struct as parameter, so I can call only it for initialize first, or second or third kind of structure:
void function("---")//<-- inside the brackets i need to insert a parameter that can be struct a, or struct b or struct c.
{
//here for example I can insert the initialize function that have to work with any struct.
}
I tryed to use a union, but I saw that I have to recreate the initializing function for each kind of struct...I tryed to use void pointers, but i need to cast theese inside the function and I need to create initializing function for each kind of struct too...
Any ideas??
The long and short of it is: avoid to do this whenever possible, but know that you Can pass different structs to a single function if you really have to.
Probably the easiest way is to create a wrapper struct, that contains 2 members: a union, and a flag to let you know which struct is passed.
typedef enum {
A,
B,
C
} struct_type;
struct _wrapper {
union {
struct a A;
struct b B;
struct c C;
};
struct_type flag;
};
void my_function(struct _wrapper *data)
{
switch (data->flag)
{
case A:
struct a val = data.A;
//do stuff with A
break;
case B:
struct b val = data.B;
break;
case C:
struct c val = data.C;
//...
break;
}
}
Another option, although it's considered bad practice, and is something you'll end up regretting is to rely on the fact that the offset of the first member of any struct is guaranteed to be 0. You can cast a pointer to any struct to a pointer to its first member. If the first member of all structs is compatible, you can rely on that (at your own risk).
One way of exploiting this is to set a function pointer as first member, or an enum field that you can use as a flag to identify the struct:
struct a {
void (*common_member)();//
/** other members **/
};
struct b {
void (*common_member)();//needn't be the same name though
/** other members **/
};
Then:
void my_func(void *data)
{//void pointer
((void (*)(void *))data)(data);//cast void *data to function pointer, and pass itself as an argument
}
This can work, if the structs are properly initialized, and the members point to the correct functions, but that's too many if's to rely on really.
Using the enum as first member is slightly less risky, but still not to be recommended. It's a sort of a combination of the function pointer and union approach
void my_func(void *data)
{
//cast void * to struct_type *, dereference AFTER the cast
//because you can't dereference a void *
switch(*((struct_type *) data))
{
case A: /* stuff */ break;
case B: /* struct b */ break;
}
}
All in all, use the first approach. Do not use the function pointer members, and acknowledge the third approach for what it is: true, you don't need a wrapper struct, but it's not that much safer than the original approach (function pointers), and no less verbose than the first approach (with union).
Bottom line: structs and unions are the way to go
In part it works. But for example, if I wanna create a function like:
typedef union elemento{
struct a A;
struct b B;
struct c C;
}elemento;
void inserimentoOrdinato(elemento dausare){
struct b prova;
prova.datatype.test1 = 3;
strcpy(prova.datatype.test2,"TESTA");
prova.datatype.test3 = 200;
prova.next = (struct a*)malloc(sizeof(struct a));
dausare.B = prova;
}
I need to use "dausare.B" or "dausare.C" for the different kinds of structures. It doesn't know itseflt which part of union has to use. Am I rigth? Thank you!
The answer is generic programming and function pointer:
**void * can be a pointer to any struct
Declaration part:
typedef void *Initializer(void* obj);//since every struct has its own fields to initialize
void function(void * obj, Initializer init)
{
init(obj);
}
Usage:
void InitA(void* a_void)
{
struct a* a = (struct a*) a_void;
//init a feilds
a->next = NULL;
}
void InitB(void* b_void)
{
struct b* b = (struct b*) b_void;
//init b feilds
b->next = NULL;
}
void InitC(void* c_void)
{
struct c* c = (struct c*) c_void;
//init a feilds
c->next = NULL;
}
int main()
{
struct a a;
struct b b;
struct c c;
Init(&a,InitA);
Init(&b,InitB);
Init(&c, initC);
return 0;
}
***Keep in mind that you dont have to build a different function for each struct if they have the same fields to initialize.
Why does this work:
struct person {
char name[50];
short mental_age;
} p1 = {"Donald", 4};
But not this:
typedef struct {
char name[50];
short mental_age;
} PERSON p1 = {"Donald", 4};
Is there a way that I can make a typedef struct and initialize Donald when I define this struct?
typedefs are aliases for other types. What you're doing is creating a convenience typedef. Since the purpose of a typedef is to create type aliases, you can't define a variable using it.
You have to do this:
typedef struct {
// data
} mytype;
mytype mydata = {"Donald", 4};
The best way, that I know of, is to separate the strict definition from the typedef statement from the struct declaration, similar to:
struct sPerson
{
char name[50];
short mental_age;
};
typedef struct sPerson PERSON;
PERSON p1 = {"Donald", 4};
I have the following structs:
typedef struct cxt_simple_socket_address_s
{
int is_ipv6;
cs_inaddr_t ip;
unsigned short ip_port;
} cxt_simple_socket_address_t;
typedef struct cs_inaddr
{
union {
struct in6_addr in6;
struct
{
uint8_t pad[12];
uint32_t in;
};
long long as_longs[2];
};
} cs_inaddr_t;
I would like to initialize a struct of type cxt_simple_socket_address_t upon declaration:
cxt_simple_socket_address_t any = {.in = INADDR_ANY};
This line doesn't compile. I have tried countless other variations, but I believe my problem is than .in is found within an anonymous struct inside an anonymous union.
HELP?
Firstly order of declaration is wrong.
struct cs_inaddr should be declared first, followed by struct cxt_simple_socket_address_s.
Since its is nested Structure (compiler will look for definition of cs_inaddr first).
typedef struct cs_inaddr
{
union {
struct in6_addr in6;
struct
{
unsigned char pad[12];
unsigned int in;
};
long long as_longs[2];
};
} cs_inaddr_t;
typedef struct cxt_simple_socket_address_s
{
int is_ipv6;
cs_inaddr_t ip;
unsigned short ip_port;
} cxt_simple_socket_address_t;
Initialization of variable should be as:
cxt_simple_socket_address_t any = {.ip = {.in = INADDR_ANY}};
Tested it using the below:
cxt_simple_socket_address_t any = {.ip = {.in = 100}};
printf("%d\n", any.ip.in);
Output: 100
Note:
The nested (inner) structure can be anonymous, since the outer structure has a tag name.
Hence can be accessed.
cxt_simple_socket_address_s doesn't contain any field naming in. Are you mean
cxt_simple_socket_address_t any = {ip.in = INADDR_ANY};
?
First of all you need to move the whole declaration of struct cs_inaddr before cxt_simple_socket_address_t in order to make it visible.
Then initialize using:
cxt_simple_socket_address_t any = {.ip.in = INADDR_ANY};
Also note that anonymous unions are introduced in C11 or as a gcc extension.
How do I assign to a typedef struct an array of another struct with a similar structure.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int age;
int height;
} Person[3];
struct internalStruct {
int age;
int height;
};
int main(void) {
//Possible
Person bob = {{7,5},{4,2},{4,3}};
//Is it possible to assign array to struct?
struct internalStruct intr[3] = {{4,32},{2,4},{2,4}};
Person job = intr; // Does not work :(.
printf("%d", jon[0].height);
return 0;
}
You cannot assign to an array in C. You can initialize an array when you declare it, but an array expression cannot appear on the left side of an assignment operator.
If you want to copy the value of an array object into another array object, you can use an explicit loop to assign each element (assuming the element type is assignable), or you can use memcpy(). (Note that a call to memcpy() needs to specify the number of bytes to copy; use sizeof for this.)
And your typedef Person:
typedef struct {
int age;
int height;
} Person[3];
is ill-advised. A Person object (variable) isn't a person; it's an array of 3 persons (people?).
My advice: Drop the typedef and just use a struct tag (as you already do for struct internalStruct) and don't try to create a special name for the array type:
struct Person {
int age;
int height;
};
...
struct Person bob[] = {{7,5},{4,2},{4,3}};
(This is still confusing, since bob is three people.)
And struct Person (as I've defined it here) and struct internalStruct are two distinct types. If you're trying to assign between these two types, it probably indicates a design flaw in your code; objects you're assigning to each other should be of the same type.
Recommended reading: the comp.lang.c FAQ, especially section 6 (arrays and pointers).
I would not suggest this tough, since you might run into memory leaks when the two structs are different:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int age;
int height;
} Person[3];
struct internalStruct {
int age;
int height;
};
int main(void) {
//Possible
Person bob = {{7,5},{4,2},{4,3}};
//Is it possible to assign array to struct?
struct internalStruct intr[3] = {{4,32},{2,4},{2,4}};
Person* jon= (Person *)intr; // Does not work :(.
printf("%d", jon[0]->height);
return 0;
}
Your Person type is an array of three structures, each of which is similar to your struct internalStruct. So, you can't just assign a struct internalStruct to a Person, though you can (with some help) assign it to one of the elements of a Person.
Also, copying arrays in C requires copying element by element, or copying the block of memory with a function like memcpy().
So the simplest way to do this would be to define struct internalStruct before Person, and define Person in terms of struct internalStruct:
struct internalStruct {
int age;
int height;
};
typedef struct internalStruct Person[3];
Doing it this way makes it possible to assign a struct internalStruct to an element of Person without type mismatches. For example:
struct internalStruct s1 = {4,32},
s2 = {2,4},
s3 = {2,4};
Person jon;
jon[0] = s1;
jon[1] = s2;
jon[2] = s3;
If you have an array of three struct internalStructs, you could copy it with a loop:
struct internalStruct st[3] = { {4,32}, {2,4}, {2,4} };
Person jon;
for (int i = 0; i < 3; i++)
jon[i] = st[i];
If you don't want to define Person in terms of struct internalStruct, then you have to make some assumptions, like that the layout of the two structures will be identical. If so, you could copy with memcpy():
struct internalStruct intr[3] = { {4,32}, {2,4}, {2,4} };
Person jon;
memcpy(jon, intr, sizeof(Person));