1.内存泄漏问题
问题代码1
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main( int argc, char *argv[] ) 5 { 6 unsigned int i = 0; 7 char *str = "hello world!\r\n"; 8 char *t = calloc( 200, sizeof( char ) ); 9 10 while( str[i] ) 11 { 12 *t++ = str[i]; 13 i++; 14 } 15 t[i] = 0; 16 printf( "%s", t ); 17 printf( "%s", str ); 18 free( t ); 19 20 return 0; 21 }
上述代码要做的事情十分简单:将str字符指针指向的字符串复制到字符指针t指向的内存区域,t指向了一块200bytes大小的内存空间,为了保持str始终指向“hello world!\r\n”,没有对str变量本身进行增减操作。该程序运行的结果如下:
hello world!
Segmentation fault (core dumped)
其实问题出在free()这里,即内存泄漏问题,传入该函数的指针变量必须指向之前分配好的地址,否则会产生内存释放失败。上述程序首先通过calloc()获得了一个内存地址,并放在字符指针变量t中,但是复制的时候t发生了变化,因此传入free()的参数并非calloc()的返回值,因此报错。
一种解决方法是,使用一个指针变量记录分配得到的内存地址,但是并不操作它,只有在最后释放的时候作为free()的参数。
问题代码2
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main( int argc, char *argv[] ) 5 { 6 unsigned int i = 0; 7 char *s = calloc( 5, sizeof( char ) ); 8 char *t = s; 9 char *str = "abcdefghijklmn"; 10 11 while( str[i] ) 12 { 13 s[i] = str[i]; 14 i++; 15 } 16 printf( "%s\n", t ); 17 free( t ); 18 19 return 0; 20 }
上述代码的功能也是实现字符串的复制,将str指向的“abcdefghijklmn”复制到s指向的内存中。运行后的错误如下:
abcdefghijklmn
*** glibc detected *** ./y: free(): invalid next size (fast): 0x084b0008 ***
======= Backtrace: =========
xxxxxxxxxxxxxxxxxxxxxx此处省略一些信息
======= Memory map: ========
xxxxxxxxxxxxxxxxxxxxxx此处省略一些信息
Aborted (core dumped)
错误的原因是,calloc()只申请了5个字节大小的内存空间,而该程序将十几个字符都写入了该片内存,释放的时候检查到内存访问越界,因此报错,这里只要申请足够大的内存空间就可以了。
2. fflush()清空stdin数据流失败。
问题代码:
1 #include <stdio.h> 2 3 int main( int argc, char *argv[] ) 4 { 5 char i, j, c; 6 7 scanf( "%c", &i ); 8 fflush( stdin ); 9 scanf( "%c", &j ); 10 11 printf( "%x %x\n", i, j ); 12 13 return 0; 14 }
现象:程序期待两个字符,第二次执行scanf函数之前已经使用fflush清空输入缓冲区,但是输入一个字符之后,便输出结果,显示输入的字符以及一个十六进制数a。
原因:fflush()函数没有起作用,第二个scanf获取到了换行符。
解决方案:有必要的时候,清空输入缓冲区。清空的方案有两种:使用fflush()函数或者使用getchar()。
fflush()用于清空缓冲区,多半指的是输出缓冲区,有些版本的函数库并不支持清空输入缓冲区,所以可移植性不强,这里使用的glibc就不支持,因此出错。
移植性较强的代码实现是:while( ( c = getchar() ) != '\n' && c != EOF )