Custom type
structural morphology
A structure is a collection of values called member variables. Each member of the structure can be a different type of variable
Declare a struct type
//Declaring a student type is to create a student variable (object) through the student type //To describe a student, you have to have attributes or something. Name, phone number, gender, age struct Stu { char name[20];//name char tele[12];//Telephone char sex[10];//Gender int age;//Age }; struct Stu s3;//Create global structure variable int main() { struct Stu s1; struct Stu s2;//Create structure variable return 0; }
Special declaration
When declaring a structure, you can declare it incompletely.
No structure label
Anonymous structure type
To be clear, anonymous structures are types that do not occupy space, just like int. they will not open up space if they do not create a variable. Therefore, if the type does not occupy space, it will not be destroyed or not destroyed. Only when there is space, it will be destroyed or not destroyed. The type is like a drawing, and the variable is the real house to be built
struct { char name[20];//name char tele[12];//Telephone char sex[10];//Gender int age;//Age }stu;//Directly connect the structure variable. When anonymous, create the variable later. Otherwise, you can't use this structure name later, because how to create a variable without a structure name
Anonymous structure pointer type
struct { char name[20];//name char tele[12];//Telephone char sex[10];//Gender int age;//Age }* pstu;//At this point, pstu becomes an anonymous structure pointer
Structure self reference
Can a structure contain a member whose type is the structure itself?
So the node comes out
One represents data and one represents address
struct Node { int data; //Data domain struct Node* next; //Pointer field };
This means that the structure finds another object of the same type by referencing a variable in its own type
be careful
Therefore, you cannot omit your own structure label for structure self reference. The following is the solution
typedef struct Node { int data; //Data domain struct Node* next; //Pointer field }Node;
Definition and initialization of structure variables
struct Stu { char name[20];//name char tele[12];//Telephone char sex[10];//Gender int age;//Age }; struct Stu s3;//Create global structure variable int main() { struct Stu s1 = {"zhuzhongyuan","13151732661","nan",22};//(definition) create the structure variable s1 and initialize it printf("%s %s %s %d",s1.name,s1.tele,s1.sex,s1.age); return 0; }
Structure memory alignment
Now let's delve into a problem: calculating the size of a structure.
This is also a particularly popular test point: structure memory alignment
#include<stdio.h> //memory alignment //Structure memory alignment struct S2 { int a; char b; char c; }; struct S1 { char b; int a; char c; }; int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
Rules for structure memory alignment
- The first member of the structure is always placed at the beginning of the structure with an offset of 0
- The structure member starts from the second member and is always placed at an integer multiple of the alignment number
- What is the alignment number? It is the compiler's default alignment number and the smaller value of the variable's own size. Note that linux does not have a default alignment number
The default alignment number under vs is 8 - The total size of the structure must be an integral multiple of the maximum number of alignments of each member
- If a structure is nested, the nested structure is aligned to an integer multiple of its maximum alignment number, and the overall size of the structure is an integer multiple of all the maximum alignment numbers (including the alignment number of nested structures)
Several exercises
Why is there memory alignment
1. Platform reason (migration reason)
Not all hardware platforms can access any data at any address. Some platforms can only access certain types of data at certain addresses, otherwise hardware exceptions will be thrown
2. Performance reasons
Data structures (especially stacks) should be aligned on natural boundaries as much as possible, because in order to access misaligned memory, the processor needs to make two memory accesses, while aligned access only needs one access
on the whole
Structure memory alignment is the practice of exchanging space for time. In image, it is a waste of memory for convenience
solve
When designing the structure, we should not only meet the alignment, but also save space. How to do this:
Let the members with small space gather together as much as possible.
Modify the default number of alignments
vs the default alignment number is 8
We can modify the default alignment number through #pragma pack()
The default setting is the power of 2
Implementation of offsetof macro
Calculates the offset of a variable in the structure from the first address
offsetof original format
Structural transmission parameters
pass by value
Address transfer
How to choose
1. When transferring parameters to a function, the parameters need to be stacked, which will have system overhead in time and space.
2. If the structure is too large when passing a structure object, the system overhead of parameter stack pressing is relatively large, which will lead to performance degradation.
Conclusion: when the structure passes parameters, the address of the structure should be passed.
Bit segment
What is a bit segment
The declaration of a bit segment is similar to that of a struct, with two differences
1. The member of the bit field must be int, unsigned int or signed int
2. The member of the bit field is followed by a colon and a number
Memory allocation for bit segments
- The members of the bit segment can be int, unsigned int, signed int, or char (belonging to the shaping family)
- The space of bit segments is opened up in the form of 4 bytes (int) or 1 byte (char) as needed
- Bit segment involves many uncertain factors. Bit segment is not cross platform. Pay attention to portable programs and avoid using bit segment
Cross platform problem of bit segment
- It is uncertain whether the int bit field is treated as a signed number or an unsigned number.
- The number of the largest bits in the bit segment cannot be determined. (16 bit machines have a maximum of 16 and 32-bit machines have a maximum of 32, which is written as 27. Problems will occur on 16 bit machines.
- Whether members in the bit segment are allocated from left to right or from right to left in memory has not been defined.
- When a structure contains two bit segments, and the member of the second bit segment is too large to accommodate the remaining bits of the first bit segment, it is also uncertain whether to discard the remaining bits or use them.
Summary:
Compared with the structure, the bit segment can achieve the same effect and save space, but there are cross platform problems.
Application of bit segment
enumeration
If we do not initialize enumeration constants, they are incremented by one by default
There are four kinds of constants
1. Literal constant
2.const modified constant
3. # identifier constant defined by number
4. Enumeration constants
Here we will talk about enumeration constants
Enumeration constants cannot be changed. They can only be initialized
How does enumeration work
Advantages of enumeration
We can use #define to define constants. Why do we have to use enumeration? Advantages of enumeration:
- Increase the readability and maintainability of the code
- Compared with #define defined identifiers, enumeration has type checking, which is more rigorous.
- Prevents naming contamination (encapsulation)
- Easy to debug
Define is not allowed, because define is completely replaced. If you directly replace GREEN with 1 in the code, there will be no concept of GREEN in the code. It is completely replaced
- Easy to use, you can define multiple constants at a time
Clean Calculator Beta
#include<stdio.h> enum Option { exit, add, sub, mul, div }; void menu() { printf("*********************\n"); printf("****1.add 2.sub****\n"); printf("****3.mul 4.div****\n"); printf("**** 0.exit ****\n"); printf("*********************\n"); } int main() { int input = 0; int a = 0; int b = 0; int c = 0; do { menu(); printf("Please select:>"); scanf("%d",&input); printf("Please enter two operands:>"); scanf("%d%d", &a, &b); switch (input) { case add: c = a + b; printf("%d\n", c); break; case sub: c = a - b; printf("%d\n", c); break; case mul: c = a * b; printf("%d\n", c); break; case div: if (b == 0) { printf("Molecule cannot be 0\n"); break; } else { c = a / b; printf("%d\n", c); break; } default: break; } } while (input); return 0; }
Consortium
Definition of union type
Union is also a special user-defined type. The variables defined by this type also contain a series of members, which are characterized by the fact that these members share the same space (so
Consortium (also known as community).
Declaration of union type
Characteristics of joint
The members of the union share the same memory space. The size of such a union variable is at least the size of the largest member (because the union must be able to save the largest member at least)
Determine the size of the current machine
I learned a method before
#include<stdio.h> int main() { int a = 1; //0x 00 00 00 01 //Low ----------- > High //01 00 00 small end storage //00 01 big end storage //Find a way to get the first byte of A char* pc = (char*)&a; if (*pc == 1) { printf("Small end storage"); } else { printf("Big end storage"); } return 0; }
Now I've learned that the commune takes advantage of his special situation
#include<stdio.h> union Un { char c; int i; }; int main() { union Un u = { 0 }; u.i = 1; if (u.c == 1) { printf("Small end storage"); } else { printf("Big end storage"); } return 0; }
Calculation of joint size
The size of the union is at least the size of the largest member.
When the maximum member size is not an integer multiple of the maximum alignment number, it should be aligned to an integer multiple of the maximum alignment number.