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

时间:2015-12-04 10:39:31

标签: c arrays c-strings u-boot

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

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

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

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

你能帮我理解吗?

6 个答案:

答案 0 :(得分:3)

“string”实际上只是指向由值为0的char终止的字符序列的指针(请注意序列必须在单个对象内)

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

答案 1 :(得分:2)

  

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

     

我在U-boot源中观察到环境变量存储在一维数组中。

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

您可以尝试删除所有#ifdef#endif,然后很明显default_environment只是单个字符串的串联。例如,"bootargs=" CONFIG_BOOTARGS "\0"。注意最后的\0,它将确保分配给default_environment的字符串不会通过第一行,并且定义了CONFIG_BOOTARGS

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

答案 2 :(得分:1)

他们没有在那里创建一个字符串数组,例如你的char *states[],它是一个正在创建的字符串(作为char[])。个人元素'字符串内部用零终止表示。

翻译您的示例

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

他们的符号将是

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

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

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

至于它的原因,@M.M.'s comment给出了一些很好的指示。

答案 3 :(得分:0)

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

单个字符

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上存储任何其他字符,它会起作用,但最好使用空字符'\0'来结束它。

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

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] = '\0';

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

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

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

答案 4 :(得分:0)

如果我们将问题简化为初始化char *foochar 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个字节,并将内容初始化为"这是测试\ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 ..."。这个数组可以像任何其他堆内存一样修改。

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

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

答案 5 :(得分:0)

常用技巧是使用指针数组(注意:这与2D数组不同!):

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

这样,states是一个包含4个char指针的数组,你只需使用它printf("State %s", states[i]);

为了完整性,2D数组将是char states[11][5],所有行具有相同的长度,这是非常罕见的,并且更难初始化。

但是一些特殊用例或API(*)需要(或返回)一个char数组,其中字符串(通常)以\0结尾,数组本身由空元素终止,连续两次\0。当公共指针数组在一个地方有指针数组而字符串本身在另一个地方时,这种表示允许整个数组的单个分配块。顺便说一句,很容易从{1}作为分隔符的1D characater数组重建指针数组,并且通常可以轻松使用字符串。

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

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