`
yangyou230
  • 浏览: 1647903 次
文章分类
社区版块
存档分类

函数的返回类型为指针类型时的若干思考(字符串常量问题)

 
阅读更多
By zieckey (http://blog.chinaunix.net/u/16292/index.html)
问题的引入:
看看下面的程序的输出:

#include<stdio.h>
char*returnStr()
{
char*p="hello world!";
returnp;
}
intmain()
{
char*str;
str=returnStr();
printf("%s\n",str);

return0;
}


这个没有任何问题,因为"hello world!"是一个字符串常量,存放在静态数据区,
把该字符串常量存放的静态数据区的首地址赋值给了指针,
所以returnStr函数退出时,该该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。

但是,下面的就有问题:

#include<stdio.h>
char*returnStr()
{
charp[]="hello world!";
returnp;
}
intmain()
{
char*str;
str=returnStr();
printf("%s\n",str);

return0;
}

"hello world!"是一个字符串常量,存放在静态数据区,没错,
但是把一个字符串常量赋值给了一个局部变量(char []型数组),该局部变量存放在栈中,
这样就有两块内容一样的内存,也就是说“charp[]="hello world!";”这条语句让“hello world!”这个字符串在内存中有两份拷贝,一份在动态分配的栈中,另一份在静态存储区。这是与前着最本质的区别,
当returnStr函数退出时,栈要清空,局部变量的内存也被清空了,
所以这时的函数返回的是一个已被释放的内存地址,所以打印出来的是乱码。

如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型。如下:

#include<stdio.h>
char*returnStr()
{
staticcharp[]="hello world!";
returnp;
}
intmain()
{
char*str;
str=returnStr();
printf("%s\n",str);

return0;
}


这个问题可以通过下面的一个例子来更好的说明:

#include<stdio.h>
//返回的是局部变量的地址,该地址位于动态数据区,栈里

char *s1()
{
char* p1 = "qqq";//为了测试‘
char p[]="Hello world!"’中的字符串在静态存储区是否也有一份拷贝
char p[]="Hello world!";
char* p2 = "w";
//为了测试‘char p[]="Hello world!"’中的字符串在静态存储区是否也有一份拷贝
printf("in s1 p=%p\n", p);
printf("in s1 p1=%p\n", p1);
printf("in s1: string's address: %p\n", &("Hello world!"));
printf("in s1 p2=%p\n", p2);
return p;
}


//返回的是字符串常量的地址,该地址位于静态数据区

char*s2()
{
char*q="Hello world!";
printf("in s2 q=%p\n",q);
printf("in s2: string's address: %p\n",&("Hello world!"));
returnq;
}

//返回的是静态局部变量的地址,该地址位于静态数据区

char*s3()
{
staticcharr[]="Hello world!";
printf("in s3 r=%p\n",r);
printf("in s3: string's address: %p\n",&("Hello world!"));
returnr;
}

intmain()
{
char*t1,*t2,*t3;
t1=s1();
t2=s2();
t3=s3();

printf("in main:");
printf("p=%p, q=%p, r=%p\n",t1,t2,t3);

printf("%s\n",t1);
printf("%s\n",t2);
printf("%s\n",t3);

return0;
}

运行输出结果:

in s1 p=0013FF0C
in s1 p1=00431084
in s1: string's address: 00431074
in s1 p2=00431070
in s2 q=00431074
in s2: string's address: 00431074
in s3 r=00434DC0
in s3: string's address: 00431074
in main:p=0013FF0C, q=00431074, r=00434DC0
$?
Hello world!
Hello world!


这个结果正好应证了上面解释,同时,还可是得出一个结论:
字符串常量,之所以称之为常量,因为它可一看作是一个没有命名的字符串且为常量,存放在静态数据区。
这里说的静态数据区,是相对于堆、栈等动态数据区而言的。
静态数据区存放的是全局变量和静态变量,从这一点上来说,字符串常量又可以称之为一个无名的静态变量,
因为"Hello world!"这个字符串在函数 s1和s2 中都引用了,但在内存中却只有一份拷贝,这与静态变量性质相当神似。

分享到:
评论

相关推荐

    C语言程序设计标准教程

     本程序中用赋值语句给num和name两个成员赋值,name是一个字符串指针变量。用scanf函数动态地输入sex和score成员值,然后把boy1的所有成员的值整体赋予boy2。最后分别输出boy2 的各个成员值。本例表示了结构变量的...

    c程序设计习题参考(谭浩强三版)习题参考解答

    3.5字符常量和字符串常量有什么区别? 3 3.6写出以下程序运行的结果: 3 3.7要将“China”译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。例如,字母“A”后面第4个字母是“E”,用“E”代替...

    c语言经典案例

    实例185 将若干字符串按照字母 顺序输出 262 实例186 用指向函数的指针比较大小 263 实例187 寻找指定元素的指针 265 实例188 字符串的匹配 266 第12章 常用数据结构 269 实例189 比较计数 270 实例190 找出最高分 ...

    javascript高级教程

     变量有它的类型,上例中myVariable的类型为string(字符串)  javascript支持的常用类型还有:  number:数(包括浮点数);  boolean:布尔值,只有true和false两个值,是所有类型中占用内存最少的;  null:...

    语言程序设计课后习题答案

    const定义的常量是有类型的,所以在使用它们时编译器可以查错;而且,这些变量在调试时仍然是可见的。 2-5 请写出C++语句声明一个常量PI,值为3.1416;再声明一个浮点型变量a,把PI的值赋给a。 解: const float PI...

    Excel VBA实用技巧大全 附书源码

    04142设置单元格字符串中一部分字符的格式(其他字体属性) 04143设置单元格的下画线 04144设置单元格的字体属性(字体、字号、加粗、斜体、颜色等) 04145设置单元格区域的外部边框 04146设置单元格区域的全部边框 ...

    c++ 面试题 总结

    一个指向char类型的const对象指针,p不是常量,我们可以修改p的值,使其指向不同的char,但是不能改变它指向非char对象,如: const char *p; char c1='a'; char c2='b'; p=&c1;//ok p=&c2;//ok *p=c1;//error (2)...

    最新软件狗时间复制工具

    为此,“蓝芯金盾加密锁”采用了源程序级加密,此方法不是去判断某个值、某个字符串或数据是否正确,而是时时变化输入参数,在任何时刻没有两个相同的数据出现。 自定义算法加密锁 现在市场上还提供一种开发者可...

Global site tag (gtag.js) - Google Analytics