strcpy, strncpy, malloc, realloc以及memory leak等注意问题

来源:互联网 发布:华信学院地址淘宝 编辑:程序博客网 时间:2024/05/08 17:04


本文涉及:

1. strcpy和strncpy使用心得

2. malloc和realloc使用心得

3. 指针的指针使用



整个源代码main.c:

#include <stdlib.h>#include <string.h>#include <stdio.h>void study_strcpy();void study_strncpy();void *study_malloc(size_t size);void study_free(void *resource);void study_use_mistakes();void study_strappend();void study_strappend2();u_char *strappend(u_char *dest, const u_char *append);u_char *strappend2(u_char **dest, const u_char *append);void malloc_memory_by_pointer(u_char *dest, size_t size);void malloc_memory_by_pointer_pointer(u_char **dest, size_t size);void study_memory_leak();void study_memory_leak2();int main(){/*strcpy 和 strncpy学习study_strcpy();study_strncpy();//学习使用中的误区study_use_mistakes();*//*realloc学习study_strappend();*//*指针的指针学习study_strappend2();*//*内存泄露学习*///存在10个字节的内存泄露//study_memory_leak();//不再有内存泄露//study_memory_leak2();return 0;}void study_memory_leak(){u_char *dest;size_t size;dest = NULL;size = 10;malloc_memory_by_pointer(dest, size);free(dest);dest = NULL;//整个方法执行完毕会有10个字节的内存泄露,具体见图}void study_memory_leak2(){u_char *dest;size_t size;dest = NULL;size = 10;//传递 &destmalloc_memory_by_pointer_pointer(&dest, size);free(dest);dest = NULL;}void malloc_memory_by_pointer(u_char *dest, size_t size){dest = (u_char *)study_malloc(size);}void malloc_memory_by_pointer_pointer(u_char **dest, size_t size){*dest = (u_char *)study_malloc(size);}void study_strappend(){const u_char *src = "hello, lingyun";const u_char *append = " , my name is c++";u_char *dest;dest = NULL;dest = strappend(dest, src);printf("value: %s\n", dest);printf("after strappend\n");//dest = strappend(dest, append);//printf("value: %s\n", dest);printf("value: %s\n", strappend(dest, append));free(dest);dest = NULL;}void study_strappend2(){const u_char *src = "hello, liyanhua";const u_char *append = " , your baby 's name is lingyutian";const u_char *append2 = " , your husband 's name is lingyun.";u_char *dest;dest = NULL;//printf("pointer address: %d\n", &dest);//可以直接打印printf("value: %s\n", strappend2(&dest, src));printf("value: %s\n", strappend2(&dest, append));//可以赋值后再操作dest = strappend2(&dest, append2);printf("value: %s\n", dest);free(dest);dest = NULL;}void study_free(void *resource){    if(resource){free(resource);resource = NULL;}}void *study_malloc(size_t size){    void        *dest;dest = malloc(size);if(dest == NULL){perror("malloc");return NULL;}printf("malloc %d bytes\n", size);return dest;}void study_strcpy(){    const u_char        *src = "hello, lingyun by using strcpy";size_t               src_len;u_char              *dest;size_t               dest_len;src_len = strlen(src);dest_len = src_len;//这里比原字符串多分配一个byte的空间dest = (u_char *)study_malloc(dest_len + 1);if(dest == NULL){return;}strcpy(dest, src);printf("src: %s\n", src);printf("dest: %s\n", dest);study_free(dest);}void study_strncpy(){    const u_char        *src = "hello, lingyun by using strncpy";size_t               src_len;u_char              *dest;size_t               dest_len;size_t               malloc_size;src_len = strlen(src);dest_len = src_len;malloc_size = dest_len + 1;//这里比原字符串多分配一个byte的空间dest = (u_char *)study_malloc(malloc_size);if(dest == NULL){return;}strncpy(dest, src, malloc_size);printf("src: %s\n", src);printf("dest: %s\n", dest);study_free(dest);}void study_use_mistakes(){    const u_char        *src = "hello, study_use_mistakes";size_t               src_len;u_char              *dest;size_t               dest_len;size_t               malloc_size;src_len = strlen(src);dest_len = src_len;//这里只分配元字符串大小的bytes空间dest = (u_char *)study_malloc(dest_len);//strcpy除了copy指定的字符串外,在结束时还会copy终止null字节//如果在分配空间时,只分配了dest_len长度个字节,通过valgrind检测时strcpy会报一个违法写1个字节操作//2013-10-31 再次重新理解如下://终止null字节没有空间写入,所以会报一个非法写1个字节操作的错误strcpy(dest, src);printf("src: %s\n", src);//由于strcpy没有将终止null字节写入到dest字符串中//所以这里在打印信息时,通过valgrind检测时,会报一个非法读一个字节操作//2013-10-31 再次重新理解如下://由于只有原字符串长度的空间,导致终止null字节没有成功写入,再读取dest时,自然会报一个非法读1个字节错误printf("dest: %s\n", dest);//由于最近遇到另外一种情况,简单描述一下://string copy,假设字符串长度为10,分配空间时分配11个字节,但是在copy时,只copy10个字节//在使用valgrind检测时,会报一个 “Conditional jump or move depends on uninitialised value(s)”错误//详见下边的补充代码//上述两个错误虽然不影响程序的正常执行,但是从程序逻辑的严谨性上来说,应该予以避免study_free(dest);//心得:/*1). 如果是纯粹的字符串复制,建议多分配一个字节,将终止null字符让程序自动加上2). 如果是多个字符串的拼接,除了最后一个字符串增加终止null字符以外,其他的都不要加3). 补充:malloc分配时,要多分配一个字节空间,使用strcpy拷贝字节时不需要处理,如果使用strncpy拷贝字符串时,n要设置为strlen + 1*/}u_char *strappend(u_char *dest, const u_char* append){size_t               append_len;size_t               size;size_t               src_len;void                *dest_new;size_t               dest_new_len;if(append == NULL){return NULL;}append_len = strlen(append);if(dest == NULL){size = append_len + 1;dest = (u_char *)study_malloc(size);if(dest == NULL){return NULL;}strcpy(dest, append);return dest;}src_len = strlen(dest);dest_new_len = src_len + append_len;size = dest_new_len + 1;printf("dest address: %d\n", dest);dest_new = realloc(dest, size);if(dest_new == NULL){return NULL;}printf("dest_new address: %d\n", dest_new);if(dest_new != dest){dest = dest_new;}else if(dest_new == dest){printf("dest_new equals dest\n");}strcpy(dest+src_len, append);return dest;}u_char *strappend2(u_char **dest, const u_char *append){void        *dest_ptr;void        *dest_new_ptr;size_t       src_len;size_t       append_len;size_t       dest_new_len;size_t       size;if(append == NULL){*dest = NULL;return NULL;}append_len = strlen(append);dest_ptr = *dest;if(dest_ptr == NULL){size = append_len + 1;dest_ptr = (u_char *)study_malloc(size);if(dest_ptr == NULL){*dest = NULL;return NULL;}strcpy(dest_ptr, append);*dest = dest_ptr;return dest_ptr;}src_len = strlen(dest_ptr);dest_new_len = src_len + append_len;size = dest_new_len + 1;printf("dest address: %d\n", dest_ptr);dest_new_ptr = realloc(dest_ptr, size);if(dest_new_ptr == NULL){return NULL;}printf("dest_new address: %d\n", dest_new_ptr);if(dest_new_ptr != dest_ptr){dest_ptr = dest_new_ptr;}else if(dest_new_ptr == dest_ptr){printf("dest_new equals dest\n");}strcpy(dest_ptr+src_len, append);*dest = dest_ptr;return dest_ptr;}



Makefile文件:

test:gcc -c main.c -g -o main.ogcc -o main main.orm -f *.oclean:rm -f *.o mainall:clean test


使用 valgrind检测命令:

valgrind --tool=memcheck --leak-check=full -q --show-possibly-lost=no main


以下是各个函数主要执行结果:


study_use_mistakes()函数执行,valgrind检测结果:

主要体会strcpy 和 strncpy使用前,malloc多分配一个字节用来存储 ‘\0’,避免出现非法写和非法读


心得:strcpy和strncpy使用

在使用strcpy函数时,如果是copy原始字符串到目标,在分配bytes空间时,要多分配一个,用来存储终止null字节 '\0'

否则在strcpy结束时,使用valgrind检测时,会报一个 非法写1个字节错误

同样在使用printf函数打印目标字符串时,会报一个非法读1个字节错误



=======================================================


study_strappend2(),使用valgrind执行结果:(无任何内存泄露)

主要体会realloc和指针的指针的使用



study_strappend(),valgrind中检测的结果:(存在内存泄露和非法free执行)




心得: malloc和realloc使用和指针的指针使用

其中定义了strappend函数用来对字符串进行append,完成字符串的附加功能

注意两个版本的不同 strappend()和strappend2()


定义了strappend2函数,来解决通过参数动态获取到更改指针的值

其中strappend和strappend2返回u_char *类型是为了在printf这样的函数中直接调用函数就能处理

但是需要注意:

strappend实现中,形参使用的是字符指针,如果没有返回值,则在调用端是不可能打印出字符串信息的


==================================================================



study_memory_leak(),存在10个字节的内存泄露


study_memory_leak2(),没有内存泄露



代码补充部分:

修改为红色标记部分,则代码使用valgrind检测时不会再有错误提示

#include <stdio.h>#include <stdlib.h>#include <string.h>#define LEN 12const u_char  *data = "lingyun test";size_t         len;u_char        *data_str;u_char         data_array[LEN];int main() {len = strlen(data);printf("data_str: %s\n", data_str);printf("data_array: %s\n", data_array);data_str = malloc(len);//malloc时多分配1个字节可以解决//data_str = malloc(len + 1);strcpy(data_str, data);printf("data_str: %s\n", data_str);free(data_str);data_str = malloc(len+1);strncpy(data_str, data, len);//使用strncpy时,n设置为strlen+1可以解决//strncpy(data_str, data, len+1);printf("data_str: %s\n", data_str);free(data_str);strcpy(data_array, data);printf("data_array: %s\n", data_array);strncpy(data_array, data, len);printf("data_array: %s\n", data_array);return 0;}



valgrind具体报错如下:




原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 太辣了辣得胃疼怎么办 出现连接问题或mmi码无效怎么办 存折丢了怎么办卡号也不记得了 车内皮子被烂苹果腐蚀有印怎么办 锅被腐蚀后变黑色应该怎么办 后厨炉灶里的炉芯进水了怎么办 小儿九个月老是流黄鼻子该怎么办 肉炖的老了不烂怎么办 吃了凉东西现在一直打嗝应该怎么办 喝了很多水还是觉得口渴怎么办 刚买的猪肝没洗直接炒了怎么办 四个多月的宝宝吃了脏东西怎么办 狗吃了脏东西拉稀呕吐怎么办 五个月宝宝怕吃药导致奶不喝怎么办 蒸锅锅盖吸住了怎么办锅比锅盖要大 豇豆没熟孕妇吃了中毒怎么办 孩子积食拉不出粑粑憋的直哭怎么办 2岁宝宝总是半夜拉粑粑怎么办 金毛拉很臭的稀粑粑怎么办 点餐系统登录后没有菜单怎么办? 环亚在线微交易亏了钱怎么办 钢管舞报了教练班觉得学不会怎么办 微信上聊天被外国人给骗了该怎么办 微信冒充朋友骗走我钱怎么办 凉皮调料水鸡精味精放多了怎么办 吃了地屈孕酮后月经不干不净怎么办 藕片用热水炒后变色了怎么办? 外汇延期收款忘了报告了怎么办 怀孕不小心吃了马生菜怎么办 高压锅的皮圈很容易坏是怎么办 华为应用市场账号密码忘记了怎么办 业主对我们提出批评意见时怎么办 向环保局投诉被公司发现了怎么办 在政务大厅上班被群众投诉怎么办 政府下发的文件通知不履行该怎么办 给私人老板开车不给工资怎么办 给个体老板开车不给工资怎么办 户口转走在人才市场的档案怎么办 外来媳妇转上海户口没有档案怎么办 公务员考试笔试差9分面试怎么办 想从事人事方面的工作没经验怎么办