catalogue
1.1 basic knowledge of structure
1.4 self reference of structure
1.5 definition and initialization of structure variables
1.6 structure memory alignment
1.7 modify the default alignment number
1.8 structural transmission parameters
2.2 memory allocation of bit segment
2.3 cross platform problem of bit segment
2.4 application of bit segment
3.1 definition of enumeration type
Key points of this chapter
- Declaration of structure type
- Self reference of structure
- Definition and initialization of structure variables
- Structure memory alignment
- Structural transmission parameters
- Struct implementation bit segment (filling & portability of bit segment)
- Definition of enumeration type
- Advantages of enumeration
- Use of enumerations
- Definition of union type
- Characteristics of joint
- Calculation of joint size
1. Structure
1.1 basic knowledge of structure
1.2 declaration of structure
struct tag
{
member-list;
}variable-list;
1.3 special declaration
For example:
1.4 self reference of structure
- A structure cannot nest itself
Correct self reference method:
be careful
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> typedef struct { int data; Node* next; }Node; int main() { Node n; return 0; }
- There is a problem with the above writing, and the compiler will still report an error,
Correct writing
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> typedef struct Node { int data; struct Node* next; }Node; int main() { Node n; return 0; }
1.5 definition and initialization of structure variables
With the structure type, how to define variables is actually very simple.
By the way, access to structures:
- For direct access Operator
- Pointer reuse for indirect access - > operator
1.6 structure memory alignment
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S1 { char c1; int i; char c2; }; int main() { printf("%d\n", sizeof(struct S1)); return 0; }
Code two
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S2 { char c1; char c2; int i; }; int main() { printf("%d\n", sizeof(struct S2)); return 0; }
Code three
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S3 { double d; char c; int i; }; int main() { printf("%d\n", sizeof(struct S3)); return 0; }
Code four
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S3 { double d; char c; int i; }; struct S4 { char c1; struct S3 s3; double d; }; int main() { printf("%d\n", sizeof(struct S4)); return 0; }
- Memory alignment exists, and all bytes of i can be obtained at one time
- If there is no memory alignment and i is taken, you need to access it twice
When designing the structure, we should not only meet the alignment, but also save space. How to do this:
Let the members who occupy less space gather together as much as possible.
for example
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S1 { char c1; int i; char c2; }; struct S2 { char c1; char c2; int i; }; int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
S1 is as like as two peas of S2 type, but the size of S1 and S2 occupies some difference.
1.7 modify the default alignment number
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #pragma pack(2) struct S { char c1; int i;// char c2;// }; int main() { printf("%d\n", sizeof(struct S)); return 0; }
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stddef.h> #pragma pack(2) struct S { char c1; int i; char c2; }; int main() { printf("%d\n", offsetof(struct S, c1)); printf("%d\n", offsetof(struct S, i)); printf("%d\n", offsetof(struct S, c2)); return 0; }
- What is printed here is the offset of the members C1, I and C2 of struct S just now
Note: the macro has not been learned here. It can be implemented after the macro is explained.
Here's another word: gcc in Linux has no alignment number
1.8 structural transmission parameters
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S { int data[1000]; int num; }; struct S s = { {1,2,3,4}, 1000 }; //Structural transmission parameters void print1(struct S s) { printf("%d\n", s.num); } //Structure address transmission parameter void print2(struct S* ps) { printf("%d\n", ps->num); } int main() { print1(s);//Transmission structure print2(&s); //Transmission address return 0; }
- Although the result is the same, the print2 function is preferred.
- When transferring parameters to a function, the parameters need to be pressed on the stack, which will have system overhead in time and space.
- 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.
- I'll elaborate later. Now it's a little troublesome to explain
2. Bit segment
After the structure is finished, we have to talk about the ability of the structure to realize the bit segment.
2.1 what is a bit segment
- In fact, char is OK
printf("%d\n", sizeof(struct A));
2.2 memory allocation of bit segment
Look at the code
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct S { char a : 3; char b : 4; char c : 5; char d : 4; }; int main() { struct S s = { 0 }; s.a = 10; s.b = 12; s.c = 3; s.d = 4; return 0; }
- The size end is considered only when the byte order is used. It is not considered here
- As mentioned above: bit segments involve many uncertain factors, and bit segments are not cross platform
- Here I tested it in vs2019 for reference only
2.3 cross platform problem of bit segment
Summary:
Compared with the structure, bit segment can achieve the same effect, but it can save space, but there are cross platform problems.
2.4 application of bit segment
Let me give you a simpler example,
There are four combinations of two bits: 00, 01, 10, 11,
- Gender: male, female, confidential. Two bits are enough. Char a: 2 is enough, not int a
- Sometimes using bit segments saves more space than defining variables and structures
3. Enumeration
You can use enumeration here.
3.1 definition of enumeration type
3.2 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
- Easy to use, you can define multiple constants at a time
By the way, the macros and characters defined by define are replaced in preprocessing
3.3 use of enumeration
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> void menu() { printf("*****************************\n"); printf("**** 1. add 2. sub *****\n"); printf("**** 3. mul 4. div *****\n"); printf("**** 0. exit *****\n"); printf("*****************************\n"); } enum Option { EXIT,//0 ADD,//1 SUB,//2 MUL,//3 DIV,//4 }; int main() { int input = 0; do { menu(); printf("Please select:>"); scanf("%d", &input); switch (input) { case ADD://case 1: break; case SUB://case 2: break; case MUL://case 3: break; case DIV://case 4: break; case EXIT://case 5: break; default: break; } } while (input); return 0; }
- Enumeration is used to improve the readability of the code,
- Using enumeration is simpler than defining characters directly,
4. Consortium
4.2 characteristics of joint
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> union Un { char c;//1 int i;//4 }; int main() { union Un u = {10}; u.i = 1000; u.c = 100; printf("%p\n", &u); printf("%p\n", &(u.c)); printf("%p\n", &(u.i)); printf("%d\n", sizeof(u));// return 0; }
Face to face questions:
Code one
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int check_sys() { int a = 1; if ((*(char*)&a) == 1) { return 1;//Small end } else { return 0;//Big end } } int main() { int ret = check_sys(); if (ret == 1) printf("Small end\n"); else printf("Big end\n"); return 0; }
- In the previous chapters, I also said to judge the size of the computer. I used (char *)void *, and then judged whether the first byte was 1,
Code two
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int check_sys() { union U { char c; int i; }u; u.i = 1; return u.c; //Return 1 is the small end //Return 0 is the big end } int main() { int ret = check_sys(); if (ret == 1) printf("Small end\n"); else printf("Big end\n"); return 0; }
- The above is implemented by using the consortium method, mainly because the address of the consortium is shared, and the addresses of char c and int i are the same
4.3 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.
For example:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> union Un { char a[5];//1 5 int i;//4 char c;//1 }; int main() { union Un u; printf("%d\n", sizeof(u)); return 0; }
- The maximum member size is 5 and the maximum number of alignments is 4, so the result is 8
For example:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> union Un { short s[5];//2 10 int a;//4 }; int main() { union Un u; printf("%d\n", sizeof(u)); return 0; }
- The maximum member size is 10 and the maximum number of alignments is 4, so the result is 12
5. Practice
Address book - static version
- The address book can store the information of 1000 people. Each person's information: Name + age + gender + phone + address
- Add human information
- Delete the information of the designated person
- Modify the information of the designated person
- Find information about the specified person
- Sort address book information
- Here's a warning. I'll use dynamic memory to solve it later
---------------------------------------------------------------------------------------------------------------------------------
End of this chapter