ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从垃圾值到段的错误

从垃圾值到段的错误 C 语言指针踩坑实录从垃圾值到段错误博主最近一段时间在深究C语言的学习下面是我在学习过程中遇到的几个我觉的比较有价值的坑希望对在向深度学习C语言的伙伴们有所帮助坑 1未初始化变量一般在声明变量的时候会有这几种情况全局变量和局部变量一般局部变量未初始化里面存储的就是一堆垃圾值局部变量和全局变量的存储位置是不一样的局部变量存储于栈而全局变量存储于数据段这里的全局变量未报错是因为它是能够被自动默认初始化为0的。inta;intmain(){intnum;printf(%d\n,a);printf(%d,num);}C不会帮助你清零对于局部变量来说出生就是垃圾值上面程序的运行是基于VS 2026版本的环境下运行的它会直接给你报错但有些编译器可能就不会这个细节我觉得还是值得注意的。坑 2数组越界——不报错比报错更可怕对于数组来说最怕的就是越界元素访问。这种访问编译器一般是不会报错的程序不会崩溃而且会正常运行终端最后一行已退出代码为 0 (0x0)——程序觉得自己运行得非常成功。因为在C标准里给予了程序员足够信任越界成为“沉默杀手”下面就是程序运行的结果就是一堆乱数字。intmain(){intarr[3]{0,1,2};printf(%d,arr[3]);return0;}坑 3改字符串字面量——只读区的段错误对于字符串字面量来说是不可修改的字面量住在只读数据段“文物保护区”这是无法对其进行修改的char *p hello;对于这个代码来说通常都不会这样去写基本上都会在前面加上const就变成这样const char *p hello;这是为了防止对其进行意外的修改操作因为指针是可以对地址进行操作的例如像这样p[0] H的赋值编译安安静静一运行就 Segmentation fault——gdb 一跑崩在p[0] H这一行。坑 4malloc 的节点忘初始化 next在编写创建节点函数的时候忘记初始化next NULL了在遍历链表的时候极有可能读到垃圾地址。这你要是不注意遍历到尾节点时判断 next ! NULL垃圾地址恰好不是 NULL → 顺着垃圾地址读下去读到什么、崩不崩那就看你的命好不好了。Node*create_node(intdata)// 错误示范malloc 完就直接返回{Node*p(Node*)malloc(sizeof(Node));p-datadata;// 忘了 p-next NULL;returnp;}malloc 只管在堆上划一块地地里的旧数据原样保留和坑 1 的栈上垃圾值是同一个道理。坑 5反转链表翻转成功却只打印一个节点在我编写翻转链表的过程中出现了一个奇怪的现象在翻转链表函数写好并运行之后没有报错但是终端输出的结果让我意想不到下面是我的主要代码和不尽人意的终端的输出结果显示代码//反转链表返回新的头节点。空链表返回指针NULLNode*reverse_list(Node*head){if(headNULL)//判断是否为空链表{returnNULL;}Node*prevhead;Node*curhead-next;head-nextNULL;while(cur!NULL)//采用循环的方式依次调转下一个节点指向{Node*pcur-next;cur-nextprev;prevcur;curp;}returnprev;}intmain(){Node*headNULL;headinsert_head(head,10);//头插法headinsert_head(head,20);print_list(head);//全局打印链表printf(--------------------------------------------------\n);reverse_list(head);print_list(head);free_list(head);return0;}终端输出结果就是这种没有编译报错又还能输出欸关键是它输出还不对当出现问题后的第一时间我意识到肯定是反转链表的逻辑函数写的有问题于是我看了一遍又一遍并反复询问自己why?why?没有问题啊为什么就是不对呢可谓是心烦意乱因为我磨蹭了20分钟还没有结果最后无奈之下我让AI帮我修改哟呵好了结果不看不知道一看哭笑不得真得把自己给笑死在主函数里居然没有用返回值接收新的头节点为什么偏偏只打印出一个节点因为翻转成功后原来的头节点已经变成了尾巴——它的 next 指向 NULL。main 里的 head 还指着这个老节点从尾巴开始打印自然只有孤零零一个。换句话说那份错误的输出本身就是线索它证明翻转其实成功了问题出在打印的起点上。需要接收返回的头节点head reverse_list(head);才行。不然导致下一次全局打印链表的时候用的还是旧的头节点。这让我意识到会调试找Bug是一件非常重要的能力就这么个小小的问题居然找了20分钟啊这里我总结的是“爆炸现场离作案现场很远”。对于输出不对的问题来说应该先从输出获取信息由表及里的依次从主函数里逐步深入的排查用gdb看现场最后才改代码。最后这5 个坑其实是同一个道理——C 把内存的全部权力交给你也把全部责任推给你。垃圾值、越界、只读区、脏堆内存、值传递都是权力没说明书的代价。
返回列表