如果不声明为常量,声明指向字符串字面值的指针数组是否有任何负面影响?
我正在设置一个字符串数组,可以有不同的长度。如果我将它们设置为指向字符串字面量的指针数组,那么一切似乎都很正常,我甚至可以稍后更改它们。在我继续在更大规模的嵌入式程序中使用它之前,我只是想确定这是最好的方法。
- 是否有这个简单示例可能遗漏的任何负面副作用?
- 将其声明为具有最大长度的2d字符数组是否有任何优势?
例子:
#include <stdio.h>
char * OutputNames[20] =
{
"Output 01",
"Output 02",
"Output 03",
"Output 04",
"Output 05",
"Output 06",
"Output 07",
"Output 08",
"Output 09",
"Output 10",
"Output 11",
"Output 12",
"Output 13",
"Output 14",
"Output 15",
"Output 16",
"Output 17",
"Output 18",
"Output 19",
"Output 20",
};
char main()
{
OutputNames[12] = "Test Output";
for (unsigned char ArrMem = 0; ArrMem < 20; ++ArrMem)
{
printf("%sn", OutputNames[ArrMem]);
}
getchar();
return (0);
}
C中的字符串字面值是只读的(即使它们的类型实际上是char []
),因此最好将数组定义为:
const char * OutputNames[] =
{
...
};
注意,这意味着指针指向的是const
,而不是指针本身。另外,请注意省略了数组长度,以便由初始化器决定数组的大小。
不,这是我最喜欢的存储长度不同的字符串集合的方式。
所需的内存量稍微多一点,因为您还存储了所有的指针。但是如果你创建一个二维数组,你会浪费更多的内存,因为每个字符串都需要足够的空间来存放最长的字符串。
您需要担心的主要问题是释放所有内存,但由于您使用的是字符串常量,因此这里不是问题。我将数组设为const
。
主要的危险是您可能会意外地尝试更改其中一个字符串字面值(可能在传递指针的调用链的深处;难以调试)导致未定义的行为。将它们声明为const:
,这样可以省去麻烦。const char *OutputNames[20] = ...
注意,这里没有将ARRAY声明为const,只是将指向的字符串声明为const。因此,您仍然可以更改数组的任何元素(使其指向不同的字符串)。
如果你真的想在运行时更改字符串,那么一切都是错误的,你应该使用数组来代替。
是否有这个简单示例可能遗漏的任何负面副作用?
-
如前所述,意外地执行写访问会调用未定义的行为。绝对没有理由不将指针声明为
const char*
。 -
由于这是一个嵌入式系统,指针表的声明是不正确的。您不仅希望指针指向只读数据,而且指针本身也应该是只读的,因此数组被分配到闪存中,而不是RAM中。所以它的类型必须是
const char* const
这是冯诺依曼假设。在哈佛架构的情况下,你可能需要添加一些丑陋的技巧,如非标准关键字。
将其声明为具有最大长度的2d字符数组是否有任何优势?
这可能会导致更好的性能。首先,保证相邻分配。这可以在支持数据缓存的系统上获得更好的性能。由于这些将在flash中分配,因此访问通常很慢,处于等待状态。
第二,你摆脱了一个完整的指针查找表,这节省了内存,并且潜在地提供了更快的访问速度,因为你减少了一个间接的级别。
缺点是2D数组不太灵活,你需要分配固定的长度。
与你的问题无关,char main()
完全是废话。Main()不是你可以随意声明的泛型函数,而是一个专门化的函数。
- main()在宿主(PC)系统上是
int main(void)
或可选的argv + argc。 独立(嵌入式)系统上的 - main()通常是实现定义的
void main(void)
,因为从main()返回是没有意义的。使用类gcc编译器编译-ffreestanding
。
在这两种情况下,是编译器决定main()的有效形式,而不是程序员。