提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
这里面有10个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie树;10个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法。。
这边有个数据结构的可视化工具:https://pythontutor.com/render.html#mode=display
一、复杂度
1、时间复杂度(最好情况时间复杂度、最坏情况时间复杂度、平均时间复杂度)
2、空间复杂度
二、数据结构知识
2.1 数据结构的逻辑结构
数据结构中的逻辑结构(附上c++中的常见数据结构的逻辑结构)_数据结构的逻辑结构有哪些-CSDN博客
数据结构的逻辑结构包括四种逻辑结构
1、集合结构
2、线性结构:一一对应
3、树形结构
4、图形结构
三、数据结构分析
3.1、链表
3.1.1 静态链表
3.2.2动态链表
3.2.2.1、回顾代码
看了一个抖音,里面讲了静态链表和动态链表。之前看的静态链表讲的蛮好的。觉得还挺简单的。今天又看到了讲动态链表的。当时就有个疑问。new出来的stu_new的next指针不需要值NULL吗?一直带着这个疑问。还评论了一下,想看看别人是怎么说的。然后回工位还在想这件事情。然后就觉得写一下吧,感觉不是很难,然后就写下了下面的代码。
下面的代码基本实现了视频里的效果。后面还要跟视频的作下对比。
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
//动态指针
//①枚举类型不会写(成员不会写)
//②结构体指针写法不会写
//scanf循环
//性别
typedef enum Gender
{
male,
female,
middle
}Gend;
//结构体
typedef struct stu
{
char name[10];
int age;
Gend gender;
int score;
struct stu* next;
}Stu;
Stu stuDynamic;
int stuAdd(Stu* stu)
{
if(NULL == stu)
{
return -1;
}
Stu *stuTemp = &stuDynamic;
while(stuTemp->next)
{
stuTemp = stuTemp->next;
}
stuTemp->next = stu;
return 1;
}
void printStu(Stu* stu)
{
Stu* temp = stu->next;
printf("打印学生信息\n");
while(temp)
{
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
temp = temp->next;
}
}
int main()
{
char name[10] = {'\0'};
int age = -1;
int score;
Gend gender;
printf("输入姓名, 年龄, 性别, 分数\n");
// gets("%s", name);
// scanf("%d", &age);
// scanf("%d", &score);
// scanf("%d", &gender);
while(age != 0)
{
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu *stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
continue;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stuAdd(stu_new);
printStu(&stuDynamic);
}
return 0;
}
但是其中还是有一个问题。就是我一开始写的代码是没有将stu_new的next指针置空的。那个代码就异常了。体现在没有让我继续输入数据,然后也打印了,打印后就退出了。 然后调试的时候发现程序在print里面会异常退出。
现在来看就是因为stu_new没有置为NULL。所以我之前的考虑是对的。那么视频里的程序是怎么写的呢,需要在会看一下视频代码。下面就把之前写的代码贴出来。
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
//动态指针
//①枚举类型不会写(成员不会写)
//②结构体指针写法不会写
//scanf循环
//性别
typedef enum Gender
{
male,
female,
middle
}Gend;
//结构体
typedef struct stu
{
char name[10];
int age;
Gend gender;
int score;
struct stu* next;
}Stu;
Stu stuDynamic;
int stuAdd(Stu* stu)
{
if(NULL == stu)
{
return -1;
}
Stu *stuTemp = &stuDynamic;
while(stuTemp->next)
{
stuTemp = stuTemp->next;
}
stuTemp->next = stu;
return 1;
}
void printStu(Stu* stu)
{
Stu* temp = stu;
printf("打印学生信息\n");
while(temp)
{
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
temp = temp->next;
}
}
int main()
{
char name[10] = {'\0'};
int age = -1;
int score;
Gend gender;
printf("输入姓名, 年龄, 性别, 分数\n");
// gets("%s", name);
// scanf("%d", &age);
// scanf("%d", &score);
// scanf("%d", &gender);
while(age != 0)
{
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu *stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
continue;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stuAdd(stu_new);
printStu(&stuDynamic);
}
return 0;
}
所以当stu_new的next指针没有置为NULL的时候,程序会越界访问。导致程序崩溃结束。看起来的效果就像是程序执行完了一样。
随后还有个问题,就是全局变量stuDynamic的next指针时NULL吗?
自己写了代码验证
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
Stu stuDynamic;
int main()
{
if(NULL == stuDynamic.next)
{
printf("stuDynamic->next:%p\n", stuDynamic.next);
printf("stuDynamic->next is NULL\n");
}
}
//stuDynamic->next:00000000
//stuDynamic->next is NULL
查了一个帖子:全局变量和局部变量初始化问题_全局变量需要初始化吗-CSDN博客
里面这么表述:这里需要分清一个事实,是变量系统都会默认给初始化,只不过全局变量默认初始化为0,而局部变量被初始化为随机数,这个随机数用不了,后面会验证
3.2.2.2、阶段总结
看了视频代码,有以下几点需要说明下
①全局变量没有写成g_xxx
②视频代码重复输入是因为用了while(1)
③视频的打印也是从g_stu开始打印,所以有全是0的输出,name是空
后面可以优化代码。
下面是优化代码,下面的代码实现了修改和查询
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include "stdbool.h"
//动态指针
//①枚举类型不会写(成员不会写)
//②结构体指针写法不会写
//③scanf循环
//④scanf用法
//⑤switch-case写法
//⑥strcpy == 0,没有判断是否==0,导致直接打印0
//⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
//⑧将strcmp用错成strcpy,导致出现修改时所有数据都被改了
//性别
typedef enum Gender
{
male,
female,
middle
}Gend;
//结构体
typedef struct stu
{
char name[10];
int age;
Gend gender;
int score;
struct stu* next;
}Stu;
Stu g_stuDaynamic;
//增加
int stu_add(Stu* stu)
{
if(NULL == stu)
{
return -1;
}
Stu *stuTemp = &g_stuDaynamic;
while(stuTemp->next)
{
stuTemp = stuTemp->next;
}
stuTemp->next = stu;
return 1;
}
//查询
int stu_find(Stu* stu, char* name)
{
Stu *temp = stu;
while(NULL == temp)
{
return -1;
}
while(temp)
{
if( strcmp(temp->name, name) == 0)
{
printf("find the record");
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
return 1;
}
temp = temp->next;
}
printf("find the record Empty!");
}
//修改
int stu_modify(const Stu* stu, Stu* stu_modify)
{
if(NULL == stu)
{
return -1;
}
Stu* temp = stu;
while(temp)
{
if(strcmp(temp->name, stu_modify->name) == 0)
{
(*temp).age = stu_modify->age;
(*temp).gender = stu_modify->gender;
(*temp).score = stu_modify->score;
return 1;
}
temp = temp->next;
}
}
void printStu(Stu* stu)
{
Stu* temp = stu->next;
printf("打印学生信息\n");
while(temp)
{
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
temp = temp->next;
}
}
int action_add()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
printf("输入姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu* stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
return -1;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stu_add(stu_new);
printStu(&g_stuDaynamic);
}
int action_find(char* name)
{
stu_find(&g_stuDaynamic, name);
return 0;
}
int action_modify()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_modify_new)
{
printf("malloc fail");
return -1;
}
printf("输入修改的姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
memcpy(stu_modify_new->name, name, 10);
stu_modify_new->age = age;
stu_modify_new->score = score;
stu_modify_new->gender = gender;
stu_modify(&g_stuDaynamic, stu_modify_new);
free(stu_modify_new);
printStu(&g_stuDaynamic);
return 1;
}
int main()
{
bool m_flag = true;
if(NULL == g_stuDaynamic.next)
{
printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
printf("g_stuDaynamic->next is NULL\n");
}
while(m_flag)
{
printf("选择操作(A:增加、D:删除、C:更改、F:查找、其他:退出):\n");
char action[2];
scanf("%s", action);
switch(action[0])
{
case 'A':
{
action_add();
break;
}
case 'F':
{
printf("输入查询的姓名:\n");
char name[100];
scanf("%s", name);
action_find(name);
break;
}
case 'C':
{
action_modify();
break;
}
default:
{
m_flag = false;
break;
}
}
}
return 0;
}
这个代码还在编译时出现一个警告:
warning:initialization discards ‘const’ qualifier from pointer target type
那么就存在一个问题,就是我不想函数更改g_stuDaynamic变量。所以用const限定为只读变量。但是在函数中还要遍历链表,temp又不能增加const修饰。但是赋值时就出现这个告警。下次看看教科书别人是怎么处理的。
还有一个删除的功能没有实现,这个会涉及到链表头、尾的问题,先阶段性提交一次。
下面是增加删除的代码
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include "stdbool.h"
#include "ctype.h"
//动态指针
//①枚举类型不会写(成员不会写)
//②结构体指针写法不会写
//③scanf循环
//④scanf用法
//⑤switch-case写法
//⑥strcpy == 0,没有判断是否==0,导致直接打印0
//⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
//性别
typedef enum Gender
{
male,
female,
middle
}Gend;
//结构体
typedef struct stu
{
char name[10];
int age;
Gend gender;
int score;
struct stu* next;
}Stu;
Stu g_stuDaynamic;
int stu_add(Stu* stu)
{
if(NULL == stu)
{
return -1;
}
Stu *stuTemp = &g_stuDaynamic;
while(stuTemp->next)
{
stuTemp = stuTemp->next;
}
stuTemp->next = stu;
return 1;
}
int stu_find(Stu* stu, char* name)
{
Stu *temp = stu;
while(NULL == temp)
{
return -1;
}
while(temp)
{
if( strcmp(temp->name, name) == 0)
{
printf("find the record");
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
return 1;
}
temp = temp->next;
}
printf("find the record Empty!");
}
int stu_modify(const Stu* stu, Stu* stu_modify)
{
if(NULL == stu)
{
return -1;
}
Stu* temp = stu;
while(temp)
{
if(strcmp(temp->name, stu_modify->name) == 0)
{
(*temp).age = stu_modify->age;
(*temp).gender = stu_modify->gender;
(*temp).score = stu_modify->score;
return 1;
}
temp = temp->next;
}
}
//删除
int stu_delete(Stu* stu, char* name)
{
if (NULL == stu)
{
return -1;
}
Stu* temp = stu;
while (temp)
{
if(NULL != temp->next && strcmp(temp->next->name, name) == 0)
{
//目标节点在重点
Stu* traget = temp->next;
Stu* tragetNext = traget->next;
temp->next = tragetNext;
free(traget);
printf("已找到记录并删除\n");
return 1;
}
temp = temp->next;
}
printf("未找到可删除记录\n");
return 0;
}
void printStu(Stu* stu)
{
Stu* temp = stu->next;
printf("打印学生信息\n");
while(temp)
{
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
temp = temp->next;
}
}
int action_add()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
printf("输入姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu* stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
return -1;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stu_add(stu_new);
printStu(&g_stuDaynamic);
}
int action_find(char* name)
{
stu_find(&g_stuDaynamic, name);
return 0;
}
int action_modify()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_modify_new)
{
printf("malloc fail");
return -1;
}
printf("输入修改的姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
memcpy(stu_modify_new->name, name, 10);
stu_modify_new->age = age;
stu_modify_new->score = score;
stu_modify_new->gender = gender;
stu_modify(&g_stuDaynamic, stu_modify_new);
free(stu_modify_new);
printStu(&g_stuDaynamic);
return 1;
}
int action_delete()
{
printf("输入需要删除的记录:\n");
char* name[100];
scanf("%s", name);
stu_delete(&g_stuDaynamic, name);
printStu(&g_stuDaynamic);
return 0;
}
bool isTargetAlpha(char c)
{
if(toupper(c) == 'A' || toupper(c) == 'D' || toupper(c) == 'C' || toupper(c) == 'F' || toupper(c) == 'Q')
{
return true;
}
return false;
}
int main()
{
bool m_flag = true;
if(NULL == g_stuDaynamic.next)
{
printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
printf("g_stuDaynamic->next is NULL\n");
}
while(m_flag)
{
printf("选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):\n");
char action[2];
scanf("%s", action);
if(!isTargetAlpha(action[0]))
{
continue;
}
switch(toupper(action[0]))
{
case 'A':
{
action_add();
break;
}
case 'F':
{
printf("输入查询的姓名:\n");
char name[100];
scanf("%s", name);
action_find(name);
break;
}
case 'C':
{
action_modify();
break;
}
case 'D':
{
action_delete();
break;
}
case 'Q':
{
m_flag = false;
printf("退出\n");
break;
}
default:
{
printf("操作有误,请重新输入\n");
break;
}
}
}
return 0;
}
感觉比想象的简单,没有之前那么复杂啊。
反正自验证实现了功能,目前还遗留的就是输错信息,程序直接退出了。需要优化下。
另外印象中删除好像还挺复杂呢?
2024年1月11日20:01:11
下面就是所谓的复杂的。现在写的是插入。好像删除也不复杂,之前印象中复杂的只有插入。不然链表也太难了吧。同时参考C和指针的书籍。其实这个代码一直你有一个问题,就是我在函数里把g_stuDaynamic写死了,不能处理其他的链表,没有通用性。这个也是看C和指针的书才发现的啊!!
#include "test.h"
//动态指针
//①枚举类型不会写(成员不会写)
//②结构体指针写法不会写
//③scanf循环
//④scanf用法
//⑤switch-case写法
//⑥strcpy == 0,没有判断是否==0,导致直接打印0
//⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
//性别
typedef enum Gender
{
male,
female,
middle
}Gend;
//结构体
typedef struct stu
{
char name[10];
int age;
Gend gender;
int score;
struct stu* next;
}Stu;
Stu g_stuDaynamic;
int stu_add(Stu* stu)
{
if(NULL == stu)
{
return -1;
}
Stu *stuTemp = &g_stuDaynamic;
while(stuTemp->next)
{
stuTemp = stuTemp->next;
}
stuTemp->next = stu;
return 1;
}
//插入数据有序排列
void stu_insert(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = &g_stuDaynamic;
current = g_stuDaynamic.next;
while(current->next != NULL && current->score <= new->score )
{
previous = current;
current = current->next;
}
if(current->next == NULL)
{
current->next = new;
}
else
{
previous->next = new;
new->next = current;
}
}
int stu_find(Stu* stu, char* name)
{
Stu *temp = stu;
while(NULL == temp)
{
return -1;
}
while(temp)
{
if( strcmp(temp->name, name) == 0)
{
printf("find the record");
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
return 1;
}
temp = temp->next;
}
printf("find the record Empty!");
}
int stu_modify(const Stu* stu, Stu* stu_modify)
{
if(NULL == stu)
{
return -1;
}
Stu* temp = stu;
while(temp)
{
if(strcmp(temp->name, stu_modify->name) == 0)
{
(*temp).age = stu_modify->age;
(*temp).gender = stu_modify->gender;
(*temp).score = stu_modify->score;
return 1;
}
temp = temp->next;
}
}
//删除
int stu_delete(Stu* stu, char* name)
{
if (NULL == stu)
{
return -1;
}
Stu* temp = stu;
while (temp)
{
if(NULL != temp->next && strcmp(temp->next->name, name) == 0)
{
//目标节点在重点
Stu* traget = temp->next;
Stu* tragetNext = traget->next;
temp->next = tragetNext;
free(traget);
printf("已找到记录并删除\n");
return 1;
}
temp = temp->next;
}
printf("未找到可删除记录\n");
return 0;
}
void printStu(Stu* stu)
{
Stu* temp = stu->next;
printf("打印学生信息\n");
while(temp)
{
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
temp = temp->next;
}
}
int action_add()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
printf("输入姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu* stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
return -1;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stu_add(stu_new);
printStu(&g_stuDaynamic);
}
//插入数据进行有序排列
int action_insert()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
printf("输入姓名、年龄、性别、分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu* stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
return -1;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stu_insert(stu_new);
printStu(&g_stuDaynamic);
}
int action_find(char* name)
{
stu_find(&g_stuDaynamic, name);
return 0;
}
int action_modify()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_modify_new)
{
printf("malloc fail");
return -1;
}
printf("输入修改的姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
memcpy(stu_modify_new->name, name, 10);
stu_modify_new->age = age;
stu_modify_new->score = score;
stu_modify_new->gender = gender;
stu_modify(&g_stuDaynamic, stu_modify_new);
free(stu_modify_new);
printStu(&g_stuDaynamic);
return 1;
}
int action_delete()
{
printf("输入需要删除的记录:\n");
char* name[100];
scanf("%s", name);
stu_delete(&g_stuDaynamic, name);
printStu(&g_stuDaynamic);
return 0;
}
bool isTargetAlpha(char c)
{
if(toupper(c) == 'A' || toupper(c) == 'D' || toupper(c) == 'C' || toupper(c) == 'F' || toupper(c) == 'Q' || toupper(c) == 'I')
{
return true;
}
return false;
}
//int i = 0;
//
//void add() const
//{
// i++;
//}
int list_func()
{
// add();
bool m_flag = true;
if(NULL == g_stuDaynamic.next)
{
printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
printf("g_stuDaynamic->next is NULL\n");
}
while(m_flag)
{
printf("选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):\n");
// printf("选择操作(A:增加、D:删除、C、更改:\n");
// printf("hello");
char action[2];
scanf("%s", action);
if(!isTargetAlpha(action[0]))
{
continue;
}
switch(toupper(action[0]))
{
case 'A':
{
action_add();
break;
}
case 'F':
{
printf("输入查询的姓名:\n");
char name[100];
scanf("%s", name);
action_find(name);
break;
}
case 'C':
{
action_modify();
break;
}
case 'D':
{
action_delete();
break;
}
case 'Q':
{
m_flag = false;
printf("退出\n");
break;
}
//插入数据有序排列
case 'I':
{
action_insert();
break;
}
default:
{
printf("操作有误,请重新输入\n");
break;
}
}
}
return 0;
}
//g_stuDaynamic->next:00000000
//g_stuDaynamic->next is NULL
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//A
//输入姓名, 年龄, 性别, 分数
//zhangs 7 0 77
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//A
//输入姓名, 年龄, 性别, 分数
//lilu 8 1 88
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//A
//输入姓名, 年龄, 性别, 分数
//wangmei 9 1 99
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//姓名:wangmei, 年龄:9, 性别:1, 成绩:99
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//I
//输入姓名、年龄、性别、分数
//xux 6 0 90
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//姓名:wangmei, 年龄:9, 性别:1, 成绩:99
//姓名:xux, 年龄:6, 性别:0, 成绩:90
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//I
//输入姓名、年龄、性别、分数
//xiaom 6 1 80
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:xiaom, 年龄:6, 性别:1, 成绩:80
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//姓名:wangmei, 年龄:9, 性别:1, 成绩:99
//姓名:xux, 年龄:6, 性别:0, 成绩:90
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//I
//输入姓名、年龄、性别、分数
//xiaoh 9 0 83
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:xiaom, 年龄:6, 性别:1, 成绩:80
//姓名:xiaoh, 年龄:9, 性别:0, 成绩:83
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//姓名:wangmei, 年龄:9, 性别:1, 成绩:99
//姓名:xux, 年龄:6, 性别:0, 成绩:90
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
上面的代码插入尾部的时候会异常,下面的可以正常插入尾部
#include "test.h"
//动态指针
//①枚举类型不会写(成员不会写)
//②结构体指针写法不会写
//③scanf循环
//④scanf用法
//⑤switch-case写法
//⑥strcpy == 0,没有判断是否==0,导致直接打印0
//⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
//性别
typedef enum Gender
{
male,
female,
middle
}Gend;
//结构体
typedef struct stu
{
char name[10];
int age;
Gend gender;
int score;
struct stu* next;
}Stu;
Stu g_stuDaynamic;
int stu_add(Stu* stu)
{
if(NULL == stu)
{
return -1;
}
Stu *stuTemp = &g_stuDaynamic;
while(stuTemp->next)
{
stuTemp = stuTemp->next;
}
stuTemp->next = stu;
return 1;
}
//插入数据有序排列
//存在最后一个节点判断异常
void stu_insert1(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = &g_stuDaynamic;
current = g_stuDaynamic.next;
while(current->next != NULL && current->score <= new->score )
{
previous = current;
current = current->next;
}
if(current->next == NULL)
{
current->next = new;
}
else
{
previous->next = new;
new->next = current;
}
}
//处理有些复杂
void stu_insert2(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = &g_stuDaynamic;
current = g_stuDaynamic.next;
while(current->score <= new->score && current->next != NULL)
{
previous = current;
current = current->next;
}
//这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
if(current->score > new->score)
{
previous->next = new;
new->next = current;
}
else
{
current->next = new;
}
}
//C和指针照着写
void stu_insert3(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = NULL;
current = &g_stuDaynamic;
while(current->score <= new->score && current != NULL)
{
previous = current;
current = current->next;
}
//这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
if(current->score > new->score)
{
previous->next = new;
new->next = current;
}
else
{
current->next = new;
}
}
//C和指针照着写,程序死机
void stu_insert4(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = NULL;
current = &g_stuDaynamic;
while( current->score <= new->score && current != NULL) //这边内存泄漏,访问其他内存,没有先判断current是否为空
{
previous = current;
current = current->next;
}
//这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
if(current->score > new->score)
{
previous->next = new;
new->next = current;
}
else
{
previous->next = new;
}
}
//C和指针照着写,程序死机
void stu_insert5(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = NULL;
current = &g_stuDaynamic;
while( current->score <= new->score && current != NULL) //这边内存泄漏,访问其他内存,没有先判断current是否为空
{
previous = current;
current = current->next;
}
//这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
if(current->score > new->score) //这边内存泄露,current=NULL时,内存泄漏
{
previous->next = new;
new->next = current;
}
else
{
previous->next = new;
}
}
void stu_insert(Stu* new)
{
Stu* previous;
Stu* current;
Stu* next;
previous = NULL;
current = &g_stuDaynamic;
while(current != NULL && current->score <= new->score)
{
previous = current;
current = current->next;
}
//这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
if(current == NULL)
{
previous->next = new;
}
else
{
previous->next = new;
new->next = current;
}
}
int stu_find(Stu* stu, char* name)
{
Stu *temp = stu;
while(NULL == temp)
{
return -1;
}
while(temp)
{
if( strcmp(temp->name, name) == 0)
{
printf("find the record");
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
return 1;
}
temp = temp->next;
}
printf("find the record Empty!");
}
int stu_modify(const Stu* stu, Stu* stu_modify)
{
if(NULL == stu)
{
return -1;
}
Stu* temp = stu;
while(temp)
{
if(strcmp(temp->name, stu_modify->name) == 0)
{
(*temp).age = stu_modify->age;
(*temp).gender = stu_modify->gender;
(*temp).score = stu_modify->score;
return 1;
}
temp = temp->next;
}
}
//删除
int stu_delete(Stu* stu, char* name)
{
if (NULL == stu)
{
return -1;
}
Stu* temp = stu;
while (temp)
{
if(NULL != temp->next && strcmp(temp->next->name, name) == 0)
{
//目标节点在重点
Stu* traget = temp->next;
Stu* tragetNext = traget->next;
temp->next = tragetNext;
free(traget);
printf("已找到记录并删除\n");
return 1;
}
temp = temp->next;
}
printf("未找到可删除记录\n");
return 0;
}
void printStu(Stu* stu)
{
Stu* temp = stu->next;
printf("打印学生信息\n");
while(temp)
{
printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
temp = temp->next;
}
}
int action_add()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
printf("输入姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu* stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
return -1;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stu_add(stu_new);
printStu(&g_stuDaynamic);
}
//插入数据进行有序排列
int action_insert()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
printf("输入姓名、年龄、性别、分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
Stu* stu_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_new)
{
printf("malloc fail");
return -1;
}
memcpy(stu_new->name, name, 10);
stu_new->age = age;
stu_new->score = score;
stu_new->gender = gender;
stu_new->next = NULL;
stu_insert(stu_new);
printStu(&g_stuDaynamic);
}
int action_find(char* name)
{
stu_find(&g_stuDaynamic, name);
return 0;
}
int action_modify()
{
char name[10] = {'\0'};
int age;
int score;
Gend gender;
Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
if(NULL == stu_modify_new)
{
printf("malloc fail");
return -1;
}
printf("输入修改的姓名, 年龄, 性别, 分数\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
memcpy(stu_modify_new->name, name, 10);
stu_modify_new->age = age;
stu_modify_new->score = score;
stu_modify_new->gender = gender;
stu_modify(&g_stuDaynamic, stu_modify_new);
free(stu_modify_new);
printStu(&g_stuDaynamic);
return 1;
}
int action_delete()
{
printf("输入需要删除的记录:\n");
char* name[100];
scanf("%s", name);
stu_delete(&g_stuDaynamic, name);
printStu(&g_stuDaynamic);
return 0;
}
bool isTargetAlpha(char c)
{
if(toupper(c) == 'A' || toupper(c) == 'D' || toupper(c) == 'C' || toupper(c) == 'F' || toupper(c) == 'Q' || toupper(c) == 'I')
{
return true;
}
return false;
}
int list_func()
{
bool m_flag = true;
if(NULL == g_stuDaynamic.next)
{
printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
printf("g_stuDaynamic->next is NULL\n");
}
while(m_flag)
{
printf("选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):\n");
char action[2];
scanf("%s", action);
if(!isTargetAlpha(action[0]))
{
continue;
}
switch(toupper(action[0]))
{
case 'A':
{
action_add();
break;
}
case 'F':
{
printf("输入查询的姓名:\n");
char name[100];
scanf("%s", name);
action_find(name);
break;
}
case 'C':
{
action_modify();
break;
}
case 'D':
{
action_delete();
break;
}
case 'Q':
{
m_flag = false;
printf("退出\n");
break;
}
//插入数据有序排列
case 'I':
{
action_insert();
break;
}
default:
{
printf("操作有误,请重新输入\n");
break;
}
}
}
return 0;
}
//g_stuDaynamic->next:00000000
//g_stuDaynamic->next is NULL
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//A
//输入姓名, 年龄, 性别, 分数
//zhangs 7 0 77
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//A
//输入姓名, 年龄, 性别, 分数
//lilu 8 1 88
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//A
//输入姓名, 年龄, 性别, 分数
//wangmei 9 0 99
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//姓名:wangmei, 年龄:9, 性别:0, 成绩:99
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
//I
//输入姓名、年龄、性别、分数
//lili 5 1 101
//打印学生信息
//姓名:zhangs, 年龄:7, 性别:0, 成绩:77
//姓名:lilu, 年龄:8, 性别:1, 成绩:88
//姓名:wangmei, 年龄:9, 性别:0, 成绩:99
//姓名:lili, 年龄:5, 性别:1, 成绩:101
//选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
几经波折啊!
3.2.2.2.2 阶段2
现在可以实现数据的增加、插入、删除、查找、修改了。但是离C和指针还有一些 差别或者差距。
差距在于我这个目前使用的是一个全局链表变量。所以所有的程序只能针对于这个链表运行。因为函数中写死了链表变量。
所以这是我又想到一个点。就是怎么叫解耦或者什么叫解耦。那就是函数中不能出现全局变量或者写死某个值或变量。
我的这段代码就是没有解耦,比如stu_insert函数中就出现这样的代码
previous = &g_stuDaynamic;
current = g_stuDaynamic.next;
高度耦合。
所以后面的代码修改方向就是需要解耦。
3.2.2.3 解耦代码
2024年1月16日 11:16:16
下面是解耦的代码,
搞的头炸啊!
//lianbiao.c文件
#include "lianbiao.h"
void func()
{
printf("hello\n");
}
bool isTargetCharacter(char* choose)
{
if(choose[0] == 'A' || choose[0] == 'I' || choose[0] == 'D' || choose[0] == 'M' || choose[0] == 'F')
{
return true;
}
return false;
}
//这边printf也是有问题的,我也是把跟指针当做value=0在用,从第二个节点开始打印。同理,我的add函数也是等于是从value=0结构后面加的
void print_lianbiao(lianbiao* stu)
{
lianbiao* root = stu;
lianbiao* current = root->next;
while(current != NULL)
{
printf("姓名:%s,年龄:%d,性别:%d,成绩:%d\n", current->name, current->age, current->gender, current->score);
current = current->next;
}
}
int stu_add1(lianbiao* stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = stu;
lianbiao** current = &previous->next;
while(*current != NULL)
{
*current = (*current)->next;
}
*current = new_stu;
return 1;
}
int stu_add2(lianbiao* stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = stu;
lianbiao* current = previous->next;
while(current != NULL)
{
current = current->next;
}
lianbiao** p = ¤t;
*p = new_stu;
return 1;
}
//吊毛,槽,这样写竟然就可以了,妈的,自己捣鼓一晚上都没弄好。看了书就好了
int stu_add(lianbiao* stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = stu; //stu是二级指针,解引用一次,里面的成员都可以被成功赋值
lianbiao* current = previous->next; //现在复盘,大概是previous->next可以被赋值。但是现在的操作是previous->next赋值给previous,再去更改previous的值就更改不了next的值
while(current != NULL)
{
previous = current;
current = current->next;
}
previous->next = new_stu;
return 1;
}
int action_add(lianbiao* stu_lianbiao)
{
char name[10];
int age;
int gender;
int score;
//lianbiao stu; //这边好像不能写局部变量,栈上申请内存,感觉每次的地址是一样的额
printf("输入需要增加(add)的数据, age=0时退出add操作:\n");
while(1)
{
printf("输入姓名、年龄、性别、成绩\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
if(age == 0)
{
break;
}
lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
strcpy(stu->name, name);
stu->age = age;
stu->gender = gender;
stu->score = score;
stu->next = NULL; //忘了写
if(stu_add(stu_lianbiao, stu))
{
printf("添加成功\n");
}
}
print_lianbiao(stu_lianbiao);
printf("结束添加add操作\n");
}
//这个没有传入根指针的二级指针,竟然也成功了
//我是把根指针当做一个value=0的节点在用了,所以都是在后面add
int stu_insert(lianbiao* stu, lianbiao* new_stu)
{
if(stu == NULL)
{
return 0;
}
lianbiao* previous = NULL;
lianbiao* current = stu;
while(current != NULL && current->score < new_stu->score) //这个地方关于current->score < new_stu->score我是存在疑问的。但是实际调试的时候score的值是0.只能理解为全局变量会被初始化为0
{
previous = current;
current = current->next;
}
if(current == NULL) //这边我还是没有真正的理解书中表达的意思。这边应该写成previous == NULL
{
previous->next = new_stu;
}
else
{
previous->next = new_stu;
new_stu->next = current;
}
return 1;
}
void action_insert(lianbiao* stu_lianbiao)
{
char name[10];
int age;
int gender;
int score;
printf("输入需要插入(insert)的数据, age=0时退出insert操作:\n");
while(1)
{
printf("输入姓名、年龄、性别、成绩\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
if(age == 0)
{
break;
}
lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
strcpy(stu->name, name);
stu->age = age;
stu->gender = gender;
stu->score = score;
stu->next = NULL; //忘了写
if(stu_insert(stu_lianbiao, stu))
{
printf("添加成功\n");
print_lianbiao(stu_lianbiao);
}
}
printf("结束添加add操作\n");
}
void stu_list_func(lianbiao* stu_lianbiao)
{
bool flag = true;
char choose[10];
printf("欢迎进入学生信息管理系统\n");
while(flag)
{
printf("选择操作A:增加、I:插入、D:删除、M:修改、F:查找\n");
scanf("%s", choose);
if(!isTargetCharacter(choose))
{
continue;
}
switch(choose[0])
{
case 'A':
{
action_add(stu_lianbiao);
break;
}
case 'I':
{
action_insert(stu_lianbiao);
break;
}
case 'D':
{
break;
}
case 'M':
{
break;
}
case 'F':
{
break;
}
case 'Q':
{
flag = false;
break;
}
default:
{
break;
}
}
}
}
//D:\APP\codeBlock\ADTlianbiao\main.c
//12, 7
//Hello world!
//欢迎进入学生信息管理系统
//选择操作A:增加、I:插入、D:删除、M:修改、F:查找
//A
//输入需要增加(add)的数据, age=0时退出add操作:
//输入姓名、年龄、性别、成绩
//zhangs 7 0 77
//添加成功
//输入姓名、年龄、性别、成绩
//lilu 8 1 88
//添加成功
//输入姓名、年龄、性别、成绩
//wangmei 9 0 99
//添加成功
//输入姓名、年龄、性别、成绩
//bv 0 0 0
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//结束添加add操作
//选择操作A:增加、I:插入、D:删除、M:修改、F:查找
//I
//输入需要插入(insert)的数据, age=0时退出insert操作:
//输入姓名、年龄、性别、成绩
//xiaoming 6 0 66
//添加成功
//姓名:xiaoming,年龄:6,性别:0,成绩:66
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//输入姓名、年龄、性别、成绩
//xiaohong 9 1 101
//添加成功
//姓名:xiaoming,年龄:6,性别:0,成绩:66
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//姓名:xiaohong,年龄:9,性别:1,成绩:101
//输入姓名、年龄、性别、成绩
//xc 0 0 0
//结束添加add操作
//lianbiao.h
#ifndef LIANBIAO_H
#define LIANBIAO_H
#include "stdio.h"
#include <stdbool.h>
#include <string.h>
typedef struct Lianbiao
{
char name[10];
int age;
int gender;
int score;
struct Lianbiao* next;
}lianbiao;
typedef struct TEST
{
int a;
int* p;
}Test;
void func();
void stu_list_func(lianbiao* stu_lianbiao);
#endif // LIANBIAO_H
//main.c
#include <stdio.h>
#include <stdlib.h>
#include "lianbiao.h"
lianbiao g_stu_lianbiao;
int testFun(Test* test)
{
test->a = 12;
int* b = (int*)malloc(sizeof(int));
*b = 7;
int* p = test->p;
p = b; //这样写不能正常赋值
int **q = &(test->p); //不需要加括号,->运算符优先级高于&和*
*q = b; //这样写可以正常赋值
}
int main()
{
printf("%s\n", __FILE__);
Test test;
testFun(&test);
printf("%d, %d", test.a, *test.p);
printf("Hello world!\n");
int *p = &g_stu_lianbiao;
stu_list_func(&g_stu_lianbiao);
return 0;
}
看打印记录感觉代码正常运行了。实际上上面的代码还是有问题,那就是我一直都其实没有理解根节点指针(rootp)是什么意思。在上面的diamante中,我其实一直都是这么用的。那就是将根节点指针指向的value=0的节点当做跟指针在用。(实际上g_stu_lianbiao的初始化就是0)。
这也是我为什么打印的时候会跳过一个节点,写的奇奇怪怪。
lianbiao* root = stu;
lianbiao* current = root->next;
上面显示我把root->next当做current。root->score所在的节点被我跳过了。
3.2.2.4 解耦阶段二
//lianbiao.h
#ifndef LIANBIAO_H
#define LIANBIAO_H
#include "stdio.h"
#include <stdbool.h>
#include <string.h>
typedef struct Lianbiao
{
char name[10];
int age;
int gender;
int score;
struct Lianbiao* next;
}lianbiao;
typedef struct TEST
{
int a;
int* p;
}Test;
void func();
void stu_list_func(lianbiao** stu_lianbiao);
#endif // LIANBIAO_H
//lianbiao.c
#include "lianbiao.h"
void func()
{
printf("hello\n");
}
bool isTargetCharacter(char* choose)
{
if(choose[0] == 'A' || choose[0] == 'I' || choose[0] == 'D' || choose[0] == 'M' || choose[0] == 'F')
{
return true;
}
return false;
}
//这边printf也是有问题的,我也是把跟指针当做value=0在用,从第二个节点开始打印。同理,我的add函数也是等于是从value=0结构后面加的
void print_lianbiao1(lianbiao* stu)
{
lianbiao* root = stu;
lianbiao* current = root->next;
while(current != NULL)
{
printf("姓名:%s,年龄:%d,性别:%d,成绩:%d\n", current->name, current->age, current->gender, current->score);
current = current->next;
}
}
void print_lianbiao(lianbiao** stu)
{
lianbiao* current = *stu;
while(current != NULL)
{
printf("姓名:%s,年龄:%d,性别:%d,成绩:%d\n", current->name, current->age, current->gender, current->score);
current = current->next;
}
}
int stu_add1(lianbiao* stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = stu;
lianbiao** current = &previous->next;
while(*current != NULL)
{
*current = (*current)->next;
}
*current = new_stu;
return 1;
}
int stu_add2(lianbiao* stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = stu;
lianbiao* current = previous->next;
while(current != NULL)
{
current = current->next;
}
lianbiao** p = ¤t;
*p = new_stu;
return 1;
}
//吊毛,槽,这样写竟然就可以了,妈的,自己捣鼓一晚上都没弄好。看了书就好了
int stu_add3(lianbiao* stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = stu; //stu是二级指针,解引用一次,里面的成员都可以被成功赋值
lianbiao* current = previous->next; //现在复盘,大概是previous->next可以被赋值。但是现在的操作是previous->next赋值给previous,再去更改previous的值就更改不了next的值
while(current != NULL)
{
previous = current;
current = current->next;
}
previous->next = new_stu;
return 1;
}
int stu_add(lianbiao** stu, lianbiao* new_stu)
{
while(stu == NULL)
{
return 0;
}
lianbiao* previous = NULL; //stu是二级指针,解引用一次,里面的成员都可以被成功赋值
lianbiao* current = *stu; //现在复盘,大概是previous->next可以被赋值。但是现在的操作是previous->next赋值给previous,再去更改previous的值就更改不了next的值
while(current != NULL)
{
previous = current;
current = current->next;
}
if(previous == NULL)
{
*stu = new_stu;
}
else
{
previous->next = new_stu;
new_stu->next = current;
}
return 1;
}
int action_add(lianbiao** stu_lianbiao)
{
char name[10];
int age;
int gender;
int score;
//lianbiao stu; //这边好像不能写局部变量,栈上申请内存,感觉每次的地址是一样的额
printf("输入需要增加(add)的数据, age=0时退出add操作:\n");
while(1)
{
printf("输入姓名、年龄、性别、成绩\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
if(age == 0)
{
break;
}
lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
strcpy(stu->name, name);
stu->age = age;
stu->gender = gender;
stu->score = score;
stu->next = NULL; //忘了写
if(stu_add(stu_lianbiao, stu))
{
printf("添加成功\n");
print_lianbiao(stu_lianbiao);
}
}
printf("结束添加add操作\n");
}
//这个没有传入根指针的二级指针,竟然也成功了
//我是把根指针当做一个value=0的节点在用了,所以都是在后面add
int stu_insert1(lianbiao* stu, lianbiao* new_stu)
{
if(stu == NULL)
{
return 0;
}
lianbiao* previous = NULL;
lianbiao* current = stu;
while(current != NULL && current->score < new_stu->score) //这个地方关于current->score < new_stu->score我是存在疑问的。但是实际调试的时候score的值是0.只能理解为全局变量会被初始化为0
{
previous = current;
current = current->next;
}
if(current == NULL) //这边我还是没有真正的理解书中表达的意思。这边应该写成previous == NULL
{
previous->next = new_stu;
}
else
{
previous->next = new_stu;
new_stu->next = current;
}
return 1;
}
int stu_insert(lianbiao** stu, lianbiao* new_stu)
{
if(stu == NULL)
{
return 0;
}
lianbiao* previous = NULL;
lianbiao* current = *stu;
while(current != NULL && current->score < new_stu->score) //这个地方关于current->score < new_stu->score我是存在疑问的。但是实际调试的时候score的值是0.只能理解为全局变量会被初始化为0
{
previous = current;
current = current->next;
}
if(previous == NULL) //这边我还是没有真正的理解书中表达的意思。这边应该写成previous == NULL
{
*stu = new_stu;
}
else
{
previous->next = new_stu;
}
new_stu->next = current; //靠这个一直没在意,调试的时候才发现
return 1;
}
void action_insert(lianbiao* stu_lianbiao)
{
char name[10];
int age;
int gender;
int score;
printf("输入需要插入(insert)的数据, age=0时退出insert操作:\n");
while(1)
{
printf("输入姓名、年龄、性别、成绩\n");
scanf("%s %d %d %d", name, &age, &gender, &score);
if(age == 0)
{
break;
}
lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
strcpy(stu->name, name);
stu->age = age;
stu->gender = gender;
stu->score = score;
stu->next = NULL; //忘了写
if(stu_insert(stu_lianbiao, stu))
{
printf("添加成功\n");
print_lianbiao(stu_lianbiao);
}
}
printf("结束添加add操作\n");
}
void stu_list_func(lianbiao** stu_lianbiao)
{
bool flag = true;
char choose[10];
printf("欢迎进入学生信息管理系统\n");
while(flag)
{
printf("选择操作A:增加、I:插入、D:删除、M:修改、F:查找\n");
scanf("%s", choose);
if(!isTargetCharacter(choose))
{
continue;
}
switch(choose[0])
{
case 'A':
{
action_add(stu_lianbiao);
break;
}
case 'I':
{
action_insert(stu_lianbiao);
break;
}
case 'D':
{
break;
}
case 'M':
{
break;
}
case 'F':
{
break;
}
case 'Q':
{
flag = false;
break;
}
default:
{
break;
}
}
}
}
//D:\APP\codeBlock\ADTlianbiao\main.c
//12, 7
//Hello world!
//欢迎进入学生信息管理系统
//选择操作A:增加、I:插入、D:删除、M:修改、F:查找
//A
//输入需要增加(add)的数据, age=0时退出add操作:
//输入姓名、年龄、性别、成绩
//zhangs 7 0 77
//添加成功
//姓名:zhangs,年龄:7,性别:0,成绩:77
//输入姓名、年龄、性别、成绩
//lilu 8 1 88
//添加成功
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//输入姓名、年龄、性别、成绩
//wangmei 9 0 99
//添加成功
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//输入姓名、年龄、性别、成绩
//vc 0 0 0
//结束添加add操作
//选择操作A:增加、I:插入、D:删除、M:修改、F:查找
//I
//输入需要插入(insert)的数据, age=0时退出insert操作:
//输入姓名、年龄、性别、成绩
//xiaoming 6 0 66
//添加成功
//姓名:xiaoming,年龄:6,性别:0,成绩:66
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//输入姓名、年龄、性别、成绩
//hanxue 9 1 102
//添加成功
//姓名:xiaoming,年龄:6,性别:0,成绩:66
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//姓名:hanxue,年龄:9,性别:1,成绩:102
//输入姓名、年龄、性别、成绩
//wuhu 7 0 82
//添加成功
//姓名:xiaoming,年龄:6,性别:0,成绩:66
//姓名:zhangs,年龄:7,性别:0,成绩:77
//姓名:wuhu,年龄:7,性别:0,成绩:82
//姓名:lilu,年龄:8,性别:1,成绩:88
//姓名:wangmei,年龄:9,性别:0,成绩:99
//姓名:hanxue,年龄:9,性别:1,成绩:102
//输入姓名、年龄、性别、成绩
//vc 0 0 0
//结束添加add操作
//选择操作A:增加、I:插入、D:删除、M:修改、F:查找
//main.c
#include <stdio.h>
#include <stdlib.h>
#include "lianbiao.h"
lianbiao* g_stu_lianbiao = NULL;
int testFun(Test* test)
{
test->a = 12;
int* b = (int*)malloc(sizeof(int));
*b = 7;
int* p = test->p;
p = b; //这样写不能正常赋值
// int **q = &(test->p); //不需要加括号,->运算符优先级高于&和*
// *q = b; //这样写可以正常赋值
test->p = b; //离谱的是,这样也可以更改结构体中指针的值
}
//这里的问题是test是个指针,指向一块内存。test指针指向的内存中的数据可以更改。因为确实是对真实内存进行修改
//链表中的问题是,更改根节点的值。指针的值是值传递,无法修改。所以要传递地址的地址
int main()
{
printf("%s\n", __FILE__);
Test test;
testFun(&test);
printf("%d, %d\n", test.a, *test.p);
printf("Hello world!\n");
int *p = &g_stu_lianbiao;
stu_list_func(&g_stu_lianbiao);
return 0;
}
上面的代码就实现了C和指针里面的链表。
2024年1月17日09:36:36
今天还回顾了一下链表,理了一下,下面的是画的图
所以对malloc也理解了一些。就是malloc申请了一块内存空间。用一个指针p指向那块内存。
四、编译报错处理
4.1 报错1
implicit declaration of function 'toupper' [-Wimplicit-function-declaration]
加上头文件"ctype.h"就不报错了。但是按理没有加头文件程序不能执行啊。但是没有头文件程序也是正常执行了。
翻译:函数'toupper'的隐式声明
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。