Structure of C language (simplified)

The structure is a type created by ourselves, which makes C language capable of describing complex types. For example, students include: name, age, gender, student number...

cognition of structure

A structure is a collection of values ​​called member variables. Each member can be a variable of a different type.
—————————

The difference between structure and array:
Array: is a collection of elements of the same type.
Structure: It is a collection of values, but these values ​​can be of different types: they can be scalars, arrays, pointers, or even other structures.

declaration of the structure

general statement

Suppose a student is to be described here:

//描述一个学生
struct Stu   //Stu是结构体变量名,可以自定义(根据实际需求)
{
    
    
	//里面是成员列表
	char name[20];//学生名字
	int age;      //学生年龄
	char id[10];  //学生学号
	//....

}s1,s2,s3;  //这里是结构体变量,是全局变量,
           //(创建结构体类型时顺带创建3个结构体全局变量)
          //这后面的分号不能丢
int main()
{
    
    
	struct Stu s4, s5; //创建结构体变量,这些是局部变量

	return 0;
}

special statement

That is, when the structure is declared, it can be declared incompletely.

anonymous struct type

struct       //没有结构体变量名
{
    
    
	int a;
	char b;
	double c;
}s1;      //只能在这里创建结构体变量名,
         //且只能使用一次

struct self reference

Definition: A structure must be able to find the next structure of the same type as it;

  • A struct can contain another struct variable
struct book1
{
    
    
	char name[20];
	int age;
	int mony;
};

struct book
{
    
    
	char name[20];
	int mony;
	struct book1 s1;
};

However, the structure cannot have its own structure variables, but it can use a pointer to point to a structure of this type to realize the self-reference of the structure

struct Note
{
    
    
	int date;        //数据域
	struct Note* next;//指针域
};

Regarding the typedef (defining type) definition defines an anonymous struct type:

typedef struct
{
    
    
	int data;//数据域
	struct Node* next;//指针域
} Node;
void main() {
    
    
	Node n;
 }

Definition and initialization of structure variables

Definition of structure variables

// struct book 是定义的数据类型的名字,它向编译系统声明这是一个“结构体类型”
struct book  
{
    
    
	int mony;
	char name[20];
}s1,s2;//全局变量(创建结构体类型时顺带创建2个结构体全局变量)
       //最后的分号千万不能省略
int main()
{
    
    
	struct book s3, s4;//局部变量
	return 0;
}

Initialization of structure variables

struct book
{
int mony;
char name[20];
}s1={30,"xiyouji"}, s2 = {20,"hongloumeng"};//s1,s2也是结构体变量,其是全局变量,
//并对其全部初始化,其实也可不初始化


int main()
{
struct book s3 = { 15,"三国演义" }, s4 = {25,"水浒传"};
//创建结构体对象并完成初始化
//其中初始化一个汉字占两个字节
return 0;
}

Structure nested initialization:


struct history
{
int age;
int id;
};


struct book
{
char name[20];
int mony;
struct history s1;
};


int main()
{
struct book s1 = { "abcdef",20,{1000,2023}};//初始化完成
return 0;
}

Anonymous struct type initialization


struct {
char name[20];
int price;
char id[12];
}s = { "git",7,"123" };

Notice:

  • The declaration and initialization of the structure can also be carried out in the function
  • After the structure is defined, it must be initialized
  • The structure can also use the form of the operator "." to operate on the value inside

Struct parameter passing

struct BOOK
{
    
    
	char name[20];
	int money;
};

//传值调用
void test1(struct BOOK s)
{
    
    
	printf("%s %d", s.name, s.money);
}

//传址调用
void test2(struct BOOK* ps)
{
    
    
	printf("%s %d", ps->name, ps->money);
}

int main()
{
    
    
	struct BOOK s1 = {
    
     "shuihuzhuan",20 };

	test1(s1);//传结构体,不会改变结构体变量
	test2(&s1);//传结构体地址,可以改变结构体变量

	return 0;
}

Note:
pass the address of the structure parameter as much as possible, because the parameter needs to be pushed on the stack. If the structure object is passed, the structure is too large, and the system for pushing the parameter to the stack is too large, which will lead to performance degradation; call by
address When using const, const can be used; the function of const in structure passing parameters: the original structure can only be read and not changed, so as to prevent misoperation.

Structure memory alignment

Now that we have understood the basic use of structures, let's explore an in-depth question:
How to calculate the size of the structure?
here is involvedStructure memory alignment.
To understand these, first introduce amacro ( offsetof() ), which calculates the offset of a struct member relative to the struct's starting position .

size_t offsetof( structName, memberName );

1. The first parameter is the structure name
2. The second parameter is the structure member
Enter two parameters, and the offset of the structure member relative to the starting position of the structure will be returned.

Take this code to explore:

struct s1
{
    
    
	char c1;
	int i;
	char c2;
};

struct s2
{
    
    
	int i;
	char c1;
	char c2;
};

int main()
{
    
    
	printf("%d\n", offsetof(s1, c1));
	printf("%d\n", offsetof(s1, i));
	printf("%d\n", offsetof(s1, c2));
	return 0;
}

insert image description here

When the offset is known, we can analyze the way the structure is stored in memory;
the structure is stored in the stack area

insert image description here

In this case, it should be 9 bytes, but the result is 12 bytes, why?

insert image description here

The above problems indicate that the members of the structure are not stored continuously in the memory in order, but have certain rules.

Rules for structure memory alignment:

1. The first member of the structure is always placed at an offset of 0 compared to the starting position of the structure variable.

2. Starting from the second member, each subsequent member must be aligned to an address that is an integer multiple of a certain number (alignment number). Alignment number
: the comparison between the default alignment number of the compiler and the size value of the member small value.
The default alignment number on the VS compiler is: 8
gcc: There is no default alignment number, and the alignment number is the size of the structure member.

3. The total size of the structure must be an integer multiple of the maximum alignment.
Maximum alignment: the maximum value of all alignments

4. If a structure is nested, the nested structure is aligned to an integer multiple of its maximum alignment number, and the integer size of the structure is the integer of the maximum alignment number (including the alignment number of the nested structure) times.

So how to use this rule?
Look at the pictures and talk:
insert image description here

One special point: if the member variable is an array.


For example: int arr [3]; just treat it as three integer variables and store them sequentially.

Why memory alignment?

1. Platform reasons:

  • Not all hardware platforms can access arbitrary data at any address; some hardware platforms can only fetch certain types of data at certain addresses, otherwise a hardware exception is thrown.

2. Performance reasons

  • Data structures should be aligned on natural boundaries as much as possible. The reason is this: To access unaligned memory, the processor needs two memory accesses; while aligned memory access requires only one access.

3. Explain as shown in the figure:
insert image description here
Summary: Structure memory alignment is the practice of exchanging space for time

Therefore, when designing the structure, we must not only satisfy the alignment, but also save space:

1. Reasonably arrange the member space of the structure


2. You can also modify the default alignment

Modify the default alignment:

#include <stdio.h>
//修改默认对齐数为1
#pragma pack(1)
struct Hand
{
    
    
	char c;
	int size;
	char q;
};
#pragma pack()//取消设置的默认对齐,还原默认
int main() {
    
    
	printf("%d\n", sizeof(struct Hand));//默认对齐数8时——12,默认对齐数1时——6
	return 0;
}

bit segment

Compared with the structure, it can save space, but has cross-platform problems;

Why there is a bit segment: because if there are 32 bits in a byte, when you only use 2 bits, the other space will be wasted, and the bit segment can choose how much space each of your members takes up, so you can change it. Good space saver.

bit field declaration

Its declaration is similar to the structure declaration, with two differences:

1. Bit field members can be int, unsigned int, signed int or char (integer family) type.
__
2. There is a colon and a number after the member name of the bit segment.
__

Example:

** S is a bit field type **

struct S
{
    
    
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};

bit segment memory allocation

Take the above bit segment type to explore;

1. The members of the bit segment can be int, unsigned int, signed int or char (integer family) type
2. The space of the bit segment is 4 bytes (int) or 1 byte (char) as required 3. Bit
segments involve many uncertain factors. Bit segments are not cross-platform. Programs that focus on portability should avoid using bit segments. 4. First of all, the numbers
behind each member are bits, which are binary bits.

struct S
{
    
    
	//因为先是char类型,先开辟一个字节--8个bit位
	char a : 3;//a成员占3个bit
	char b : 4;//b成员占4个bit
	char c : 5;//这时用了7个bit,还剩1个,因为下面还是char类型,不够就再开辟一个字节
	//c成员在新开辟的字节占5个bit
	char d : 4;//这时还剩3个bit,char类型,开辟一个字节,d成员占4个bit
	//因此S位段类型所占3个字节
};

int main()
{
    
    
	struct S s = {
    
     0 };
	s.a = 10;
	s.b = 20;
	s.c = 3;
	s.d = 4;

	printf("%d ", sizeof S);//3
	return 0;
}

For the data inside the next byte of the VS compiler, the address of the low bit is used first, and then the address of the high bit is used (the allocation in memory is used from right to left)
insert image description here

Bit segment cross-platform issues:

1. The type of int bit field, whether it is regarded as a signed bit or an unsigned bit, is uncertain;
2. The maximum number of bits in a bit field cannot be determined. (16-bit machines have a maximum of 16, 32-bit machines have a maximum of 32, written as 27, there will be problems on 16-bit machines.
3. The members in the bit segment are allocated from left to right in memory, or from right to left. The standard has not yet been defined.
4. When a structure contains two bit segments, and 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, the bit segment can achieve the same effect, which can save space very well, but there is a cross-platform problem.

6 hours of continuous liver is really not covered ^ _ ^ Finally, I hope that brothers and sisters will support a little bit, next time our liver will explode.

Guess you like

Origin blog.csdn.net/m0_66780695/article/details/132054437