news 2026/8/26 4:13:39

三、记录一些调试经验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
三、记录一些调试经验

一、 不能编译或能编译但运行异常

可以结合printf语句打印,缩小范围,再设置断点,逐行跟踪变量的值是否是预期值,重点关注是否是内存分配不够溢出,或者是一些逻辑问题

二、能编译能运行但提交结果部分正确,部分错误

这种一般不好直接调试,但可从以下方向进行排查:

1. 先核对 “输入输出格式”(最容易忽略的坑),如行末尾、行前是否有空格,间隔是一个还是两个空格,什么时候换行,输出格式是否需要前导0(最容易被忽略的点,一定要注意,不是什么时候都是%d输出,该用%04d输出时就要用)

另外还有一个点,就是一般最后一行输出其实不需要换行符,如果加了换行符,需要考虑像这:

输出格式如下: 5 10000 23333 44444 55555 88888 而代码写成 printf("%d\n", len); qsort(res, len, sizeof(int), compare); int space = 0; for (int i = 0; i < len; i++) { if (!space) { printf("%05d", res[i]); space = 1; } else { printf(" %05d", res[i]); } } printf("\n"); 可能会导致当len=0时,此时不应该有第二行输出,但仍会多输出一个换行符。 所以最保险的办法是不加这个换行符(不影响最终结果),注释掉即可

2. 构造 “测试用例” 覆盖全场景,尤其注意题目中的边界条件检查

3. 检查 “数据类型” 和 “计算精度,注意字符串内存是否溢出, int型数据是否溢出等

4. 逻辑错误,重点关注初始化,循环,分支三类逻辑是否正确

三、可以边输入边判断并输出,不影响格式问题!

四、自己在PTA做题过程中遇到的一些借助ai才排查到的问题例子:

1.

char str[81]; fgets(str, 80, stdin); //这里的80应该改为81,是总长度! str[strcspn(str, "\n")] = '\0';

应改为:

char str[81]; fgets(str, 81, stdin); //是总长度! str[strcspn(str, "\n")] = '\0';

fgets会自动在末尾加'\0',所以这里的参数是包含'\0'在内的总长度,如果写成则只最多只会从stdin中读79个字符,不符合题目最多输入80个字符的意思!

2.

对于超大整数,如果超过int型范围,换long long(64位)去接收,scanf的输入格式和printf打印的占位符都是lld

3. double类型,如果要求打印整数,需要先用(int)强转,再用%d形式打印,直接打印%d不能匹配double类型 !

4. 要求输出前导0时,如4要求输出04,用%02d占位符表示,其中0表示前导0,2表示输出的总位数,如04是两位,%.05d表示输出总位数为5为,不够的左侧补0

5.

输出指定长度的字符串,用%.*s格式,其中占位符.*表示输出字符串的长度,可以截断

字符串转int,用sscanf(char*,"%d", &n),特别注意传的是char*,是地址,可以是字符数组名+3, 但是不能是s[3],这传入的是一个字符,编译器会把这个字符的ascii码值当成内存地址去访问,引起异常

若题目说该数字的位数不超过1000位这种,最好多定义几个字节,比如char str[1005]

又犯一次错: 题目说不超过 100000 个字符的串,我

char s2[100000];// 这里出了问题,不超过100000个字符,那么加上'\0'也得有100001个了,溢出! //应该换成就通过了: char s2[100005];

6.

题目要求四舍五入时,用math.h里的一个round(double)函数,自动对小数作四舍五入

  • round(7.56)直接返回 8,因为它只做 “保留 0 位小数” 的四舍五入;
  • 若要保留 N 位小数,必须通过 “×10^N → round () → ÷10^N” 的缩放逻辑实现;
  • round()对 0.5 的处理是 “向远离 0 的方向舍入”(正数进 1,负数退 1)

7.

关于只对一个数组中的有效元素,找出最大最小值时,

如果初始化最大、最小的索引这样写:

int max_index = 0; int min_index = 0;

如果索引0不是有效的,那么需要先记录下第一个有效元素的索引first_effctive

再初始化为:

int max = first_effctive;
int min = first_effctive;

8.

int n; scanf("%d", &n); getchar(); //吃掉换行符,因为后面要用fgets读取 char** str = (char**)malloc(sizeof(char*) * n); for (int i = 0; i < n; i++) { str[i] = (char*)malloc(sizeof(char) * 20); fgets(str[i], 17, stdin); str[i][strcspn(str[i], "\n")] = '\0'; }

这里因为输入的字符串是一行,包含空格,所以用fgets去读,但是之前的n用scanf读取后,在缓冲区留下了换行符,导致fgets会读取留下的这个换行符而错误

所以一定要用getchar()吃掉上一步scanf留下的换行符,保证后面的fgets正确读取 !

另外,用scanf的%c格式读取时一定一定要小心,它不会跳过换行符等,会读取任意字符

如果缓冲区输入有留下换行符(是我们不期望读取的字符)需要先getchar()吃掉处理

9.

double类型数据读取时,一定用%lf格式去读才能读到!

复数乘法,模值相乘,和幅度角值可以直接相加,得到的就是相乘后的模和幅度角

模相乘,幅度相加

三角函数sin可以直接用,参数和返回都是double,fabs(double) 用于返回浮点数,double类型数的绝对值,1e-4表示0.0001

10. 打印%需要转义,%本身表示占位符开始,所以打印%需要用专门的%%来打印

11.sscanf处理包含非法字符的字符串(比如12a3)时,并不会直接返回失败,而是会 “尽可能读取合法部分”,这就导致你无法准确判断输入是否为纯数字,比如读取为12,到a不匹配时就停下。返回2(成功读取的数量),所以在转换之前,需要先遍历字符判断是否合法

12. p=='\0' 与 p == NULL 的区别

*p == '\0'p == NULL是完全独立的两个状态,没有任何必然联系,我用最直白的方式解释:

  • p == NULL:表示指针变量p本身的值是 0(空地址),它没有指向任何有效的内存空间,此时访问*p会直接导致程序崩溃;
  • *p == '\0':表示指针p指向的有效内存地址中存储的字符是字符串结束符,此时p本身是一个有效的非空指针

13.

字符串比较一定要用strcmp,即使是字符串与单个字符串"#"这种比较,也要用strcmp

在处理输入以读取到#为结束标志时,由于#不算输入,所以注意这时count的统计不能++

当题目直说输入字符串以回车结束时,需要考虑输入可能有空格等空白字符,所以用fgets读取更好,用scanf读取会漏掉要求输入的空白字符!

14.

C 语言不会在运行时检查数组索引是否越界,访问arr[n]不会直接崩溃,而是会读取「数组内存后方的相邻垃圾内存」

内存类型越界,栈数组(在main函数里面静态定义的数组)大概率段错误,小概率逻辑错乱,关键是否触达栈保护页,报段错误

堆数组(动态分配)越界时大概率读取垃圾值,极小概率段错误是否超出进程地址空间,报答案错误!

15.

关于realloc函数使用的易错点,realloc(arr,sizeof(类型)*size)

注意第二个参数是扩容后的总大小,以字节为单位,不是以类型个数为单位,只写个size是错的!

对于动态加入链表函数,head在函数内是局部副本,需要返回类型不为空才能传给主调函数!

16.

在C语言中,NULL宏通常被定义为((void *)0)。这是一个将整数0强制转换为void类型的指针,表示一个不指向任何有效内存地址的空指针,调试时可以用%s格式把空指针打印出null !

17.

全局变量(包括静态局部变量)的 int 类型会自动初始化为 0,而普通局部变量(栈上)的 int 类型如果不手动初始化,值是未定义的垃圾值

具体来说,在主函数外定义的int类型,自动为0,而在main函数内定义的int类型变量,是垃圾值,一般根据需要手动赋0才行

18.

当使用scanf结合!=EOF判断时,输入数据按回车并不算输入/文件 末尾的结束符,scanf会跳过换行符继续阻塞I/O,等待输入数据并读取!

所以这时可手动以输入-1或换行符表示结束

或者边输入边输出运行结果!

19.

exit是库函数,用于退出程序!,编写自定义函数时注意避开系统已存在的函数名称

20.

隐藏的数组越界问题:

1) PTA天梯赛59题,题目虽告知每行字符总长度不超过100,我最开始定义的char str[105],

但是题目要求替换部分内容,而替换后的总长度超过了 105个字符,导致越界!

遇到这种问题,都先试试扩大数组能否解决问题,比如扩大char str[200]!

另外可以复习一下此题的解题思路,尤其是如何找到最后3个单词并进行拼接覆盖(相当于替换的效果)!

2)

段错误时,一般考虑数组越界,而数组越界分为内存溢出和索引异常!

如果确定数组大小足够大,那就考虑索引异常(过大或为负索引),这时候仔细审查索引的控制,是否可能出现过大/为负数的情况!

21.

如果排除了越界错误,且部分答案正确,仔细读题,重新审题,严格按照题目要求复现,同时挖掘边界和极端情况!

关于极端输入的找法:

如果从题目中不明显,顺着代码数据流向找,判断每一步是否有逻辑漏洞漏掉一些条件/极端情况!

22.

复现PTA天梯赛88题,尤其是has_extra位置的定义,控制的是不同分数而不是批次!

顺序学习思路:

对一批分数先排序,然后从小到大选,遇到同分的处理:

int last_score;

遍历分数数组,如果>last_score就取,并更新last_score

如果==last_score,继续根据条件判断是否可选,不用更新last_score

但如果要求了同一批次、同一分数下只能多选一个额外名额,则需要更新额外名额的标志位has_extra !

此方法,先升序或降序排序(让相同的值挨着排列),再更新last_number,也可用于int型数组去重!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/26 4:12:16

实时手机检测-通用在安防监控中的应用:打电话行为识别实战

实时手机检测-通用在安防监控中的应用&#xff1a;打电话行为识别实战 1. 项目概述与价值 在现代安防监控场景中&#xff0c;准确识别打电话行为具有重要实用价值。无论是考场防作弊、驾驶安全监控&#xff0c;还是公共场所行为规范管理&#xff0c;都需要快速准确地检测手机…

作者头像 李华
网站建设 2026/7/14 16:56:37

Qwen3-Reranker-0.6B惊艳效果:中文古诗与现代译文跨体裁语义重排

Qwen3-Reranker-0.6B惊艳效果&#xff1a;中文古诗与现代译文跨体裁语义重排 注意&#xff1a;本文所有展示效果均基于真实测试&#xff0c;使用vllm部署Qwen3-Reranker-0.6B模型&#xff0c;通过gradio webui进行调用验证。 1. 模型能力概览 Qwen3-Reranker-0.6B是Qwen3 Embe…

作者头像 李华
网站建设 2026/7/14 16:56:39

Super Qwen Voice World实战落地:自媒体批量生成多角色配音方案

Super Qwen Voice World实战落地&#xff1a;自媒体批量生成多角色配音方案 1. 项目概述与核心价值 Super Qwen Voice World是一个基于Qwen3-TTS语音合成技术的复古像素风语音设计平台。这个项目专门为自媒体创作者、视频制作者和内容生产者设计&#xff0c;解决了多角色配音…

作者头像 李华
网站建设 2026/7/14 16:56:38

Face3D.ai Pro免配置环境搭建:Docker容器化部署全流程(含端口映射)

Face3D.ai Pro免配置环境搭建&#xff1a;Docker容器化部署全流程&#xff08;含端口映射&#xff09; 1. 项目介绍与核心价值 Face3D.ai Pro 是一个将前沿AI视觉算法与现代化工业UI设计相结合的Web应用。这个系统最大的亮点在于&#xff0c;它能从单张普通的2D正面照片中&am…

作者头像 李华