商品管理系统&链表实现&二级指针&

建议!:这是我从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 }
main.cpp 
#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);
support.h

 

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来通过【动态内存分配】的方式分配新空间,来创建新节点
    • 循环的首位判断

       

posted @ 2023-11-15 11:37  Aeside  阅读(32)  评论(0)    收藏  举报