C language exercise 58: Custom type: structure

Custom type: structure

 

The concept of structure

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

A structure is a custom data type that can be composed of many default data types. It is mainly used to describe variables in complex scenarios.

For example, if you want to describe a student through a structure
struct Stu
{
 char name[20];//名字
 int age;//年龄
 char sex[5];//性别
 char id[20];//学号
}; //分号不能丢

Structure form:

struct 结构体名
{
	数据类型1 成员变量1;
	数据类型2 成员变量2;
	..........
};

 special statement

When declaring a structure, you can declare it incompletely.

//匿名结构体类型
struct
{
 int a;
 char b;
 float c;
}x;
struct
{
 int a;
 char b;
 float c;
}a[20], *p;

The above two structures omit the structure tag when they are declared.

So here’s the problem?

//Based on the above code, is the following code legal? p = &x;

Warning: The compiler will treat the above two declarations as two completely different types, so they are illegal.

Anonymous structure types can basically only be used once if the structure type is not renamed.

Self-reference of structure Is it okay to include a member of the type of the structure itself in the structure? For example, define the nodes of a linked list:

struct Node
{
	int data;
	struct Node next;
};

Is the above code correct?

If correct, what is sizeof(struct Node)?

After careful analysis, it is actually not feasible, because if a structure contains another structure variable of the same type, the size of the structure variable will be infinite, which is unreasonable. Correct way to use self-reference:

struct Node
{
 int data;
 struct Node* next;
};

In the process of self-referencing and using the structure, typedef is mixed in to rename the anonymous structure type, which can easily cause problems. Take a look at the following code. Is it feasible?

typedef struct
{
 int data;
 Node* next;
}Node;

The answer is no,

Because Node is produced by renaming the previous anonymous structure type, it is not feasible to use the Node type to create member variables in advance inside the anonymous structure. The solution is as follows: Don’t use anonymous structures when defining structures.

typedef struct Node
{
 int data;
 struct Node* next;
}Node;

Creation and initialization of structure variables

Two ways to create:

struct Stu 
{
	char name[20];//名字
	int age;//年龄
	float score;//成绩
}s1,s2,s3;
struct Stu 
{
	char name[20];//名字
	int age;//年龄
	float score;//成绩
};
int main()
{
	struct Str s1;
	return 0;
}

 initialization

struct Stu 
{
	char name[20];//名字
	int age;//年龄
	float score;//成绩
};
int main()
{
	struct Stu s1 = { "zhangsan",20, 98.5f };
	struct Stu s2 = { "lisi",33, 68.5f};
	struct Stu s3 = { "wangwu",24, 98.0f };
	struct Stu s4 = { .age = 22,.name = "cuihua", .score = 55.5f };

	printf("%s %d %f\n", s1.name, s1.age, s1.score);
	printf("%s %d %f\n", s4.name, s4.age, s4.score);

	return 0;
}

structure member access operator

There are two structure member access operators

One is . and the other is -> . The form is as follows:

Structure variable.Member variable name

Structure pointer—>member variable name

For example:

#include <stdio.h>
#include <string.h>
struct Stu
{
 char name[15];//名字
 int age; //年龄
};
void print_stu(struct Stu s)
{
 printf("%s %d\n", s.name, s.age);
}
void set_stu(struct Stu* ps)
{
 strcpy(ps->name, "李四");
 ps->age = 28;
}
int main()
{
 struct Stu s = { "张三", 20 };
 print_stu(s);
 set_stu(&s);
 print_stu(s);
 return 0;
}

Structure memory alignment

First, you must master the alignment rules of the structure :

1. The first member of the structure is mapped to the address with an offset of 0 relative to the starting position of the structure variable.

2. Other member variables must be mapped to an address that is an integer multiple of a certain number (logarithm). Logarithm = The smaller value of the compiler’s default logarithm and the size of the member variable. - The default value in VS is 8 - There is no default logarithm in Linux, the logarithm is the size of the member itself

3. The total size of the structure is an integer multiple of the maximum logarithm (each member variable in the structure has a logarithm, the largest of all logarithms).

4. If a structure is nested, and the members of the nested structure are aligned to an integer multiple of the maximum alignment number among its own members, the overall size of the structure is the maximum alignment number (including An integer multiple of the logarithm of the members in the nested structure).

//练习1
struct S1
{
 char c1;
 int i;
 char c2;
};
printf("%d\n", sizeof(struct S1));

 Analyze the size occupied by S1.
The size of the first member variable is 1, and the default alignment number is 4, so its alignment number is 1. But according to the above rules, c1 starts from the starting position deviation of 0, then c1 occupies the starting position, occupying 1 byte; the size of the second member variable is 1, and the default
alignment number is 4, then it The alignment number of is also 1. According to the above rules, c2 is the position where the starting position deviation is an integral multiple of 1, but any number is an integral multiple of 1, so c2 occupies the address with the deviation value = 1, occupying 1 byte;
third The size of each member variable is 4, and the default integer multiple positions are also deviation values ​​0, 4, 8, 12... and so on. So the starting position of a is the position with offset value 4, which occupies 4 bytes. The alignment number is 4, then its alignment number is also 4. According to the above rules, the starting position of a must be with a deviation value of 4.
Note that the positions with a deviation value of 2 and a deviation value of 3 are empty, so S1 occupies 8 bytes. In the picture below, yellow is c1, blue is c2, and red is c3. The number next to it is the deviation value between the current address and the starting address.

//练习3
struct S3
{
 double d;
 char c;
 int i;
};
printf("%d\n", sizeof(struct S3));

 Learn that the size of S3 is 16 bytes. The maximum number of alignments is 8. So this is what S4 has in its memory: 

struct S4
{
 char c1;
 struct S3 s3;
 double d;
};
printf("%d\n", sizeof(struct S4));

 

S4 size is 32 bytes.

Why do memory alignments exist?

1. Platform reasons (transplantation reasons): Not all hardware platforms can access any data at any address; some hardware platforms can only fetch certain types of data at certain addresses, otherwise a hardware exception will be thrown.

2. Performance reasons: Data structures (especially stacks) should be aligned on natural boundaries as much as possible. The reason is that to access unaligned memory, the processor requires two memory accesses; aligned memory access requires only one access. Assuming a processor always fetches 8 bytes from memory, the address must be a multiple of 8. If we can ensure that the addresses of all double type data are aligned to multiples of 8, then we can use a memory operation to read or write the value. Otherwise, we may need to perform two memory accesses because the object may be divided into two 8-byte memory blocks.

Generally speaking: the memory alignment of structures is to trade space for time.

Keep members who take up little space together as much as possible

Modify the default logarithm (memory alignment can be ignored after modification)

#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对⻬数,还原为默认
int main()
{
 //输出的结果是什么?
 printf("%d\n", sizeof(struct S));
 return 0;
}

Structure parameter passing

struct S
{
 int data[1000];
 int num;
};
struct S s = {
   
   {1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
 printf("%d\n", ps->num);
}
int main()
{
 print1(s); //传结构体
 print2(&s); //传地址
 return 0;
}

Which of the print1 and print2 functions above is better?

The answer is: the print2 function is preferred.

Reason: When the function passes parameters, the parameters need to be pushed onto the stack, which will cause system overhead in time and space. If a structure object is passed and the structure is too large, the system overhead of pushing parameters onto the stack will be relatively large, which will lead to performance degradation. Conclusion: When passing parameters to a structure, you must pass the address of the structure.

Structure type variables need to access their members

 B should be: (*p).a

Guess you like

Origin blog.csdn.net/2301_77479435/article/details/132889433