前段时间看了一个面试题,程序找错误:
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';//不能修改指针定义的字符串内容。