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具体报错如下:
- strcpy, strncpy, malloc, realloc以及memory leak等注意问题
- malloc、calloc、realloc注意点
- strcpy与memcpy以及strncpy
- strcpy与memcpy以及strncpy
- strcpy与memcpy以及strncpy
- strcpy与memcpy以及strncpy
- 解决memory leak问题
- 解决memory leak问题
- strcpy/strncpy/strcat/strlen等源码
- strcpy()的注意事项以及strncpy()的用处
- 解决memory leak问题
- 内存空间分配,以及malloc、calloc、realloc、alloca、realloc的区别
- realloc、malloc、以及calloc函数的区别
- realloc、malloc、以及calloc函数的区别
- strcpy & strncpy
- Strcpy / Strncpy
- strcpy(),strncpy()
- strcpy & strncpy
- uva 11796 - Dog Distance(投影位移)
- 技巧-MAC下隐藏Dock栏正在运行中的软件图标
- STL中map的用法
- 并发和并行的区别
- Memcached高速缓存服务器部署及应用(三、php+memcached缓存技术实例 )
- strcpy, strncpy, malloc, realloc以及memory leak等注意问题
- Parse samsung s3 camera apk
- 大学生活的成败
- windows CA :由于吊销服务器已脱机,吊销功能无法检查吊销。
- 解决Toast重复弹出,Toast单例模式
- NYOJ 275题 对花的烦恼一
- flex 中展开所有子节点
- Java RMI
- [Android实例] 判断网络是否连接,然后选择网络类型(比如wifi等)来连接网络