人人都写过的5个Bug!
1. 变量未初始化
#include
#include
int main()
{
int i, j, k;
int numbers[5];
int *array;
puts("These variables are not initialized:");
printf(" i = %d\n", i);
printf(" j = %d\n", j);
printf(" k = %d\n", k);
puts("This array is not initialized:");
for (i = 0; i < 5; i++) {
printf(" numbers[%d] = %d\n", i, numbers[i]);
}
puts("malloc an array ...");
array = malloc(sizeof(int) * 5);
if (array) {
puts("This malloc'ed array is not initialized:");
for (i = 0; i < 5; i++) {
printf(" array[%d] = %d\n", i, array[i]);
}
free(array);
}
/* done */
puts("Ok");
return 0;
}
These variables are not initialized:
i = 0
j = 0
k = 32766
This array is not initialized:
numbers[0] = 0
numbers[1] = 0
numbers[2] = 4199024
numbers[3] = 0
numbers[4] = 0
malloc an array ...
This malloc'ed array is not initialized:
array[0] = 0
array[1] = 0
array[2] = 0
array[3] = 0
array[4] = 0
Ok
i
和 j
的值刚好是 0,但 k
值为 32766。在 numbers 数组中,大多数元素也恰好是零,除了第三个(4199024)。These variables are not initialized:
i = 0
j = 1074
k = 3120
This array is not initialized:
numbers[0] = 3106
numbers[1] = 1224
numbers[2] = 784
numbers[3] = 2926
numbers[4] = 1224
malloc an array ...
This malloc'ed array is not initialized:
array[0] = 3136
array[1] = 3136
array[2] = 14499
array[3] = -5886
array[4] = 219
Ok
2. 数组越界
#include
#include
int main()
{
int i;
int numbers[5];
int *array;
/* test 1 */
puts("This array has five elements (0 to 4)");
/* initalize the array */
for (i = 0; i < 5; i++) {
numbers[i] = i;
}
/* oops, this goes beyond the array bounds: */
for (i = 0; i < 10; i++) {
printf(" numbers[%d] = %d\n", i, numbers[i]);
}
/* test 2 */
puts("malloc an array ...");
array = malloc(sizeof(int) * 5);
if (array) {
puts("This malloc'ed array also has five elements (0 to 4)");
/* initalize the array */
for (i = 0; i < 5; i++) {
array[i] = i;
}
/* oops, this goes beyond the array bounds: */
for (i = 0; i < 10; i++) {
printf(" array[%d] = %d\n", i, array[i]);
}
free(array);
}
/* done */
puts("Ok");
return 0;
}
This array has five elements (0 to 4)
numbers[0] = 0
numbers[1] = 1
numbers[2] = 2
numbers[3] = 3
numbers[4] = 4
numbers[5] = 0
numbers[6] = 4198512
numbers[7] = 0
numbers[8] = 1326609712
numbers[9] = 32764
malloc an array ...
This malloc'ed array also has five elements (0 to 4)
array[0] = 0
array[1] = 1
array[2] = 2
array[3] = 3
array[4] = 4
array[5] = 0
array[6] = 133441
array[7] = 0
array[8] = 0
array[9] = 0
Ok
3. 字符串溢出
char
值,也可以将其视为数组。因此,你也需要避免超出字符串的范围。如果超出,则称为字符串溢出。gets
函数读取数据。gets
函数非常危险,因为它不知道接收它的字符串中可以存储多少数据,只会天真地从用户那里读取数据。#include
#include
int main()
{
char name[10]; /* Such as "Beijing" */
int var1 = 1, var2 = 2;
/* show initial values */
printf("var1 = %d; var2 = %d\n", var1, var2);
/* this is bad .. please don't use gets */
puts("Where do you live?");
gets(name);
/* show ending values */
printf("<%s> is length %d\n", name, strlen(name));
printf("var1 = %d; var2 = %d\n", var1, var2);
/* done */
puts("Ok");
return 0;
}
var1 = 1; var2 = 2
Where do you live?
Beijingis length 7
var1 = 1; var2 = 2
Ok
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch
是世界上名字最长的城市,这个字符串有 58 个字符,远远超出了 name
变量中可保留的 10 个字符。var1
和var2
,都有可能被波及:var1 = 1; var2 = 2
Where do you live?
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogochis length 58
var1 = 2036821625; var2 = 2003266668
Ok
Segmentation fault (core dumped)
var1
和 var2
不再是它们的起始值 1
和 2
。getline
函数就是一个不错的选择,它将分配足够大的内存来存储用户输入,因此用户不会因输入太长字符串而意外溢出。4. 内存重复释放
malloc
函数为数组和字符串申请内存,系统将开辟一块内存并返回一个指向该内存起始地址的指针。内存使用完毕后,我们一定要记得使用 free
函数释放内存,然后系统将该内存标记为未使用。free
函数一次。如果你第二次调用 free
函数,将导致意外行为,而且可能会破坏你的程序。#include
#include
int main()
{
int *array;
puts("malloc an array ...");
array = malloc(sizeof(int) * 5);
if (array) {
puts("malloc succeeded");
puts("Free the array...");
free(array);
}
puts("Free the array...");
free(array);
puts("Ok");
}
free
函数时出现 core dump 错误:malloc an array ...
malloc succeeded
Free the array...
Free the array...
free(): double free detected in tcache 2
Aborted (core dumped)
free
函数呢?一个最简单的方法就是将 malloc
和 free
语句放在一个函数里。malloc
放在一个函数里,而将 free
放在另一个函数里,那么,在使用的过程中,如果逻辑设计不恰当,都有可能出现 free
被调用多次的情况。5. 使用无效的文件指针
config.dat
文件里,程序运行时,就可以调用这个文件,读取配置信息。fopen
函数打开文件,然后该函数返回指向文件的流指针。fopen
函数将返回 NULL
。在这种情况下,我们仍然对其进行操作,会发生什么情况?我们一起来看下:#include
int main()
{
FILE *pfile;
int ch;
puts("Open the FILE.TXT file ...");
pfile = fopen("FILE.TXT", "r");
/* you should check if the file pointer is valid, but we skipped that */
puts("Now display the contents of FILE.TXT ...");
while ((ch = fgetc(pfile)) != EOF) {
printf("<%c>", ch);
}
fclose(pfile);
/* done */
puts("Ok");
return 0;
}
Open the FILE.TXT file ...
Now display the contents of FILE.TXT ...
Segmentation fault (core dumped)
fopen
函数打开文件后,使用 if (pfile != NULL)
以确保指针是可以使用的。小结
评论