不确定用字符串数组初始化一维字符数组

unsure about initializing one dimensional char array with array of strings

根据我的理解,字符串数组可以如下所示或使用二维数组进行初始化。请问还有没有其他的可能。

char *states[] = { "California", "Oregon", "Washington", "Texas" };

我在 U-boot 源代码中观察到环境变量存储在一维数组中,如图 here:

uchar default_environment[] = {
#ifdef  CONFIG_BOOTARGS
    "bootargs="     CONFIG_BOOTARGS     "[=11=]"
#endif
#ifdef  CONFIG_BOOTCOMMAND
    "bootcmd="      CONFIG_BOOTCOMMAND   "[=11=]"
#endif 
...
    "[=11=]"
};

你能帮我理解一下吗?

他们没有在那里创建一个字符串数组,例如您的 char *states[],它是正在创建的单个字符串(作为 char[])。字符串中的单个 'elements' 由零终止表示。

翻译你的例子

char *states[] = { "California", "Oregon", "Washington", "Texas" };

他们的符号是

char states[] = { "California" "[=11=]" "Oregon" "[=11=]" "Washington" "[=11=]" "Texas" "[=11=]" "[=11=]" };

相同
char states[] = { "California[=12=]Oregon[=12=]Washington[=12=]Texas[=12=][=12=]" };

您可以通过获取指向每个零终止块开头的指针来使用它们,然后字符串函数(例如 strlen 将读取直到它们看到下一个 '[=16=]' 字符。

至于为什么, 给出了一些很好的指示。

是的,您可以使用指针创建和初始化字符串数组或数组层次结构。详细描述它以防有人需要它。

单个字符

1. char states; 

指向字符数组的指针。

2. char *states = (char *) malloc(5 * sizeof(char)):

以上语句等同于char states[5]; 现在由你决定是否用 strcpy() 初始化它,比如

strcpy(states, "abcd");

或像这样使用直接值。

states[0] = 'a';
states[1] = 'b';
states[2] = 'c';
states[3] = 'd';
states[4] = '/0';

尽管如果您在索引 4 上存储任何其他字符,它也可以工作,但最好使用空字符 '[=20=]' 结束此操作。


指向指针数组的指针或指向字符矩阵的指针

3. char ** states = (char **) malloc(5 * sizeof(char *));

它是一个指针数组,即每个元素都是一个指针,可以指向或换句话说保存一个字符串等,如

states[0] = malloc ( sizeof(char) * number ); 
states[1] = malloc ( sizeof(char) * number );
states[2] = malloc ( sizeof(char) * number );
states[3] = malloc ( sizeof(char) * number );
states[4] = malloc ( sizeof(char) * number );

以上语句等同于char states[5][number];

同样取决于您如何将这些指针初始化为字符串,即

strcpy( states[0] , "hello");
strcpy ( states[1], "World!!");

states[2][0] = 'a';
states[2][1] = 'b';
states[2][2] = 'c';
states[2][3] = 'd';
states[2][4] = '[=16=]';

指向指针矩阵的指针或指向 3D 字符的指针

char *** states = (char ***) malloc(5 * sizeof(char**));

等等。 实际上,这些可能性中的每一种都以某种方式达到了指针。

如果我们将问题简化为初始化 char *foo 与初始化 char foo[100] 之间的区别是什么,它可能会有所帮助。查看以下代码:

char buffer1[100] = "this is a test";
char *buffer2     = "this is a test";

int main(void)
{
    printf("buffer1 = %s\n", buffer1);
    buffer1[0] = 'T';
    printf("buffer1 = %s\n", buffer1);


    printf("buffer2 = %s\n", buffer2);
    buffer2[0] = 'T';
    printf("buffer2 = %s\n", buffer2); // this will fail
}

在第一种情况下(buffer1)我们用一个字符串初始化一个字符数组。编译器会为数组分配100个字节,并将内容初始化为"this is a test[=24=][=24=][=24=][=24=][=24=][=24=][=24=][=24=][=24=]..."。这个数组像任何其他堆内存一样是可修改的。

在第二种情况下,我们没有为数组分配任何内存。我们要求编译器做的就是为指针留出足够的内存(通常为 4 或 8 个字节),然后将其初始化为指向存储在其他地方的字符串。通常,编译器会为字符串生成一个单独的代码段,或者只是将其与代码内联存储。在任何一种情况下,该字符串都是 只读。所以在我试图写入的最后一行,它导致了段错误。

这就是初始化数组和初始化指针的区别。

A​​ "string" 实际上只不过是指向由值为 0 的字符终止的字符序列的指针(请注意,序列 必须 在单个对象内)。

char a[] = {65, 66, 67, 0, 97, 98, 99, 0, 'f', 'o', 'o', 'b', 'a', 'r', 0, 0};
/*                      ^              ^                                ^  ^ */

在上面的数组中,我们有四个值为 0 的元素...因此您可以将其视为 4 个字符串

// string 1
printf("%s\n", a); // prints ABC on a ASCII computer

// string 2
printf("%s\n", a + 4); // prints abc on a ASCII computer

// string 3
printf("%s\n", a + 8); // prints foobar

// string 4
printf("%s\n", a + 14); // prints empty string

常用的技术是使用指针数组(注意:这与二维数组不同!)如:

char *states[] = { "California", "Oregon", "Washington", "Texas" };

这样,states 是一个 4 字符指针数组,您可以简单地使用它 printf("State %s", states[i]);

为了完整起见,二维数组应该是 char states[11][5] 所有行都具有相同的长度,这种情况很少见,而且更难初始化。

但一些特殊用例或 API(*) 需要(或 return)单个字符数组,其中字符串(通常)以 [=13=] 结尾,数组本身是由一个空元素终止,即它连续两个 [=13=]。当公共指针数组在一个地方有指针数组而在另一个地方有字符串本身时,这种表示允许整个数组的单个分配块。顺便说一下,用 [=13=] 作为分隔符从一维字符数组重建指针数组很容易,通常这样做是为了能够轻松使用字符串。

uchar default_environment[] 技术的最后一个有趣点是它是一个很好的序列化:您可以直接将它保存到一个文件并加载回来。正如我已经说过的,通常的用法是构建一个指针数组,以便轻松访问各个字符串。


(*) 例如,WinAPI 函数 GetPrivateProfileSectionWritePrivateProfileSection 使用这样的表示来设置或获取 key=value[ 的列表=33=] 一次调用中的字符串。

As per my understanding array of strings can be initialized as shown below or using two dimensional array. Please tell is there any other possibility.

I have observed in U-boot source that environment variables are stored in one dimensional array.

如果暗示这个 default_environment 是一个字符串数组,那么它是 而不是 。这与第一个示例中的字符串数组初始化无关。

您可以尝试删除所有 #ifdef#endif,那么很明显 default_environment 只是单个字符串的串联。例如,"bootargs=" CONFIG_BOOTARGS "[=15=]"。注意末尾的 [=16=],它将确保分配给 default_environment 的字符串不会通过第一行,因为已定义 CONFIG_BOOTARGS

uchar default_environment[] = {
#ifdef  CONFIG_BOOTARGS
    "bootargs="     CONFIG_BOOTARGS     "[=10=]"
#endif
#ifdef  CONFIG_BOOTCOMMAND
    "bootcmd="      CONFIG_BOOTCOMMAND   "[=10=]"
#endif 
...
    "[=10=]"
};