Data type:
C language built-in type:
— char short int long float double
Custom type / construction type:
- structure, enumeration, union
1, Structure
1. Special declaration
When declaring a structure, you can declare it incompletely
Anonymous structure
struct { int a; char c; double d; }s1, s2; // correct int main() { struct s3; // err return 0; }
Anonymous structure type
struct { int a; char c; double d; }s1, s2; struct { int a; char c; double d; }*ps; int main() { ps = &s1; // '=': incompatible types from '*' to '*' // The compiler will treat the above two declarations as two completely different types, which is illegal return 0; }
2. Structure self reference
Data structure: describes the structure of data stored in memory Linear data structure: sequential list, linked list
Node of the same type found node of the same type
Incorrect writing:
struct Node { int date; struct Node n; // Wireless recursive err };
Correct writing: save address
struct Node { int date; // Data domain struct Node* next; // Pointer field };
Where is the error of the following code and how to correct it
typedef struct { int date; Node* next; }Node;
The anonymous structure is named, but it has not been generated when used
Solution:
typedef struct Node { int date; struct Node* next; }Node;
3. Definition and initialization of structure variables
Create and initialize
struct Point { int x; int y; }p1 = { 5,6 }, p2; // overall situation struct Point p2 = { 1,2 }; // overall situation int main() { struct Point p1 = { 3,4 }; // local // Program run here to create // Global variables are created before the program runs return 0; }
Structure nesting initialization
struct Point { int x; int y; }p1 = { 5,6 }, p2; struct Point p2 = { 1,2 }; struct S { double d; struct Point p; char name[20]; }; int main() { struct Point p1 = { 3,4 }; struct S s = { 3.14, {1, 5}, {"zhangsan"}}; return 0; }
4. Print structure
#include <stdio.h> struct Point { int x; int y; }p1 = { 5,6 }, p2; struct Point p2 = { 1,2 }; struct S { double d; struct Point p; char name[20]; int date[20]; }; int main() { struct Point p1 = { 3,4 }; struct S s = { 3.14, {1, 5}, {"zhangsan"}, {1,2,3} }; printf("%lf\n", s.d); // 3.140000 printf("%d %d\n", s.p.x, s.p.y); // 1 5 printf("%s\n", s.name); // zhangsan int i = 0; for (i = 0; i < 20; i++) { printf("%d ", s.date[i]); // 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } return 0; }
2, Structure memory alignment
What is the same as like as two peas of S1 and S2, but how much difference does S1 and S2 occupy?
#include <stdio.h> struct S1 { char c1; int a; char c2; }; struct S2 { char c1; char c2; int a; }; int main() { struct S1 s = { 'x', 100, 'y' }; printf("%d\n", sizeof(struct S1)); // 12 printf("%d\n", sizeof(struct S2)); // 8 printf("%d\n", sizeof(s)); // 12 return 0; }
1. Memory alignment
Structure memory alignment rules:
- The first member of the structure is always placed where the starting position of the structure is offset by 0
- Structure members start with the second member and are always placed at an offset of an integer multiple of a pair
Alignment number = the compiler's default alignment number and the smaller value of the variable's own size
Linux - no default alignment number (its own size is the alignment number)
VS - the default number of alignments is 8 - The total size of the structure must be an integral multiple of the maximum number of alignments of each member
practice:
struct S3 { double d; char c; int i; };
// 16
How to find nested structure
#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; }
Rule 4:
If a structure is nested, the nested structure is aligned to an integer multiple of its maximum alignment number,
The overall size of a structure is an integer multiple of the maximum number of alignments (including the number of alignments of nested structures).
Why is there memory alignment?
- Platform reason (migration reason): not all hardware platforms can access any data at any address; Some hardware platforms can only work at certain addresses
Get some specific types of data, otherwise throw a hardware exception. - Performance reason: data structures (especially stacks) should be aligned on natural boundaries as much as possible. The reason is that in order to access misaligned memory, the processor
Two memory accesses are required; Aligned memory access requires only one access
Summary:
Memory alignment of structures is a way to trade space for time
When designing the structure, we should not only meet the alignment, but also save space. How to:
Let the members with small space gather together as much as possible.
2. Modify the default number of alignments
Use the preprocessing instruction #pragma to set the default alignment number and cancel the setting to restore the default alignment number
Example: modify the alignment number of structure S1 to 1
#include <stdio.h> // Next to each other, there is no space to waste and the efficiency is low #pragma pack(1) struct S1 { char c1; int i; char c2; }; #pragma pack() int main() { struct S1 s[] = { 0 }; printf("%d\n", sizeof(s)); // 6 return 0; }
3. Macro offsetof (type can be passed when parameters are passed)
Calculates the offset of a structure member from the starting position of the structure stored in memory
size_t offsetof( structName, memberName );
#include <stdio.h> #include <stddef.h> struct S1 { char c1; int i; char c2; }; int main() { printf("%d\n", offsetof(struct S1, c1)); // 0 printf("%d\n", offsetof(struct S1, i)); // 4 printf("%d\n", offsetof(struct S1, c2)); // 8 return 0; }
4. Structural transmission parameters
Value / address transmission
#include <stdio.h> struct S { int data[1000]; int num; }; // Structural transmission parameters void print1(struct S tmp) { int i = 0; for (i = 0; i < 10; i++) { printf("%d ", tmp.data[i]); } printf("\nnum = %d\n", tmp.num); } // Structure address transfer parameter void print2(struct S* ps) { int i = 0; for (i = 0; i < 10; i++) { printf("%d ", ps->data[i]); } printf("\nnum = %d\n", ps->num); } int main() { struct S s = { {1,2,3,4,5,6,7,8,9,10}, 100 }; print1(s); // Transmission structure print2(&s); // Transmission address return 0; }
When a function passes parameters, 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.
3, Bit segment
1. The ability of a structure to implement a bit segment
- Bit segments can save space
- Bit segment - binary bit
#include <stdio.h> struct A { int _a : 2; // _ a - 2 bits are bits int _b : 5; // _ b - 5 bit s int _c : 10; int _d : 30; }; int main() { printf("%d\n", sizeof(struct A)); // 8 return 0; }
2. Memory allocation for bit segments
- The member 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 segments involve many uncertain factors. Bit segments are not cross platform. Pay attention to portable programs and avoid using bit segments.
An example:
struct S { char a : 3; char b : 4; char c : 5; char d : 4; }; int main() { struct S s = { 0 }; s.a = 10; // 1010 - 010 s.b = 12; // 00001100 - 1100 s.c = 3; // 00000011 - 00011 s.d = 4; // 00000100 - 0100 }
How is space opened up?
Conjecture: char-> First open 1 byte 00000000 a-3bit 010 b-4bit 1100 There is not enough space left. Open up another byte c-5bit 00011 There is not enough space left. Open up another byte d-4bit 0100 Left<-Right height 0(1100)(010) 000(00011) 0000(0100) 62 03 04
3. 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 uncertain whether to discard the remaining bits or use them.
Summary:
Compared with the structure, bit segment can achieve the same effect, but it can save space, but there are cross platform problems.
4, Enumeration
enum Color enumeration type. {} is the possible value of enumeration type, also known as enumeration constant
#include <stdio.h> enum Color { RED = 2, // Initial value assignment GREEN, BLUE, }; int main() { enum Color c = GREEN; // Possible values assigned to enumeration types if (c == GREEN) { printf("green\n"); } return 0; }
Advantages of enumeration:
We can use #define to define constants. Why do we have to use 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
Example: clear calculator
enum Option { EXIT, // 0 ADD, // 1 SUB, MUL, DIV, }; int main() { int input = 0; do { menu(); printf("Please select:>\n"); switch (input) { case ADD: break; case SUB: break; case MUL: break; case DIV: break; case EXIT: break; } } while (input); return 0; }
5, Consortium (Consortium)
1. Definition of union type
Union is also a special user-defined type. The variables defined by this type also contain a series of members. The characteristic is that these members share the same space (so union is also called community)
#include <stdio.h> //Declaration of union type union Un { char c; int i; }; int main() { //Definition of joint variables union Un u = { 0 }; // Same address printf("%p\n", &u); printf("%p\n", &(u.c)); printf("%p\n", &(u.i)); return 0; }
2. 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 storage size of the current computer:
#include <stdio.h> // 1 int main() { int a = 1;//0x 00 00 00 01 //Low ------------------- > High //01 00 - small end storage //00 01 - big end storage char* pc = (char*)&a; if (*pc == 1) { printf("Small end\n"); } else { printf("Big end\n"); } }
Using Consortium:
// 2 int check_sys() { union U { char c; int i; }u; u.i = 1; return u.c; } int main() { if (check_sys() == 1) { printf("Small end\n"); } else { printf("Big end\n"); } return 0; }
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.
Example: calculate the following code results
union Un1 { char c[5]; // 5 1 int i; // 4 8 4 // The total size of the union must be a multiple of 4. 3 bytes are wasted after c. The result is 8 }; union Un2 { short c[7]; // 14 2 int i; // 4 8 4 // 14 is not a multiple of 4. The result is 16 }; int main() { printf("%d\n", sizeof(union Un1)); // 8 printf("%d\n", sizeof(union Un2)); // 16 }
Address book program