C语言:函数堆内存分配问题剖析

使用的编辑器:visual studio 2013

下面两段代码test1和test2,test1是对数组进行了初始化,而test2没有定义长度:

#include <stdio.h>
#include <string.h>
void test1();
void test2();
void main() {
	test1();
	test2();
}
void test1(){
	char s[11] = "wgwe123";
	char s2[11] = "";
	strcpy(s2, s);
	//strcpy_s(s2,strlen(s)+1 ,s);
	int i = 0;
	for (int j = 0; j < strlen(s2); j++){
		printf("s[%d] = %c,length = %d\n", j, s2[j], strlen(s2));
	}
	printf("*****************************\n");
	while (s[i] !='\0'){
		printf("s[%d] = %c,length = %d\n", i, s[i],strlen(s));
		++i;
	}
	printf("s2 = %s,length = %d\n", s2,strlen(s2));
}
void test2(){
	char s[11] = "wgwe123";
	char s2[] = "";
	strcpy(s2, s);
	//strcpy_s(s2,strlen(s)+1 ,s);
	int i = 0;
	for (int j = 0; j < strlen(s2); j++){
		printf("s[%d] = %c,length = %d\n", j, s2[j], strlen(s2));
	}
	printf("*****************************\n");
	while (s[i] !='\0'){
		printf("s[%d] = %c,length = %d\n", i, s[i],strlen(s));
		++i;
	}
	printf("s2 = %s,length = %d\n", s2,strlen(s2));
}

然而,test1和test2的运行结果和想象的完全不一样(test1是进行了数组的初始化,而test2没有)test1的结果是:

s2[0] = w,length = 7
s2[1] = g,length = 7
s2[2] = w,length = 7
s2[3] = e,length = 7
s2[4] = 1,length = 7
s2[5] = 2,length = 7
s2[6] = 3,length = 7
**************************
s[0] = w,length = 7
s[1] = g,length = 7
s[2] = w,length = 7
s[3] = e,length = 7
s[4] = 1,length = 7
s[5] = 2,length = 7
s[6] = 3,length = 7
s2 = wgwe123,length = 7

test2的结果是:

s2[0] = w,length = 7
s2[1] = g,length = 7
s2[2] = w,length = 7
s2[3] = e,length = 7
s2[4] = 1,length = 7
s2[5] = 2,length = 7
s2[6] = 3,length = 7
************************
s[0] = g,length = 6
s[1] = w,length = 6
s[2] = e,length = 6
s[3] = 1,length = 6
s[4] = 2,length = 6
s[5] = 3,length = 6
s2 = wgwe123,length = 7

显然test1的结果是正确的,test2的结果是错误的,是因为s2数组初始化没有设置长度(当然这本身就是不对的)

问题是:输出的结果:s2也成功被复制了,s 的内容却发生了变化,为什么初始数组会发生变化呢再来:

void test3(){
	char s[11] = "wgwe123";
	char s2[] = "aaa";
	strcpy(s2, s);
	//strcpy_s(s2,strlen(s)+1 ,s);
	int i = 0;
	for (int j = 0; j < strlen(s2); j++){
		printf("s[%d] = %c,length = %d\n", j, s2[j], strlen(s2));
	}
	printf("*****************************\n");
	while (s[i] !='\0'){
		printf("s[%d] = %c,length = %d\n", i, s[i],strlen(s));
		++i;
	}
	printf("s2 = %s,length = %d\n", s2,strlen(s2));
}

结果是:

s2[0] = w,length = 7
s2[1] = g,length = 7
s2[2] = w,length = 7
s2[3] = e,length = 7
s2[4] = 1,length = 7
s2[5] = 2,length = 7
s2[6] = 3,length = 7
************************
s[0] = 1,length = 3
s[1] = 2,length = 3
s[2] = 3,length = 3
s2 = wgwe123,length = 7

s2被赋值成功了,s变成了123,查看strcpy的源码:

char * strcpy(char *dst,const char *src)  
{
    assert(dst != NULL && src != NULL);   
    char *ret = dst;  
    while ((*dst++=*src++)!='\0');
    return ret;
}

源码是没问题的,那就考虑内存占用问题了,实际上,如果没有对s2进行初始化,那么s2系统只给他分配了一个字节的空间保存数组的\0,那么对s2进行拷贝的时候,很有可能会把s的内存空间占用,而如果s2开始就分配了内存的话这种情况是不存在的。打印内存如下:

拷贝前:s 地址为: 8ffe84, s2 地址为: 8ffe83

拷贝后:s 地址为: 8ffe84, s2 地址为: 8ffe83

s2的首地址分配是在s前面的,所以对s2进行赋值的时候,s1的内存必然会被占用,果然刚好占用了一个字节,如下图所示:

当对s2进行拷贝的时候,s的内存被占用,如下图所示:

因此,输出的s从首地址8ffe84开始到'\0'结束,为:gwe123

s2的从首地址8ffe83开始到'\0'结束,为:wgwe123

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值