商品管理系统&链表实现&二级指针&
建议!:这是我从Notion直接复制过来的,个人精力有限,而且是第一次使用博客园,不想调格式了.....,这里的就凑合看吧,如果可以的话我建议转到我的Notion笔记,链接是https://billowy-pigment-2ec.notion.site/8cc78481ec66478e90cad44e2bc05db9?pvs=4
关于写这篇文章的原因
- 一方面是为了记录我第一次写的大程序
- 另一方面是因为在写这个程序中遇到了许多麻烦,想要记录下来希望能帮助到其他学习c的人(特别是链表的实现,cao)
修改日志
-
10.2X 开始写屎山,喜欢往NULL还有不可写入的指针里面写东西,bug。主打一个叛逆
-
10.26 修好上面的bug,但是屎山
-
11.2 终于学到了结构体,然后就会用结构体编写屎山了,不过好歹可以运行了 。喜欢用malloc,但是人菜瘾大老是报错
-
11.11 学习了typedef、链表结构,尝试使用来改造屎山
-
11.13 好像项目有点小大,bug还没改完,但是先改成项目类型分开功能
-
11.14 修改了大部分bug,但是保留了一小部分bug来表现我最真实的水平,打DOTA去了
- 修完三个小时bug的我belike:
![]()
- 11.15 我们安全了,暂时的…….程序终于可以正常运行了
程序代码
1 //10.2X 开始写屎山,喜欢往NULL还有不可写入的指针里面写东西,bug。主打一个叛逆 2 //10.26 修好上面的bug,但是屎山 3 4 //11.2 终于学到了结构体,然后就会用结构体编写屎山了,不过好歹可以运行了 .喜欢用malloc,但是人菜瘾大老是报错 5 6 //11.11 学习了typedef、链表结构,尝试使用来改造屎山 7 //11.13 好像项目有点小大,bug还没改完,但是先改成项目类型分开功能 8 //11.14 修改 9 #include <stdio.h> 10 #include <string.h> 11 #include <stdlib.h> 12 #include "support.h" 13 14 15 16 17 int main() 18 { 19 //test_input 20 21 //test 22 23 printf("---商品信息管理系统---\n"); 24 printf(" 1.添加商品\n"); 25 printf(" 2.删除商品\n"); 26 printf(" 3.修改商品\n"); 27 printf(" 4.查询商品\n"); 28 printf(" 0.退出系统\n"); 29 30 31 int option = 0,option2 = 0; 32 int is_head = 1; 33 int position = 0; 34 Node* goods_data = NULL; 35 36 char name_input[100]; 37 int price = 0; 38 int number = 0; 39 float repurchase_rate = 0; 40 41 while (option != 5) 42 { 43 printf("请输入选项:"); 44 scanf("%d",&option); 45 switch(option) 46 { 47 case 1: 48 //声明 &初始化 49 price = 0; 50 number = 0; 51 repurchase_rate = 0; 52 53 printf("请输入商品的信息:\n"); 54 printf("名称:\n"); 55 scanf("%s",name_input); 56 printf("价格:\n"); 57 scanf("%d",&price); 58 printf("数量:\n"); 59 scanf("%d",&number); 60 printf("回购率:\n"); 61 scanf("%f",&repurchase_rate); 62 63 //节点创建 64 if(is_head == 1 ){ 65 //第一次创建,head 66 is_head = 0; 67 goods_data = creat_Linklist(name_input,price,number,repurchase_rate); 68 }else{ 69 //后续增添节点,newNode 70 add_node(goods_data,name_input,price,number,repurchase_rate); 71 } 72 73 74 break; 75 case 2: 76 print_nodelist(goods_data); 77 printf("选择输入你要删除的商品:"); 78 scanf("%d",&position); 79 80 delect_node(&goods_data,position); 81 82 position = 0; 83 break; 84 85 case 3://修改信息 86 print_nodelist(goods_data); 87 printf("请输入你要修改的商品序号:\n"); 88 scanf("%d",&position); 89 print_nodedata(goods_data,position); 90 91 modify_nodedata(goods_data,position); 92 93 position = 0; 94 break; 95 96 case 4://查询商品 97 printf("请选择查询类型:\n"); 98 printf("1.列表查询\n"); 99 printf("2.名称查询\n"); 100 scanf("%d",&option2); 101 102 if(option2 == 1) 103 { 104 print_nodelist(goods_data); 105 printf("请输入你要查询商品序号:\n"); 106 scanf("%d",&position); 107 print_nodedata(goods_data,position); 108 } 109 else if(option2 == 2) 110 { 111 char name_input[100]; 112 printf("请输入你要查找的商品名字:\n"); 113 scanf("%s",name_input); 114 115 seach_node(goods_data,name_input); 116 117 } 118 else{ 119 printf("输入错误!\n"); 120 } 121 122 break; 123 124 case 5://退出系统 125 break; 126 127 default: 128 printf("不存在的选项,请重新输入选项!\n"); 129 break; 130 } 131 } 132 133 return 0; 134 }
#ifndef _STRUCT_H_ #define _STRUCT_H_ typedef struct node { //data char *name; int price; int number; float repurchase_rate; //Link struct node* next; }Node; #endif Node* creat_Linklist(char* name_input,int price,int number,float repurchase_rate); void add_node(Node* head,char* name,int price,int number,float repurchase_rate); void print_nodelist(Node* head); void print_nodedata(Node* head,int position); void delect_node(Node** head,int position); Node* modify_nodedata(Node* head,int position); Node* seach_node(Node* head,char* name);
Linklist.cpp
BUG修改记录
-
print_nodedata,对链表外访问
1 void print_nodedata(Node* head,int position) 2 { 3 Node* current = head; 4 5 for(int cnt = 1 ;cnt <= position ;cnt++ ){ 6 current = current->next; 7 } 8 }
- 修正:
- 增加获取链表长度
Node* current = head; int len = 0;//获取链表长度 while ( current->next != NULL ){ len++; current = current->next; } current = head;//重置current for(int cnt = 0;cnt < len_Linklist ;cnt++ ){ current = current->next; }
- 修正:
-
储存的字符串输出乱码 11.14 17:09
![]()
//问题源 //商品名字 动态分配内存储存name,避免浪费空间 //name_input ---> name(结构体中) char* name = (char*)malloc(strlen(name_input)+1); strcpy(name_input,name); newNode->name = name;
-
printf访问不存在的值
- printf访问不存在的值
void print_nodelist(Node* head) { int cnt = 0; Node* current = head; while(current != NULL){ //商品信息输出 printf("%d.%s\\n",++cnt,current->name); current = current->next; } }
- 当最后一次也就是current指向了NULL的时候,printf会访问NULL输出,bug
-
不安全的边界,可能访问内存外的东西
- position大于节点个数时,会访问内存外,然后程序崩溃(别问我为什么知道)
void delect_node(Node** head,int position) { Node* current = *head; Node* last_node = *head; for(int cnt = 1 ;cnt <= position ;cnt++ ){ last_node = current; if(current->next != NULL ){ //ĩλ¼ì²â current = current->next; } }
- 修正
- 新增一个len_Linklist函数用于计数节点个数
- [ ] 改正后函数逻辑改变,后面的内容需要重构
for(int cnt = 0 ;cnt < len_Linklist(*head) ;cnt++ ){ last_node = current; if(current->next != NULL ){ //末位检测 current = current->next; } }
商品删除有误 -
- 选的是apple删除的是banana
![]()
-
链表技术总结
-
二级指针
-
在C语言中,函数调用进入的东西都是另外拷贝一份独立操作的
-
也就是说int a变量进去的是他的拷贝a’
-
在我们传入int pa时,拷贝了pa的值(也就是a的地址0X114514*)
-
然后在函数中使用a的地址0X114514 0X114514——>a
-
这样才导致main函数中的变量a变化
-
那么现在我们回来看到传入的指针headRef
void insert(struct Node** headRef, int position, int value)-
图示headRef的变化过程
![Untitled]()
- 进入函数后我们就只能对拷贝出来的指针(也就是右边的那个)进行操作了
- 比方说,现在我要改变链表的头部,把链表的头部改为下一个指针
- 我把链表的头部改为下一个指针,也就是(0X114514)变成了(0X1919)
![Untitled]()
- 然后函数运行结束,返回main函数中
- 原来拷贝的指针释放,而原来main函数中的指针不变
![Untitled]()
-
那么如果我们现在变成用二级指针呢?
- 二级指针,也就是指针的地址
- 比方说,指针int* pa = 0X114514(a的地址)
- 那么pa的指针也就是int* ppa = 0X810(一个指向**-->**储存着0X114514的内存的地址)
insert( &pa, position, value) //取指针pa的地址(0X810)输入进去![Untitled]()
- 那么这时候,我们就可以通过改变0X810指向的值(0X114514)来改变外面的指针了
总结一下:
- 如果我们想对一个变量(或者地址)在函数中进行修改
- 那么我们就要传入它的指针
- 因为C语言的函数调用值都是拷贝一份另外在函数中使用的
- WARNING!函数内二级指针记得当地址用!(曾经有个悬崖边上插着个牌子写着warning,然后一个程序员看了就从上面跳了下去)
-
-
关于链表中结构体以变量的形式储存
- Q:为什么在链表中的节点(newNode)是指针(Node)而不是类似int的(Node)?*
- A:如下…
- 类似int的Node类型,在C语言中是只能【静态内存分配】来分配内存的,
- 也就是说在程序一运行时就分配好了内存,程序运行的过程中是不可以修改的,
- 比如说数组arr[x],创建后就通过【静态内存分配】分配好了内存,
- 你不能更改数组的大小,也就是不能更改它的内存大小
- 而作为int的Node指针类型,在C语言中则除了【静态内存分配】,还可以使用【动态内存分配】的方式分配内存(malloc,calloc)
- 也就是说,如果我使用了Node类型而不是Node*,那么我在程序运行过程中,是不可以通过【静态内存分配】来定义新节点的
- 而我用Node*指针类型作为节点,我虽然不能通过【静态内存分配】来分配空间,但是我还可以用malloc来通过【动态内存分配】的方式分配新空间,来创建新节点
- 类似int的Node类型,在C语言中是只能【静态内存分配】来分配内存的,
-
循环的首位判断
-








浙公网安备 33010602011771号