请问下列代码运行错误的原因是什么,怎么修改?
void get_memory(char *p, int num) {
p = (char *)malloc(sizeof(char) * num);
}
void test_memory_malloc(void) {
char *str = NULL;
get_memory(str, 100);
// str 仍然为 NULL
strcpy(str, "hello"); // 运行错误
}
分析:
实际运行
get_memory函数的第一个参数传的是指针地址,这种方式只能修改指针所对应的地址上的内容,不能修改地址,所以str作为参数调用GetMemory后,str这个地址不会发生改变,依然是初值NULL.
要实现这个功能,我们可以用两种方式:
1、将参数char* p修改为char* *p, 这样可以修改*p的值,
void get_memory(char** p, int num) {
*p = (char *)malloc(sizeof(char) * num);
}
2、 以返回值 的方式返回指针地址。
char* get_memory(int num) {
char * p = NULL;
*p = (char *)malloc(sizeof(char) * num);
return p;
}
两种方式都可以的.
为了后面更深入的分析,我们选用第一种方式。
void get_memory(char** p, int num) {
*p = (char *)malloc(sizeof(char) * num);
}
void test_memory_malloc(void) {
char *str = NULL;
get_memory(&str, 100);
strcpy(str, "hello");
}
我们来看这份代码,功能能实现,但是我们再想一想还有没有其他可能出现的问题。。。。。。
个人觉得从安全还有以下几点需要优化:
1、get_memory函数需要判断入参
1) 需要判断p是否为空,否则 *p 会异常
2)需要判断num是否为非正数,如果小于或等于0,那么就不应该调用malloc, 当然这里还要注意一点,若num为无符号数,那就要判断一个大小范围,否则传一个负数时会变成一个很大的正数,申请一个很大的空间,可能申请失败,也可能导致系统内存变得很小。
从上面两点,这里可以改为:
#define MAX_MEMORY 0x100000
void get_memory(char** p, int num) {
if( (p == NULL) || (num <= 0) || (num >= MAX_MEMORY)) {
printf("param fail!\n");
return 1;
}
*p = (char *)malloc(sizeof(char) * num);
}
2、申请空间后,一定要做判断,是否申请成功,并进行初始化,修改为:
int get_memory(char** p, int num) {
if( (p == NULL) || (num <= 0) || (num >= MAX_MEMORY)) {
printf("param fail!\n");
return 1;
}
*p = (char *)malloc(sizeof(char) * num);
if( *p == NULL) {
printf("malloc faile\n");
return 1;
}
(void)memset(*p, 0, sizeof(char) * num);
return 0;
}
返回值0,或1可以用宏表示。
3、对strcpy使用str需要判断str 是否为空。也就是是否申请是否成功,
可修改为
if( str == NULL)
retrun;
strcpy(str,"hello");
4、使用strcpy拷贝字符串,要判断拷贝是否越界,如果申请的空间小于要拷贝的内容,会导致str所指的字符串没有终止符'\0',方法有:
1) 将最后一个字节强制加上'\0'
strcpy(str, "hello");
str[99] = '\0';
这种并不靠谱,可能会踩了str空间后面的内存。
2)使用 strncpy_s安全函数,设置拷贝大小。
strncpy_s(str, 100 -1 , "hello", 5);
5、malloc动态申请的内容一定要记得释放,否则会导致内存泄漏以及野指针,所以最后要加上:
if(str != NULL) {
free(str);
str = NULL;
}
6、优化魔鬼数字等。
从以上几个方面,修改后的代码,仅作参考:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX_MEMORY 0x100000
#define MALLOC_MEMORY 100
#define OK 0
#define ERROR 1
static int get_memory(char** p, int num) {
if ((p == NULL) || (num <= 0) || (num >= MAX_MEMORY)) {
printf("param fail!\n");
return ERROR;
}
*p = (char *)malloc(sizeof(char) * num);
if (*p == NULL) {
printf("malloc faile\n");
return ERROR;
}
(void)memset(*p, 0, sizeof(char) * num);
return OK;
}
void test_memory_malloc(void) {
char *str = NULL;
int ret = 0;
char info[] = "hello";
ret = get_memory(&str, MALLOC_MEMORY);
if((ret != OK) || (str == NULL)) {
printf("test fail %d\n", ret);
return;
}
(void)strncpy_s(str, MALLOC_MEMORY - 1, info, strlen(info));
printf("print info: %s\n", str);
if (str != NULL) {
free(str);
str = NULL;
}
}