你声明了一个指向字符串字面值(它们的第一个字符)的指针数组。
你声明了一个指向字符串字面值(它们的第一个字符)的指针数组
char *name[] = {"Invalid name", "Jan.", "Feb", "Mar", "Apr", "May", "June",
"July", "Aug", "Sep", "Oct", "Nov", "Dec"};
字符串字面值具有静态存储期,也就是说,在函数退出后它们仍然存在。
例如,在 C 标准(6.4.5 字符串字面值)中写道:
6 在第 7 翻译阶段,对于由一个或多个字符串字面值组成的每个多字节字符序列,都会添加一个值为零的字节或代码。78) 然后使用这些多字节字符序列初始化一个具有静态存储期的数组,该数组的长度刚好足以容纳这个序列....
另一方面,数组本身具有自动存储期,也就是说在函数退出后不再存在。但是该函数返回一个指向字符串字面值的指针,而不是指向数组本身的指针。
如果尝试返回指向数组本身的指针,则该函数将出现错误,例如:
char * ( *month_name(int n) )[13] {
char *name[] = {"Invalid name", "Jan.", "Feb", "Mar", "Apr", "May", "June",
"July", "Aug", "Sep", "Oct", "Nov", "Dec"};
//...
return &name;
}
或使用以下方式
char ** month_name(int n) {
char * name[] = {"Invalid name", "Jan.", "Feb", "Mar", "Apr", "May", "June",
"July", "Aug", "Sep", "Oct", "Nov", "Dec"};
return n < 1 || n > 12 ? name : name + n;
}
或者,如果您想声明一个二维数组,可按如下方式:
char *month_name(int n) {
char name[][13] = {"Invalid name", "Jan.", "Feb", "Mar", "Apr", "May", "June",
"July", "Aug", "Sep", "Oct", "Nov", "Dec"};
return n < 1 || n > 12 ? name[0] : name[n];
}
那么在这种情况下,返回语句
return n < 1 || n > 12 ? name[0] : name[n];
由于数组本身在退出函数后不会存在,因此确实会出现未定义的行为。
请注意,在C++中,与C相反,字符串字面值具有常量字符数组的类型。因此,要将您的函数编译为C ++代码,您必须按照以下方式定义该函数。
const char *month_name(int n) {
const char *name[] = {"Invalid name", "Jan.", "Feb", "Mar", "Apr", "May", "June",
"July", "Aug", "Sep", "Oct", "Nov", "Dec"};
return n < 1 || n > 12 ? name[0] : name[n];
}
在C语言中,最好以相同的方式定义函数,因为尽管C语言中字符串文字具有非常量字符数组的类型,但任何试图更改字符串文字的尝试都会引发未定义的行为。这样的函数定义可以避免程序错误。
char* name[]
不是一个字符串字面量数组吗?这样写(只是有点不规范)/有效吗?生成的汇编代码似乎表明了这一点。但如果是这样,应该使用const char*
。 - Lala5thint f() { int v[] = {0}; return v[0]; }
相同的情况,你知道这并不是问题。 - molbdniloconst
:static char * const name[] = { … };
。指向的数据也可以是const
:static const char * const name[] = { … };
,如果您更改函数返回类型和调用代码以匹配。 - Eric Postpischilchar *
来引用字符串字面量而不是C++中所需的const char *
,我已删除了C++标签。 - Eric Postpischil