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

由于这是我直接从Notion复制过来的,很多格式有问题,建议直接去我的Notion里面看,链接https://billowy-pigment-2ec.notion.site/8cc78481ec66478e90cad44e2bc05db9?pvs=4

写的比较粗糙,凑合看吧

但是个人在后面的链表实现问题写得比较详细

同时也欢迎各位佬来提意见!

  • 开发日志抱怨日记

    • 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 我们安全了,暂时的…….程序终于可以run了

  • AI对上面代码的评价是

    AI

    您的代码中存在一些问题。我将依次指出并修正它们。

    1. malloc返回的是指针类型,而您在这里定义了一个Node类型的指针,应该去掉*(double*):
    c
    Node* newNode = (Node*)malloc(sizeof(Node*));
    

    改为:

    c
    Node* newNode = (Node*)malloc(sizeof(Node));
    
    1. 您没有正确地使用字符串拷贝函数strcpy()。在这个函数中,第二个参数应该是要复制到的位置(即目标),而不是源字符串。正确的用法是:
    c
    strcpy(newNode->name, name_input);
    
    
    1. 您在链表创建和插入节点的时候有问题。每次添加新节点的时候,都会使head变量失效。您的add_node函数需要传入一个指向头结点的指针,然后在这个函数中修改这个头结点的值:
    c
    void add_node(Node** head_ref, char* name, int price, int number, float repurchase_rate) {
        Node* new_node = (Node*)malloc(sizeof(struct node));
        // ... 其他初始化
        new_node->next = (*head_ref);
        (*head_ref) = new_node;
    }
    
    

    这样,您就可以从main函数中调用它了:

    c
    goods_data = add_node(&goods_data, name_input, price, number, repurchase_rate);
    
    
    1. 在delect_node函数中,当删除第一个元素时,需要让头指针指向下一个元素。否则,程序将试图访问已经被释放的内存区域。修改如下:
    c
    if(last_node == NULL) {
        free(head);
        head = current->next;
        return;
    }
    last_node->next = current->next;
    free(current);
    
    
    1. 在print_nodelist函数中,您忘记了为计数器加一:
    c
    printf("%d.", ++cnt);
    
    
    1. 在modify_nodedata函数中,当位置大于链表长度时,会发生段错误。因为当计数器超出范围后,current就不再是一个有效的指针。因此,在调用之前,应先检查链表的长度。例如:
    c
    for (int i = 1; i < length + 1; i++) {
        if(i == position) break;
        current = current->next;
    }
    
    
    1. 最后,seach_node函数似乎存在问题。在while循环中的条件似乎不需要,因为您只需要遍历整个链表即可。您还可以考虑在找到元素之后跳出循环。这里可能需要进一步讨论。此外,当元素不存在时,应当返回NULL。例如:
    c
    Node* seach_node(Node* head, char* name_input) {
        for (int i = 1; head != NULL; i++) {
            if (!strcmp(head->name, name_input)) {
                print_nodedata(head, i);
                return head;
            }
            head = head->next;
        }
        printf("该商品不存在\\n");
        return NULL;
    }
    
    

    希望以上建议能对您有所帮助!如果您还有其他疑问,请随时问我。

  • AI提出的bug修改

    • [x] head重复创建
    • [x] delect删除head
  • 目前功能调试情况

    • [x] 添加商品
    • [x] 删除商品
    • [x] 修改商品
    • 查询商品
      • [x] 列表查询
      • [x] 名称查询

BUG修改记录

  • print_nodedata,对链表外访问

    void print_nodedata(Node* head,int position)
    {
    	Node* current = head;
    	
    	for(int cnt = 1 ;cnt <= position ;cnt++ ){
    		current = current->next;
    	}
    }
    
    • 修正:
      • 增加获取链表长度
    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

    Untitled

    //问题源
    //商品名字 动态分配内存储存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函数用于计数节点个数
    • [x] 改正后函数逻辑改变,后面的内容需要重构
    for(int cnt = 0 ;cnt < len_Linklist(*head) ;cnt++ ){
    		last_node = current;
    		if(current->next != NULL ){
    			//末位检测 
    			current = current->next;
    		}	
    	}
    
  • 商品删除有误

    • 选的是apple删除的是banana
    • 是由于current = current→next运行过早导致的

    Untitled

  • 链表技术总结

    • 二级指针

      • 在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的变化过程

        • 进入函数后我们就只能对拷贝出来的指针(也就是右边的那个进行操作了
        • 比方说,现在我要改变链表的头部,把链表的头部改为下一个指针
        • 我把链表的头部改为下一个指针,也就是(0X114514)变成了(0X1919
        • 然后函数运行结束,返回main函数中
        • 原来拷贝的指针释放,而原来main函数中的指针不变
      • 那么如果我们现在变成用二级指针呢?

        • 二级指针,也就是指针的地址 
        • 比方说,指针int* pa = 0X114514(a的地址)
        • 那么pa的指针也就是int* ppa = 0X810(一个指向**-->**储存着0X114514的内存的地址)
          insert( &pa, position, value)
          //取指针pa的地址(0X810)输入进去

        • 那么这时候,我们就可以通过改变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来通过【动态内存分配】的方式分配新空间,来创建新节点
    • 循环的首位判断

      • 输入 == 输出
      • 可以作为判断首位的依据
      Node* current = *head;
      	Node* last_node = *head;
      	
      	for(int cnt = 1 ;cnt <= position ;cnt++ ){
      		last_node = current;
      		if(current->next != NULL ){
      			//末位检测 
      			current = current->next;
      		}	
      	}
      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值