C++系列之-----字符串变量的内存分布

本文探讨C++中字符串变量在内存中的分布,解释常量字符串存储在静态数据区,但拷贝到局部数组后随数组释放。通过示例展示了堆、栈和静态数据区的区别,并强调动态内存分配后的释放问题。同时,对比了字符数组和字符指针的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间看了一个面试题,程序找错误:

char *str()
{
	char p[] = "hello world!";
	return p;
}

以前一直把数组名和指针看作一个东西,况且指针指向的是常量字符串,常量字符串保存在内存的静态数据区,函数结束不会释放的,错误认为,此程序没有错误,可以正确返回字符串。

在vc 6.0中编译运行时,输出的是乱码。

度娘了一把,现在把这个过程理顺清楚了,陈述如下:

常量字符串确实保存在内存的静态数据区,函数结束时不会释放。但是,此函数中的常量字符串赋值给了一个局部数组,函数结束时,数组释放,于是不能得到函数返回值。常量字符串一份保存在静态数据区,一份被拷贝到局部数组中。

引起我迷惑的地方主要在:字符数组名不能简单看作就是字符指针。

为了使此函数正常运行,可以做如下两种修改:

static char *str()
{
	static char p[] = "hello world!";
	return p;
}//静态数组保存在内存的静态数据区,函数结束不会释放
char *str()
{
      char *p = "hello world!";
      return p;
}//返回的是指针的值,也就是静态数据区中字符串的地址,函数结束不会释放


为了验证常量字符串的内存位置,写程序如下:

#include <iostream>
using namespace std;

char *text5 = "hello world!";

int main()
{
	char *text1 = "hello world!";
	char text2[] = "hello world!";
	char *text3 = "hello world!";
	static char *text4 = "hello world!";

	cout << &text1 << "     " << static_cast<void *>(text1) << "         " << text1 << endl;
	cout << &text2 << "     " << static_cast<void *>(text2) << "         " << text2 << endl;
	cout << &text3 << "     " << static_cast<void *>(text3) << "         " << text3 << endl;
	cout << &text4 << "     " << static_cast<void *>(text4) << "         " << text4 << endl;
	cout << &text5 << "     " << static_cast<void *>(text5) << "         " << text5 << endl;
	
	return 0;
}

结果截图:



从图中可以看到,常量字符串,只要内容一样,均存于同一块内存位置,静态变量和全局变量均存于静态数据区,局部变量存于栈。


除了静态数据区和栈内存,还有一种内存位置—堆,用于存放动态数据。

char *p = new char[10];//此时,10个字符被分配到堆内存,p依然是存于栈内存的指针变量

使用堆内存时,在使用完毕后,一定记得释放,否则会造成内存泄露,切记!!


程序中各种变量在堆内存,栈内存和静态数据区的分布:

#include <stdio.h>
#include <malloc.h>
int g_i = 100;
int g_j = 200;
int g_k, g_h;
int main()
{
	const int MAXN = 100;
	int *p = (int*)malloc(MAXN * sizeof(int));
	static int s_i = 5;
	static int s_j = 10;
	static int s_k;
	static int s_h;
	int i = 5;
	int j = 10;
	int k = 20;
	int f, h;
	char *pstr1 = "MoreWindows123456789";
	char *pstr2 = "MoreWindows123456789";
	char *pstr3 = "Hello";
	
	
	printf("堆中数据地址:0x%08x\n", p);
	
	putchar('\n');
	printf("栈中数据地址(有初值):0x%08x = %d\n", &i, i);
	printf("栈中数据地址(有初值):0x%08x = %d\n", &j, j);
	printf("栈中数据地址(有初值):0x%08x = %d\n", &k, k);
	printf("栈中数据地址(无初值):0x%08x = %d\n", &f, f);
	printf("栈中数据地址(无初值):0x%08x = %d\n", &h, h);
	
	putchar('\n');
	printf("静态数据地址(有初值):0x%08x = %d\n", &s_i, s_i);
	printf("静态数据地址(有初值):0x%08x = %d\n", &s_j, s_j);
	printf("静态数据地址(无初值):0x%08x = %d\n", &s_k, s_k);
	printf("静态数据地址(无初值):0x%08x = %d\n", &s_h, s_h);
	
	putchar('\n');
	printf("全局数据地址(有初值):0x%08x = %d\n", &g_i, g_i);
	printf("全局数据地址(有初值):0x%08x = %d\n", &g_j, g_j);
	printf("全局数据地址(无初值):0x%08x = %d\n", &g_k, g_k);
	printf("全局数据地址(无初值):0x%08x = %d\n", &g_h, g_h);
	
	putchar('\n');
	printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr1, pstr1, pstr1);
	printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr2, pstr2, pstr2);
	printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr3, pstr3, pstr3);
	free(p);
	return 0;
}

结果截图:

由以上结果可以看出,堆数据占一块内存,栈数据占一块内存,全局数据和静态数据(已初始化的挨在一起,未初始化的挨在一起)占一块内存。

ps:常量数据的位置貌似不在静态数据区,是单独的一块内存(这个不确定,以后再验证)

字符数组和字符指针简单辨析:

1. 指针可以通过加减、自加减改变其值,数组不可以;

2. 以数组定义的字符串可以修改其中的字符,以指针定义的字符串不能修改其中的字符。

例子:

char p[] = "hello world!";
cout << *p++;//数组名是常量,不能改变其值

char *p = "hello world!";
*p = 'H';//不能修改指针定义的字符串内容。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值