一段内存申请分配代码笔试题的分析

请问下列代码运行错误的原因是什么,怎么修改?

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;
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值