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

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

 
阅读更多
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 中都引用了,但在内存中却只有一份拷贝,这与静态变量性质相当神似。

分享到:
评论

相关推荐

    第5讲 指针高级之指针数组-将若干字符串按字母顺序(由小到大)输出

    这里,`strArray` 是一个包含5个元素的指针数组,每个元素都指向一个字符串常量。 接下来,我们要对这个指针数组进行排序,但注意,我们并不直接排序字符串本身,而是排序这些指针。这是因为字符串在内存中通常是不...

    C语言程序设计标准教程

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

    2021年C语言选择题库.docx

    C语言选择题库 以下是根据给定的文件信息,生成的相关知识点: 1.C语言程序的组成部分:C语言程序是由主程序...这些知识点涵盖了C语言的基本概念、数据类型、运算符、控制结构、函数、数组、指针、字符串操作等方面。

    10-指针(二)-自己使用的C语言教程PPT-适合老师备课或者自学.pptx

    在C语言中,如果一个数组的元素都是指针类型,则称之为指针数组。指针数组定义的形式为:类型名 *数组名[常量表达式];例如:int *a[5] ;表示指针数组a的每个元素都是指向int型变量的指针变量。指针数组的主要用于...

    C指针详解

    函数返回指针也是常见的做法,如动态内存分配函数`malloc()`和`calloc()`返回指向新分配内存的指针。 八、指针与字符串 C语言中的字符串是以空字符`\0`结尾的字符数组,可以使用`char *`指针来处理字符串。`strtok...

    c语言上机考试题201012(答案).pdf

    文档显示了两个main函数的定义,一个返回void,另一个没有返回值类型定义,这不符合C99标准,应该明确指出返回类型为int。 ```c void main() { // ... } ``` 3. 输入输出函数 使用`printf`和`scanf`函数进行数据的...

    C++词汇

    C++词汇 C++中,保留字也称关键字,它是预先定义好的标识符。关键字是C++中已经被系统定义为特殊含义的一类标识符。C++中的关键字有autodoubleintstruct ...字符串是标准库中的一种数据类型,一般用于表示一串字符。

    j二级C语言PPT教案.pptx

    - **传地址方式**:形参可以是数组名或指针变量,实参可以是数组名、指针变量、字符串常量或指定单元的起始地址。这种方式允许函数修改实参的值,实现数据的双向传递。 3. **函数调用的一致性**:调用函数时,实参...

    重庆大学C语言程序设计复习题及参考答案

    10. 字符串输入:gets函数用于从标准输入读取字符串,可以为字符数组(如a或s1)输入数据,但不能为未初始化的指针(如s2)输入数据。scanf函数可以为s1和s2输入数据,但对s2需要先进行初始化。 11. 位操作符的等价...

    C语言常见笔试题及答案

    `"\n"`与`'\n'`的区别在于前者是字符串常量,包含一个换行符;而后者是字符常量,代表单个换行字符。此题考察了字符串和字符常量的表示方法,以及转义序列在C语言中的应用。 #### 题目八:预处理指令`#include`的...

    C程序设计第三版答案_航院_考试题库

    通过指针,可以间接访问和修改变量,实现动态内存分配、数组和字符串操作等功能。理解指针的使用对于深入掌握C语言至关重要,但同时也需要小心,不当的指针操作可能会导致程序崩溃或安全漏洞。 ### 预处理 预...

    C++程序设计模拟试卷.pdf

    选项D错误,因为它尝试用字符串("AB"和"CD")作为参数,字符串不是基本数据类型,它们的加法操作不是简单的数值相加,而是字符串连接,所以这不是正确的使用方式。 在多态性方面,第5题指出,如果类B是类A的公有...

    C语言复习总结(20211006122808).pdf

    常量包括整型、字符型、实型、字符串和符号常量,而变量则根据数据类型分为不同类别,如整型变量(有符号、无符号、短整型、长整型)和实型变量(单精度、双精度)。变量在内存中占用相应字节数。 总结来说,C语言...

    Python源码剖析笔记

    指针的易错点通常发生在对只读数据段的写操作,例如尝试修改一个字符串常量。另外,函数中传入指针参数后,需要注意不要改变其指向,除非在函数内部做好相应的内存管理。在C语言中,指针的内存管理非常关键,比如...

    C语言符号意思.docx

    在C语言中,还有多种常量类型,包括整数、长整数、无符号数、浮点数、字符、字符串、符号常数、转义字符等。 数据类型转换可以分为自动转换和强制转换两种。自动转换是在不同类型数据的混合运算中,由系统自动实现...

    谭浩强c语言程序设计(txt格式的)

    - 字符串的处理函数,如字符串连接、比较等。 **3.6 指针** - 指针是一种特殊类型的变量,它保存的是另一个变量的地址。 - 指针的声明、赋值、解引用等基本操作。 **3.7 指针与数组** - 数组名实际上是一个指向...

    计算机基础与程序设计简答.pdf

    第二章 字符串和符号常量 1. 字符串的存储:储存字符串ˋX ˊ 占用 2 个字节,储存字符ˋX ˊ 只要一个字节。 2. 布尔值表示:非 0 代表真,0 代表假。 3. 符号常量的定义形式:#define 符号常量标识符常量 第三章...

Global site tag (gtag.js) - Google Analytics