A thorough study of C language 4. Linked lists and structures

Table of contents

1. Structure 

1. Definition of structure

2. The concept of structure

1.

2.

3.

4.

 5.

6.

3. Use of structural variables

1. Operators '->' and '.' of structure variables

2. Assignment of structure variables

3. Structural variables as function parameters

4. Structure pointer

5.Structure size

2. Dynamic memory allocation

1. Dynamic memory management function

 1.malloc function

2.calloc function 

3.free function

Precautions:

2. Memory processing function

1.memcpy function

2.memmove function

 Three, linked list

1. Definition and use of linked lists

1. Linked list is the most important application of structure.

2. Creation of linked list

To summarize the above questions,

3. Reverse linked list

 4. Add, delete and check operations on linked lists


Linked lists and structures are relatively difficult things. Moreover, these are the foundation for learning data structures later. They can be said to be a link between the past and the following. You must learn them well.

The first thing I want to say is that there are many connections between structures and pointers, which means that your knowledge of pointers must be passed.

Let's take our time now, little by little.

1. Structure 

1. Definition of structure

struct s {
	int i;
	char c;
};

Struct s is the type name, and the variables have not been defined yet. i and c are both member variables of the structure. What you need to know is that the structure is a custom type (you can look ahead to see my initial C language 2. The four structures of C language). So, struct s is just a type name, not that it is a structure named s. I have not defined a new structure variable name at this time. Remember to add a semicolon when defining the structure type;

You can define it later, or you can just add the variable name after the semicolon in the curly braces. (Multiple can be defined)

struct s {
	int i;
	char c;
}s1,s2;

You can also define a structure called an anonymous structure .

struct {
	int i;
	char c;
};

It is a structure that does not give variable names.

The following is a blog post about the use of anonymous structures that I found on csdn. You can take a look. (3 messages) Anonymous structure and anonymous union_kuikuitage's blog-CSDN blog_anonymous structure

#include <stdio.h>    

struct person    
{    
    char    *name;    
    char     gender;    
    int      age;    
    int      weight;    
    struct  
    {    
        int  area_code;    
        long phone_number;    
    };   
};    

int main(void)    
{  
    struct person jim = {"jim", 'F', 28, 65, {21, 58545566}};  
    printf("%d\n", jim.area_code);       
}   
1#include <stdio.h>    

struct person    
{    
    char    *name;    
    char     gender;    
    int      age;    
    int      weight;    
    struct  
    {    
        int  area_code;    
        long phone_number;    
    };   
};    

int main(void)    
{  
    struct person jim = {"jim", 'F', 28, 65, {21, 58545566}};  
    printf("%d\n", jim.area_code);       
}   


如果不使用匿名结构体,则上述例子对应的代码如下:

#include <stdio.h>    

struct phone  
{  
    int  area_code;  
    long phone_number;  
};  

struct person    
{    
    char        *name;    
    char         gender;    
    int          age;    
    int          weight;    
    struct phone office;  
};    

int main(void)    
{  
    struct person jim = {"jim", 'F', 28, 65, {21, 58545566}};  

    printf("%d\n", jim.office.area_code);       
}   



对比上述两个例子可以看出:

使用匿名结构体,结构体对象 jim 可以通过 jim.area_code 直接访问匿名结构体成员变量 area_code,代码相对比较简洁

反之则必须通过 jim.office.area_code 来访问结构体成员变量

2. The concept of structure

1.

A structural type is a data type that allows programmers to aggregate some data components into a whole. Each data component contained in a structure has a name. These data components are called structure members or structure components.

Struct members can be any variable type in C language.

2.

In C language, the definition of a structure is regarded as a statement.

3.

Compared with arrays, structures provide a more convenient means of organizing different types of data together. Increased readability and made the program clearer.

4.

Structures can be nested, unlike functions, which cannot be nested. However, when defining a nested structure type, you must first define the member structure type, and then define the main structure type.

 Note that this is done in order.

 5.

The keyword struct and the structure name s must be used together, because they can only represent a variable name when combined.

6.

C language stipulates that the storage layout of structure type variables is arranged in the order of members in its type definition.

Let me show you two examples.

#define _CRT_SECURE_NO_WARNINGS 1
//输出平均分最高的学生信息
#include<stdio.h>
struct student {
	int num;
	char name[10];
	int computer, english, math;
	double average;
};
int main() {
	int i, n;
	//定义结构变量
	struct student max, stu;

	printf("Input n:");
	scanf("%d",&n);
	printf("Input the student's information:");
	
	//这里与已知长度和数据的数组的选择法排序不同,这里数据都是未知的。
	for (i = 1; i <= n; i++) {
		printf("NO.%d:",i);
		scanf("%d%s%d%d%d",&stu.num,stu.name,&stu.math,&stu.english,&stu.computer);
		stu.average = (stu.math + stu.english + stu.computer) / 3.0;
		if (i == 1) {
			max = stu;
		}
		else if (max.average < stu.average)
			max = stu;
	}
	printf("num:%d,name:%s.average:%2lf\n",max.num,max.name,max.average);

	return 0;
#include <stdio.h>
#define MAXN 10

struct student{
    int num;
    char name[20];
    int score;
    char grade;
};

int set_grade( struct student *p, int n );

int main()
{   struct student stu[MAXN], *ptr;
    int n, i, count;

    ptr = stu;
    scanf("%d\n", &n);
    for(i = 0; i < n; i++){
       scanf("%d%s%d", &stu[i].num, stu[i].name, &stu[i].score);
    } 
   count = set_grade(ptr, n);
   printf("The count for failed (<60): %d\n", count);
   printf("The grades:\n"); 
   for(i = 0; i < n; i++)
       printf("%d %s %c\n", stu[i].num, stu[i].name, stu[i].grade);
    return 0; 
}

int set_grade( struct student *p, int n ){
	int count=0; 
	for(int i=0;i<n;i++){
		if((p->score)<60){
			count++;
			p->grade='D';
		}else if(p->score>=60 && p->score<=69){
			p->grade='C';
		}else if(p->score>=70 && p->score<=84)
			p->grade='B';
		else
			p->grade='A';	
		p++;
	}
	return count;
}

3. Use of structural variables

1. Operators '->' and '.' of structure variables

'->' is the operator used by pointers to operate structure variables, and '.' is the operator used by ordinary variables to operate structure variables.

Since the precedence of the structure member operators is the highest, they are generally executed first.

2. Assignment of structure variables

If two structure variables have the same type, it is allowed to assign the value of one structure variable directly to another structure variable.

This is the only overall mode of operation in the structure.

 That is, only variables of the same structural type can be assigned directly.

3. Structural variables as function parameters

Features: Multiple data can be passed and the parameter form is relatively simple. However, for large structures with many members, the copying of structural data when passing parameters makes the efficiency low.

A more appropriate method at this time is to define a structure pointer and just use the pointer as a parameter.

4. Structure pointer

Pointers can point to variables of any type. The value of the structure pointer is actually the first address of the structure variable. That is the address of the first member.

5.Structure size

 This involves a concept called alignment number.

(3 messages) Memory alignment number in C language_Breeze-CSDN Blog_C language memory alignment https://blog.csdn.net/qq_34328833/article/details/51352663?ops_request_misc=%257B%2522request%255Fid%2522% 253A%2522163991575616780265494360%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=1639915756167 80265494360&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-51352663 .pc_search_result_cache&utm_term=%E5%AF%B9%E9%BD%90%E6%95%B0&spm=1018.2226.3001.4187 I have seen this and it is pretty good. You can take a look.

2. Dynamic memory allocation

1. Dynamic memory management function

 1.malloc function

The parameter after the malloc function is the length (bytes) to be allocated, and the return value is of void* type. Therefore, forced type conversion is required when using it.

2.calloc function 

The num here refers to the allocation of size bytes of space, and num is allocated. (continuous space) 

3.free function

The function of the free function is to release the dynamic space previously allocated to the pointer variable ptr, but the pointer variable ptr will not automatically become a null pointer, and will still point to the place pointed to before. Therefore, after releasing, if the ptr pointer is still used, remember to leave it blank, otherwise ptr will be a wild pointer.  

Precautions:

1. Remember to release the space every time you dynamically apply for space.

2. What is obtained in dynamic memory allocation is a continuous space without a name and only the first address, which is equivalent to an unnamed one-dimensional array.

3.malloc does not perform any operation on the allocated storage block. But calloc will automatically initialize the entire area to 0.

4. Dynamic memory allocates space in the heap area, which is either released by the operator or released by the system when the program ends.

2. Memory processing function

1.memcpy function

 num refers to the length (bytes), destination refers to the destination, and source refers to the variable address used to transfer.

According to C language regulations, memcpy should copy memory that does not overlap.

2.memmove function

 It’s similar to the above. What’s the difference between the two? I have written a chapter about simulating their implementation before, you can check it out.

 Three, linked list

1. Definition and use of linked lists

1. Linked list is the most important application of structure.

It is a non-fixed length data structure and a dynamic storage technology that can only be accessed sequentially and not randomly. Arrays in structures tend to waste space and are inconvenient to operate.

Self-referencing of structures

The self-reference of a structure does not refer to itself in the structure, but refers to a structure pointer of the same type (this is also the representation of a linked list)

2. Creation of linked list

1) Apply for memory m: The memory is divided into two parts, one part is called the data domain, and the other part is called the pointer domain. The domain here is the place where it is stored. The data domain stores some ordinary data, and the pointer domain stores a pointer that points to The first address of the next linked list node.

2) Store the data in

3) If the current node is the first node, save the address of m in the pointer head, otherwise save the first address of m in the pointer field of the previous node.

4) Repeat the above process until the data storage is completed, and store the end flag NULL in the pointer field of the last node;

 Let’s take a look at two more questions.

1.

//求单链表结点的阶乘和
#include <stdio.h>
#include <stdlib.h>
typedef struct Node* PtrToNode;
struct Node {
    int Data; /* 存储结点数据 */
    PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

int FactorialSum(List L);

#define _CRT_SECURE_NO_WARNINGS 1
int FactorialSum(List L) {
	int sum = 0;
	PtrToNode p;
	for (p = L; p; p = p->next) {
		int fact = 1;
		for (i = 1; i <= p->date; i++) {
			fact *= i;
		}
		sum += fact;
	}
	return sum;
}



int main()
{
    int N, i;
    List L, p;

    scanf("%d", &N);
    L = NULL;
    for (i = 0; i < N; i++) {
        p = (List)malloc(sizeof(struct Node));
        scanf("%d", &p->Data);
        p->Next = L;  L = p;
    }
    printf("%d\n", FactorialSum(L));

    return 0;
}

2.

//建立学生信息链表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stud_node {
	int    num;
	char   name[20];
	int    score;
	struct stud_node* next;
};
struct stud_node* head, * tail;

void input();

int main()
{
	struct stud_node* p;

	head = tail = NULL;
	input();
	for (p = head; p != NULL; p = p->next)
		printf("%d %s %d\n", p->num, p->name, p->score);

	return 0;
}


void input() {
	struct stud_node* p;
	int x;
	scanf("%d", &x);
	while (x) {
		p = (struct stud_node*)malloc(sizeof(struct stud_node));
		p->num = x;
		scanf("%s%d",p->name, &p->score);
		p->next = NULL;
		if (head == NULL)
			head = p;
		else
			tail->next = p;
		tail = p;
		scanf("%d", &x);
	}
}

3.

//建立一个有N个学生信息数据的链表
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define N 4
struct student {
	//数据域
	int num;
	char name[20];
	char sex;
	int score;
	//指针域
	struct student* next;
};
int main() {
	//定义指针变量
	struct student* head, * p, * q;
	//定义结点大小
	p = (struct student*)malloc(sizeof(struct student));
	//初始化结点
	scanf("%d%s%c%d",&p->num,p->name,&p->sex,&p->score);
	//将第一个结点的地址给head。
	head = p;
    head->next=NULL;
	//用一个for循环,初始化所有的结点,即整个链表。
	for (int i = 0; i < N; i++) {
		//要重新定义第二个结点,然后初始化
		q = (struct student*)malloc(sizeof(struct student));
		scanf("%d%s%c%d", &q->num, q->name, &q->sex, &q->score);
		//让前一个结点的指针域指向下一个结点的地址
		p->next = q;
		//再让p指向已定义好的结点,q指针继续去处理下一个结点。
		p = q;
	}
	//循环结束后,最后一个结点的指针域为空。
	p->next = NULL;
	//用一个for循环输出所有结点中的信息
	for (p = head; p; p = p->next) {
		printf("%d %s %c %d\n",p->num,p->name,p->sex,p->score);
	}


	return 0;
}

4.

//链表的比较及排序
#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<stdlib.h>
#define N 10
struct student {
	int num;
	int score;
	struct student* next;
};
int main() {
	struct student* head, * p, * q, * k;
	k = (struct student*)malloc(sizeof(struct student));
	//以后内存函数的使用都要判断一下,是否开辟成功,如果未开辟成功,则结束进程
	if (!k)
		exit(1);

	scanf("%d%d",&k->num,&k->score);
	//初始化第一个结点,因为结点是不连续的,仅仅是靠指针域中的地址来进行联系,所以,这既是第一个结点,也是最后一个结点,对指针域进行初始化
	k->next = NULL;
	head = k;


	//接下来对后面的N-1个结点进行定义初始化
	//这一整个片段是很关键的一环,写的是真的好,主要是我没见过
	for (int i = 1; i < N; i++) {
		k = (struct student*)malloc(sizeof(struct student));
		//判断语句
		if (!k)
			exit(1);

		scanf("%d%d", &k->num, &k->score);
		//让p指向第一个结点
		p = head;
		q = NULL;
        //插入操作
		//此时的while起一个比较的作用(升序)
		while (p && (p->num <= k->num)) {
			
			q = p;
			p = p->next;
		}
		if (p == head) {
			k->next = head;
			head = k;
		}
		else {
			k->next = q->next;
			q->next = k;
		}
	}
	/*首先,让p指向第一个结点,k指向的是一个新结点,二者相比较,如果k指向的结点大于p指向的,先把初始结点的地址给q,p就指向下一位,
	执行else语句。即在q指向的结点后面插入k指向的结点。
	如果p指向的结点数据大于k指向的结点数据,则将k指向的结点插到第一个结点前面,也就是插到相比较结点的前面。
    交换完数据以后,利用for循环再次重新定义一个新节点,再次进行比较。
	*/

    free(k);//一定要记得释放申请的内存
	//输出整个的链表
	for (p = head; p; p = p->next) {
		printf("%d  %d\n", p->num,p->score);
	}

	return 0;
}

To summarize the above questions,

There are two ways to create a linked list. One is to use a for loop to first define a head node, and then use a for loop to continue to create subsequent nodes. The other is to use a while loop to set a lying branch structure in it. When the defined node is the first tense, and is not the first tense.

//定义指针变量
	struct student* head, * p, * q;
	//定义结点大小
	p = (struct student*)malloc(sizeof(struct student));
	//初始化结点
	scanf("%d%s%c%d",&p->num,p->name,&p->sex,&p->score);
	//将第一个结点的地址给head。
	head = p;
    head->next=NULL;
	//用一个for循环,初始化所有的结点,即整个链表。
	for (int i = 0; i < N; i++) {
		//要重新定义第二个结点,然后初始化
		q = (struct student*)malloc(sizeof(struct student));
		scanf("%d%s%c%d", &q->num, q->name, &q->sex, &q->score);
		//让前一个结点的指针域指向下一个结点的地址
		p->next = q;
		//再让p指向已定义好的结点,q指针继续去处理下一个结点。
		p = q;
	}
	//循环结束后,最后一个结点的指针域为空。
	p->next = NULL;
void input() {
	struct stud_node* p;
	int x;
	scanf("%d", &x);
	while (x) {
		p = (struct stud_node*)malloc(sizeof(struct stud_node));
		p->num = x;
		scanf("%s%d",p->name, &p->score);
		p->next = NULL;
		if (head == NULL)
			head = p;
		else
			tail->next = p;
		tail = p;
		scanf("%d", &x);
	}
}

It is necessary to distinguish between these two methods and what to do when doing so.

3. Reverse linked list

http://hi.csdn.net/attachment/201010/23/0_1287825676duab.gifhttp://hi.csdn.net/attachment/201010/23/0_1287825676duab.gif

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

typedef struct tagListNode {
    int data;
    struct tagListNode* next;
}ListNode, * List;

void PrintList(List head);
List ReverseList(List head);

int main()
{
    //分配链表头结点
    ListNode* head;
    head = (ListNode*)malloc(sizeof(ListNode));
    head->next = NULL;
    head->data = -1;

    //将[1,10]加入链表
    int i;
    ListNode* p, * q;
    p = head;
    for (int i = 1; i <= 10; i++)
    {
        q = (ListNode*)malloc(sizeof(ListNode));
        q->data = i;
        q->next = NULL;
        p->next = q;
        p = q;
    }

    PrintList(head);           /*输出原始链表*/
    head = ReverseList(head);  /*逆序链表*/
    PrintList(head);           /*输出逆序后的链表*/
    return 0;
}

List ReverseList(List head)
{
    if (head->next == NULL || head->next->next == NULL)
    {
        return head;   /*链表为空或只有一个元素则直接返回*/
    }

    ListNode* t = NULL,
        * p = head->next,
        * q = head->next->next;
    while (q != NULL)
    {
        t = q->next;
        q->next = p;
        p = q;
        q = t;
    }

    /*此时q指向原始链表最后一个元素,也是逆转后的链表的表头元素*/
    head->next->next = NULL;  /*设置链表尾*/

    //这个地方就是一个知识点了,链表的第一个元素是元节点,即头节点的下一个,故,链表逆序时,头节点不变。
    head->next = p;           /*调整链表头*/
    return head;
}

void PrintList(List head)
{
    ListNode* p = head->next;
    //或者用个for循环,遍历
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("/n");
}

 4. Add, delete and check operations on linked lists

Indeed, these operations are relatively simple. Just give a soft question and grind it slowly.

#define _CRT_SECURE_NO_WARNINGS 1
//建立链表,查找值为x的结点并删除这个结点,x的值从键盘输入。
#include<stdio.h>
#include<stdlib.h>
//先定义结构体类型
struct node {
	int date;
	struct node* next;
};
//函数声明
struct node* create_number(int);
struct node* find(struct node *, int);
struct node* Delete(struct node *, struct node * );
void out_list(struct node*);

int main() {
	//建议还是初始化一下
	struct node* head=NULL, * p=NULL;
	int n, x;
	n = x = 0;

	printf("Create List,Enter n:");
	scanf("%d", &n);
	
	head = create_number(n);

	printf("List:");
		out_list(head);

	printf("x:");
		scanf("%d", &x);

		p = find(head, x);
		head = Delete(head, p);

		printf("Result:");
		out_list(head);

	return 0;
}

//创造结点的函数
struct node* create_number(int n) {//n代表准备创造结点的个数
	//创造结点时,至少需要三个指针变量,head固定在首结点,p和k用于创造新结点
	int i;
	struct node* head=NULL, * k=NULL, * p=NULL;

	if (n < 1) {
		return NULL;
	}
	else {
		k = (struct node*)malloc(sizeof(struct node));
		//判断是否申请成功
		if (!k)
			exit(1);
		k->date = 1;//初始化第一个数据
		//第一个结点,也是最后一个,这个操作相当于给指针域初始化
		k->next = NULL;
		head = k;

		p = k;
		for (i = 2; i <= n; i++) {
			k = (struct node*)malloc(sizeof(struct node));

			if (!k)
				exit(1);
			k->date = i;
			//初始化
			k->next = NULL;

			p->next = k;
			p = k;
		}
		
		return head;
	
	}
}
//查找函数
struct node* find(struct node* head, int x) {//头指针和待查找的元素
	//另外定义一个指针去遍历,从而保证head指针不被改变
	struct node* p = head;
	while (p && p->date != x) {
		p = p->next;
	}
	if (!p)
		return NULL;
	else
		return p;
}
//删除函数
struct node* Delete(struct node* head, struct node* p) {
	struct node* q;
	if (!p)
		return head;
	//如果p不为空,判断p指向结点的位置,从而进行删除操作
	if (p = head)
		head = head->next;
	else {
		q = head;
		while (q->next != p)
			q = q->next;
		q->next = p->next;
	}
	//别忘了释放空间
	free(p);

	return head;
}
//输出函数
void out_list(struct node* head) {
	//另外定义变量去遍历
	struct node* p;
	if (!head) {
		p = head;
		while (!p) {
			printf("%d", p->date);
			p = p->next;
		}
	}
	else
		printf("不存在\n");

	putchar('\n');
}

 In fact, I could write a lot more. After thinking about it, I decided not to write too much. I might as well write another chapter. I hope everyone can learn something from it.

Guess you like

Origin blog.csdn.net/m0_63309778/article/details/121981368