1 使用scanf/printf出错
2 数组越界:Run-Time Check Failure #2 - Stack around the variable ‘XXXX‘ was corrupted.
需求:
飞秋为局域网通信软件,遵循IPMSG协议,其协议格式为:
char buf[] = "1_lbt6_0#262272#54E1AD293CAD#0#0#0#4000#9:1531646672:lh:lh:32:hello world";
将IPMSG的版本号、包编号、主机名、用户名、操作码、消息 提取出来
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main() {
char buf[] = "1_lbt6_0#262272#54E1AD293CAD#0#0#0#4000#9:1531646672:lh:lh:32:hello world";
char* temp_array[6]={""};
char* temp;
int i = 0;
//sscanf(buf, "%s:%ld%:%s:%s:%d:%s", version_code, &package_code, host, user, &operation_number, info);
temp = strtok(buf, ":");
temp_array[i++] = temp;
while (temp)
{
temp = strtok(NULL, ":");
temp_array[i++] = temp;
}
printf("version_code:%s\n", temp_array[0]);
printf("package_code:%s\n", temp_array[1]);
printf("host:%s\n", temp_array[2]);
printf("user:%s\n", temp_array[3]);
printf("operation_number:%s\n", temp_array[4]);
printf("infomation:%s\n", temp_array[5]);
return 0;
}
错误报告:
Run-Time Check Failure #2 - Stack around the variable 'temp_array' was corrupted.
能打印,只是运行的过程中出错了,运行时出错,一般就是由于数组越界。
问题出在while循环,可以在while中加入打印循环控制变量的语句,修改后的循环如下:
while (temp)
{
temp = strtok(NULL, ":");
printf("%d\n", i); //打印循环变量
temp_array[i++] = temp;
}
字符指针数组temp_array
只有6个元素,它的下标最多只能到5,而根据打印结果,可以看到数组的下标到了6,也就是说,出现了数组越界。
究其根本,字符串buf
中,冒号:
只出现了5次,buf
会被切6次(即strtok
函数执行第6次时,返回值仍然不是NULL
),第6次切完后,temp
并不为空,因此未跳出while循环,导致切了第7次,此次且完后temp
为NULL
,并且这个NULL
被赋值给了temp_array[6]
即便字符串中没有冒号,strtok也是可以切的,第一次切返回字符串首地址,第二次切返回NULL
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main() {
char buf[] = "dajglgj";
char* temp;
temp = strtok(buf, ":"); //即便buf中没有冒号:,也是可以切的
printf("%s\n", temp); //输出dajglgj
temp = strtok(NULL, ":");
printf("%s\n", temp); //输出(null)
return 0;
}
输出
让我们回到最初的需求,现在可以将程序修改成如下形式:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main() {
char buf[] = "1_lbt6_0#262272#54E1AD293CAD#0#0#0#4000#9:1531646672:lh:lh:32:hello world";
char* temp_array[6]={""};
char* temp;
int i = 0;
//sscanf(buf, "%s:%ld%:%s:%s:%d:%s", version_code, &package_code, host, user, &operation_number, info);
temp = strtok(buf, ":");
temp_array[i++] = temp;
while (temp)
{
temp = strtok(NULL, ":");
if(temp) temp_array[i++] = temp; //当temp不为NULL时才向数组赋值
}
printf("version_code:%s\n", temp_array[0]);
printf("package_code:%s\n", temp_array[1]);
printf("host:%s\n", temp_array[2]);
printf("user:%s\n", temp_array[3]);
printf("operation_number:%s\n", temp_array[4]);
printf("infomation:%s\n", temp_array[5]);
return 0;
}
3 写入位置XXX时发生访问冲突。
发生这种错误的原因,是由于给未定义的空间赋值,图中只是给dict分配了内存,但english和chinese都只是指针,指向的空间没有定义,所以会访问出错。
4 LINK2019外部符号无法解析
需求:制作一个只包含两个单词的词典
这里新建一个名为mini.c的源文件,内容如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
typedef struct _dict {
char english[256];
char chinese[256];
} Dict;
Dict* dict_init() {
//hello 你好
//world 世界
Dict* dict = (Dict*)malloc(sizeof(Dict) * 2);
cpystr(dict[0].english, "hello");
cpystr(dict[0].chinese, "你好");
cpystr(dict[1].english, "world");
cpystr(dict[1].chinese, "世界");
return dict;
}
void search(Dict* dict, char* english, int n)
{
for (int i = 0; i < n; i++)
{
if (cmpstr(dict[i].english, english) == 0)
{
printf("OK!The Chinese word is:\s", dict[i].chinese);
printf("\n");
return ;
}
}
printf("There is no %s\n", english);
}
void translate() {
Dict* dict = dict_init();
int ret = 0;
char english[256];
while (1)
{
printf("Please Enter the world you want to search:");
fgets(english, strlen(english), stdin);
english[strlen(english) - 1] = 0;
printf("%s\n", english);
search(dict, english, 2);
}
free(dict);
}
上面的代码中有三个函数,dict_init
是词典初始化,search
是搜索,translate
是翻译
接下来再建立一个名为main.c的源文件,内容如下:
int main()
{
translate();
return 0;
}
调试运行,发现有以下几个错误
我们自己定义的函数或者变量,在错误列表中,会在函数名前面加下划线,比如我们自己写的为dict_init
,但在错误列表中为_dict_init
。错误列表中,识别不了_cpystr
和_cmpstr
,也就是说,IDE认为,我们使用了两个自定义的符号,分别为cpystr
和cmpstr
,但却没有给出它们的定义。
可以在mini.c中查找(ctrl+F)这两个符号,以cpystr
为例
也就是说,编译器识别不了函数cpystr
,查看字符串拷贝函数,可以发现函数名为strcpy
,str在前面,因此,问题找到了,即库函数名搞错。cmpstr
的问题也是类似的,这里不再赘述。
将上述两个问题修改过来之后,编译能够通过,但也遇到了新的问题,当然,执行过程出错,或者执行的结果不符合预期,并不是本文讨论的内容,本文只讨论报错信息如何解除。
5 读取位置 XXX时发生访问冲突。
这种情况一般是读取未定义的空间
int** pArray_test()
{
int* p[3]; //p的本质数组,而不是指针,数组的每个元素都是指针
for (int i = 0; i < 3; i++)
{
p[i] = (int*)malloc(sizeof(int));
*(p[i]) = i+10;
}
return p;
}
void test05() {
int** p = pArray_test();
for (int i = 0; i < 3; i++)
{
printf("%d\n", *(p[i]));
}
}
原因:在函数pArray_test中,p是一个数组,它的内存是在栈中,函数返回时,栈中的内存被释放,但由于内存保护,*p
的内容暂时被保留了起来,*p
的内容,其实就是第一次调用malloc时所开辟空间的首地址,而malloc开辟的空间在堆中,因此还没释放,故可以打印出来(即控制台中的10);但test05的循环第二次执行时,内存保护失效,IDE触发异常。
6 检测到堆损坏
HEAP CORRUPTION DETECTED: after Normal block (#89) at 0x01596850.CRT detected that the application wrote to memory after end of heap buffer.
有两种可能:一是内存溢出,实际使用的内存大小超出了你申请的内存大小,在释放内存的时候就会发生该问题;二是释放野指针,假如某块内存被多个指针所指向,其中一个指针释放后,另一个就成为了野指针,对这个野指针释放时,就会报这种错误。
7 一元负运算符应用于无符号类型
负号用于无符号类型
printf("%d\n", -sizeof(struct Hero));
sizeof得到的结果,类型为unsigned int
,前面加负号会报错
需要对sizeof的结果做强制类型转化
printf("%d\n", -(int)sizeof(struct Hero)); //或printf("%d\n", -(long)sizeof(struct Hero));