以下函数返回的指针是否不可访问?
char *foo(int rc)
{
switch (rc)
{
case 1:
return("one");
case 2:
return("two");
default:
return("whatever");
}
}
因此,C / C ++中局部变量的生存期实际上仅在函数内,对吗?这意味着char* foo(int)
终止后,它返回的指针不再意味着什么,对吧?
我对局部变量的生存期有些困惑。什么是好的澄清?
是,局部变量的生存期在创建它的范围({
,}
)内。
局部变量具有自动或局部存储。 自动,因为一旦创建范围终止,它们就会被自动销毁。
但是,您这里拥有的是字符串文字,它在实现定义的只读内存中分配。字符串文字与局部变量不同,它们在程序的整个生命周期中都保持有效。它们的寿命为[[静态持续时间 [参考1]。
小心点!
但是,请注意,任何试图修改字符串文字内容的尝试都是undefined behavior(UB)。用户程序不允许修改字符串文字的内容。因此,始终建议在声明字符串文字时使用const
。 const char*p = "string";
而不是
char*p = "string";
实际上,在C ++中,不建议在不使用const
的情况下声明字符串文字,但在C语言中则不建议使用。但是,使用const
声明字符串文字可为您带来的好处是,编译器通常会在出现警告时提供警告您尝试在第二种情况下修改字符串文字。
#include<string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[]="Sample string";
strcpy(str1,source); // No warning or error just Uundefined Behavior
strcpy(str2,source); // Compiler issues a warning
return 0;
}
输出:
cc1:警告被视为错误prog.c:在“ main”函数中:prog.c:9:错误:传递“ strcpy”的参数1会从指针目标类型中丢弃限定符
注意,编译器会针对第二种情况发出警告,但不会针对第一种情况发出警告。
整数值处理什么?
换句话说,以下代码有效吗?int *foo()
{
return &(2);
}
答案是,没有此代码无效。格式不正确,会导致编译器错误。类似:
prog.c:3: error: lvalue required as unary ‘&’ operand
字符串文字是l值,即:您可以使用字符串文字的地址,但不能更改其内容。但是,任何其他文字(C99标准6.4.5 / 5“字符串文字-语义”:int
,float
,char
等)都是r值(C标准对此使用术语表达式的值),并且不能采用其地址完全没有
[Ref 1]
在翻译阶段7中,一个或多个字符串文字产生的每个多字节字符序列都附加一个零值的字节或代码。。对于字符串文字,数组元素的类型为char,并使用多字节字符序列的各个字节进行初始化。对于宽字符串文字,数组元素的类型为wchar_t,并使用宽字符序列进行初始化...不确定这些数组是否不同,只要它们的元素具有适当的值。然后将多字节字符序列用于初始化一个足以包含序列的静态存储持续时间和长度数组
如果程序尝试修改这样的数组,则行为未定义
。对于C,这是第6.4.5节第6段规定的:
在翻译阶段7中,一个或多个字符串文字产生的每个多字节字符序列都附加一个零值的字节或代码。然后使用多字节字符序列对于C ++,在第2.14.5节,第8-11段:初始化静态存储持续时间数组和长度足以容纳该序列的长度。
8普通字符串文字和UTF-8字符串文字也称为窄字符串文字。窄字符串文字的类型为“数组nconst char
”,其中n是如下定义的字符串的大小,并且具有静态存储持续时间(3.7)。9以u开头的字符串文字,例如
u"asdf"
,是char16_t
字符串文字。char16_t
字符串文字的类型为“ nconst char16_t
的数组”,其中n是如下定义的字符串的大小;它具有静态存储期限,并使用给定的字符进行初始化。一个c-char可能以代理对的形式产生多个char16_t
字符。10以U开头的字符串文字,例如
U"asdf"
,是char32_t
字符串文字。char32_t
字符串文字的类型为“ nconst char32_t
的数组”,其中n是如下定义的字符串的大小;它具有静态存储期限,并使用给定的字符进行初始化。11以L开头的字符串文字,例如
L"asdf"
是宽字符串文字。宽字符串文字的类型为“ nconst wchar_t
的数组”,其中n是如下定义的字符串的大小;它具有静态存储期限,并使用给定的字符进行初始化。
此外,字符串文字是只读的,因此(为了良好的风格,也许您应该将foo
更改为const char *foo(int)
const char*
为字符串文字。不能修改,一定不能被调用者释放。由于下面描述的释放问题,对于返回默认值非常有用。如果您实际上需要在某个地方传递函数指针,那么这可能很有意义,因此您需要一个返回字符串的函数。]char*
或const char*
到静态字符缓冲区。一定不能被呼叫者释放。可以修改(可以由调用方(如果不是const的话),也可以由返回它的函数)进行修改,但是返回此函数的函数不能(轻松地)具有多个缓冲区,因此(轻松地)线程安全,并且调用方可能需要复制返回的内容值,然后再次调用该函数。char*
分配给malloc
的缓冲区。可以修改,但通常必须由调用方显式释放,并且具有堆分配开销。 strdup
是这种类型。const char*
或char*
到缓冲区,该缓冲区作为参数传递给函数(返回的指针无需指向参数缓冲区的第一个元素)。将缓冲区/内存管理的职责留给调用者。许多标准的字符串函数都属于这种类型。一个问题是,将它们混合在一个函数中会变得很复杂。调用方需要知道如何处理返回的指针,有效期多长,以及调用方是否应该释放它,并且没有(好的)方法在运行时确定该指针。因此,例如,您无法拥有一个函数,该函数有时返回指向调用者需要free
的堆分配缓冲区的指针,有时返回指向字符串文字的默认值的指针,调用者必须
not free
。
这是C的一个相当方便的功能,不是吗?它允许函数返回预先编写的消息,而不必强迫程序员担心消息存储在的内存中。
另请参见@asaelr的正确观察const
。
Because it points to static address
字符串文字所在的位置。程序加载时主要是readonly
和global
。即使您尝试释放或修改,它也会抛出segmentation fault
在具有内存保护的平台上