OJ专题(一)
最近大家都开始使用string.h头文件里面的一些函数啦,而且声明的变量也越来越大,那么,这样会出现什么问题呢?要注意些什么呢?现在我给大家整理一下。
我们发现,最近OJ上测试时经常会造成segmentation fault,产生core dump等错误,经过网上搜集资料、结合OJ服务器机器属性(据说是32位的Linux…)以及大家写的代码中可以发现,可能原因有如下几个
一、 内存访问越界
1. 使用错误的下标,导致数组访问越界。在测试某些测点(大家没想到的一些临界测点)时,可能会产生大于数组长度,或者小于0的数组下标,这样,大家在自己机器上测试时不会发现,一旦用OJ评测,就会发生运行时错误。
2. 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符。
3. 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。以后一定记住用后面几个函数!即使前面几个可以自动添加’\0’来作为结束标志,但有的时候如果不注意就会超出数组范围,这样,就会发生运行时错误。最近大家使用string.h比较频繁,一旦要注意呀
二、 堆栈溢出。记住,不要定义特别大的局部变量(也就是在函数里面,包括main函数,具体多大呢。。大家自己去试试,试到程序奔溃为止。),因为局部变量都分配在栈上,这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。大家最近定义的变量都非常大。所以我建议大家首先要选择好的算法,能节省更多的时空(时间与空间),然后是准确估计具体要用到多少的空间,比如题意有给出“每个单词最多10个字符”,那么我们就在每个单词的那一维定义11个字符,这样既符合题意,又不会溢出。最后,实在没办法的,我们就定义成全局变量!也就是函数外面,不要定义在函数里面(包括main函数),当然,这个和机器、编译器也有一些关系,有些编译器给函数分配的堆栈就特别大,所以有的时候就能测试通过。
其它大家未学习到、未涉及到的具体有:
1. 非法指针。
a) 使用空指针
b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump.
2. 多线程程序使用了线程不安全的函数。
3. 多线程读写的数据未加锁保护。对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump
综上所述:我建议大家以后做题学会以下几个方面:
1. 多想想一些临界的测点。比如要求输入字符串,那么就试试一个字符的能不能有效。
2. 学会调试,查看调试过程中变量的变化情况。
3. 学会文件操作或者重定向操作,这样以后测试的时候就不麻烦啦!一个命令就搞定,不用一个个字符输入。如果实在要。。那就学会在控制台复制粘贴好了。。
通知一:C语言积分赛快开始啦~大家抓紧时间准备吧,这可能是大家大学刚进来参加的第一个学术类竞赛,也是一个比较有“营养价值”的比赛,拿奖不仅有加综测,还有机会期末加分哦。。大家准备好了吗!
通知二:招募几位对OJ有强烈兴趣的同学,帮忙管理OJ,主要负责的事项有:出题(只要负责写代码出测点就好了~)+ 管理测点->给有需要的同学。想参加的同学发送短信“姓名+班级+学号”到18120775090,到时候按人数进行筛选~
最后:祝大家生活健康,学习进步!