如何从字符串初始化字符数组

19

我想要做以下事情:

char a[] = { 'A', 'B', 'C', 'D'};

但我不想单独写这些字符。我希望有像以下这样的东西
#define S "ABCD"

char a[] = { S[0], S[1], S[2], S[3] };

但是这段代码无法编译(gcc会提示“初始化元素不是常量”)。
我尝试将 #define 行替换为:
const char S[] = "ABCD";

但似乎这并没有帮助。

我应该怎么做(或类似的方式),让我将“ABCD”作为正常的“字符串”编写,而不是分开的四个字符?

顺便说一句,人们似乎没有正确阅读问题...

我无法使以下代码编译:

const char S[] = "ABCD";
char t[] = { S[0], S[1], S[2], S[3] };
char u[] = { S[3], S[2], S[1], S[0] };

4
为什么不直接使用char a[]="ABCD"? - Tim Ring
它肯定应该能够工作。你是如何编译的?你传递给gcc什么选项? - qrdl
1
请解释一下为什么要使用逐个字符赋值来将一个char字符串复制/赋值到另一个char字符串。 - nik
编译器在引用 S 中的任何条目之前,可能需要知道 t 和 u 的大小。尝试将 t [] 更改为 t [4],将 u [] 更改为 u [4]。 - Andrioid
@Android:尝试过了,不起作用。 - Arnaud Gouder de Beauregard
显示剩余4条评论
12个回答

20
在C语言中,你不能使用非常量表达式初始化全局和局部静态变量,因为编译器需要将这些值静态地放入可执行文件中。只有在C99标准中,你可以在聚合初始化器中使用非常量表达式,而在C89标准中不行。对于包含字符的数组,每个元素必须是算术常量表达式。然而,你的初始化表达式并未满足这个要求,因为它使用了一个指针类型的操作数。你可以使用字符串字面值来初始化数组,这样就满足了要求。总之,在C语言中,你不能使用非常量表达式进行初始化。你可以选择多次编写代码,一次是正序的,一次是倒序的;或者换用C++语言;或者如果你真的想实现这种功能,可以使用char const*数组。最后一种方法的意思是使用一个由char const*组成的数组来代替字符数组。
char const c[] = "ABCD";
char const *f[] = { &c[0], &c[1], &c[2], &c[3] };
char const *g[] = { &c[3], &c[2], &c[1], &c[0] };

这很好,因为地址常量表达式用于初始化指针。

地址常量可以是空指针、指向具有静态存储期限定符的对象的左值的指针或指向函数标识符的指针;它可以使用一元运算符 & 或整数常量转换为指针类型来明确定义,也可以通过数组或函数类型的表达式的使用隐含地创建。在创建地址常量时,可以使用数组下标[]和成员访问.和->操作符、地址& 和间接引用 * 一元操作符和指针转换,但不得使用这些操作符来访问对象的值。

你可以尝试调整编译器选项——另一句话:

实现可能接受其他形式的常量表达式。


8

简单地说

const char S[] = "ABCD";

应该可以正常工作。

你使用的编译器是什么?


1
请注意,这将初始化一个包含5个元素的数组。末尾还有\0。如果您不需要它,请将其设置为const char S[sizeof("ABCD")-1] = "ABCD"。 - laalto
是的,只需将大小指定为4,编译器就会忽略\0。选择取决于你实际想要做什么。 - Mehrdad Afshari
你试过这个吗?我用ARM ADS 1.2和gcc(针对x86)尝试了一下,结果是一样的:两个编译器都抱怨输入不是常量。 - Arnaud Gouder de Beauregard
我刚在 Leopard 的 x86 平台上使用 gcc 4.0.1 测试了一下,完美运行。这是标准操作。如果不能正常工作,我就认为编译器是有问题的。 - Mehrdad Afshari
请参见此问题的其他答案:不是这一行构建失败!如果添加一行“char t[] = {S[0],S[1]};”,我就无法使其工作。 - Arnaud Gouder de Beauregard
1
我猜你应该在问题中澄清这一点。顺便说一下,如果你在函数中声明它,那也可以工作,但在全局变量中不起作用。我正在想一个解决方法,但迄今为止还没有找到。 - Mehrdad Afshari

5
另一种选择是使用sprintf。
例如,
char buffer[50];
sprintf( buffer, "My String" );

祝你好运。


0

这在gcc版本4.3.3(Ubuntu 4.3.3-5ubuntu4)上编译正常。

const char s[] = "cheese";

int main()
{
    return 0;
}

嘿,别傻了 :-) 但请添加一行 char t[] = { s[0], s[1] };,因为这就是我想做的! - Arnaud Gouder de Beauregard
Arnaud:所以你的问题出在那一行。你为什么想要这样做?你具体想要实现什么? - Mehrdad Afshari
1
我想要两个具有相同内容但顺序不同的字符数组。而且这个顺序在编译时已知,因此我不想在运行时进行任何洗牌操作! - Arnaud Gouder de Beauregard
我建议如果你真的必须这样做,并且我推荐在运行时进行,那么请通过自定义预处理器来运行你的代码。例如:perl -pe 'if (/^char t[] = "(.*?)"/) { $reversed = reverse $1; print qq{char u[] = "$reversed";\n}; }' - Sam Watkins

0
这是一个模糊的解决方案:定义宏函数:
#define Z(x) \
        (x==0 ? 'A' : \
        (x==1 ? 'B' : \
        (x==2 ? 'C' : '\0')))

char x[] = { Z(0), Z(1), Z(2) };

将它们移到main函数之外。它们不能作为全局变量工作。 - Mehrdad Afshari
正如Mehrdad所说:我的问题不是在函数内部,而是当这些变量是全局的(或静态的,但不是函数的一部分)时发生的。 - Arnaud Gouder de Beauregard
@Mehrdad,@Arnaud:好的,我明白了。我现在将解决方案更改为另一个。 - anon
不错,但更简单的解决方案是 #define Z0 'A',#define Z1 'B',等等... 这正是我不喜欢的起点 :-) - Arnaud Gouder de Beauregard
呵呵,不错 :) 如果您将Z0、Z1等定义为"A"、"B"等(注意双引号),那么您就不必在初始化程序中使用逗号了,简单的char x[] = {Z1 Z2 Z3}就可以工作。 - anon

0

奇怪的错误。

你能测试一下吗?

const char* const S = "ABCD";
char t[] = { S[0], S[1], S[2], S[3] };
char u[] = { S[3], S[2], S[1], S[0] };

0

我不确定你的问题是什么,但下面的代码似乎可以正常工作:

#include <stdio.h>

int main()
{
    const char s0[] = "ABCD";
    const char s1[] = { s0[3], s0[2], s0[1], s0[0], 0 };

    puts(s0);
    puts(s1);
    return 0;
}


Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
cl /Od /D "WIN32" /D "_CONSOLE" /Gm /EHsc /RTC1 /MLd /W3 /c /ZI /TC
   .\Tmp.c
Tmp.c
Linking...

Build Time 0:02


C:\Tmp>tmp.exe
ABCD
DCBA

C:\Tmp>

编辑于2009年6月9日

如果你需要全球访问,你可能需要像这样丑陋的东西:

#include <stdio.h>

const char *GetString(int bMunged)
{
    static char s0[5] = "ABCD";
    static char s1[5];

    if (bMunged) {
        if (!s1[0])  {
            s1[0] = s0[3]; 
            s1[1] = s0[2];
            s1[2] = s0[1];
            s1[3] = s0[0];
            s1[4] = 0;
        }
        return s1;
    } else {
        return s0;
    }
}

#define S0 GetString(0)
#define S1 GetString(1)

int main()
{
    puts(S0);
    puts(S1);
    return 0;
}

这个答案已经尝试过了 :-) 问题在于数组应该是全局的! - Arnaud Gouder de Beauregard

0

编译问题只在我这里出现(gcc 4.3,ubuntu 8.10),如果三个变量是全局的。问题在于C不像脚本语言那样工作,所以您不能认为u和t的初始化发生在s之后。这就是为什么会出现编译错误的原因。现在,您不能像以前那样初始化t和y,这就是为什么您需要一个char*的原因。完成工作的代码如下:

#include <stdio.h>
#include <stdlib.h>

#define STR "ABCD"

const char s[] = STR;
char* t;
char* u;

void init(){
    t = malloc(sizeof(STR)-1);
    t[0] = s[0];
    t[1] = s[1];
    t[2] = s[2];
    t[3] = s[3];


    u = malloc(sizeof(STR)-1);
    u[0] = s[3];
    u[1] = s[2];
    u[2] = s[1];
    u[3] = s[0];
}

int main(void) {
    init();
    puts(t);
    puts(u);

    return EXIT_SUCCESS;
}

0
const char S[] = "ABCD";

这应该可以工作。我只使用这种符号,对我来说完全正常。我不知道你是如何使用的。


显然,我没有很清楚地表达我的问题。 尝试编译以下两行代码: const char S[] = "ABCD"; char t[] = { S[0], S[1] }; - Arnaud Gouder de Beauregard
什么是这样做的必要性?难道你不能只使用char s[] ="ABCD"吗?具体需求是什么? - Meetu Choudhary

0

这是脚本生成适当代码的情况之一,可能会有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接