《从缺陷中学习C/C++》第3章库函数问题,本章主要介绍库函数的使用中会遇到的问题。使用库函数可以降低软件开发的难度,提高代码编写的效率。本节为大家介绍危险的strdup函数。
-
作者:刘新浙/刘玲/王超/李敬娜 等来源:人民邮电出版社|
2013-11-28 15:35
3.22 危险的strdup函数
3.22 危险的strdup函数
代码示例
- void printDup(char *str)
- {
- char *tmp = strdup(str);
- printf("%s\n", tmp);
- }
- int main()
- {
- char *ptr = "Hello World!";
- printDup(ptr);
- printf("Command to check memleak: valgrind --tool=memcheck--leak- check=yes ./a.out\n");
- return 0;
- }
现象&后果
程序运行一切正常,但用内存检查工具查看时,发现有内存泄漏发生,strdup分配的内存没有被释放。
Bug分析
这里的内存泄漏主要与strdup函数有关。strdup用来实现字符串复制,它的glibc参考实现如下:
- char * __strdup (const char *s)
- {
- size_t len = strlen (s) + 1;
- void *new = malloc (len);
- if (new == NULL)
- return NULL;
- return (char *) memcpy (new, s, len);
- }
由strdup函数实现代码可以看到,strdup会自动分配内存空间,并复制字符串。但strdup只malloc了内存,并没有释放。释放strdup内部动态分配的内存需要由调用者去做,这点在strdup的man手册里明确提到。
一般大家都比较清楚malloc/free要成对使用,但strdup把动态分配内存的事实隐藏在自己内部,如果使用者不了解这个细节,就会造成内存泄漏。
正确的做法是,strdup返回的字符串在使用完之后要及时用free释放掉。
正确代码
- void printDup(char *str)
- {
- char *tmp = strdup(str);
- printf("%s\n", tmp);
- free(tmp);
- }
- int main()
- {
- char *ptr = "Hello World!";
- printDup(ptr);
- printf("Command to check memleak: valgrind --tool=memcheck--leak- check=yes ./a.out\n");
- return 0;
- }
编程建议
由于strdup函数有容易忘记释放内存的风险,不推荐使用它。如果想做字符串复制操作,建议直接使用malloc函数加memcpy函数。