【问题标题】:How to Initialize char array from a string如何从字符串初始化字符数组
【发布时间】:2009-06-08 08:37:28
【问题描述】:

我想做以下事情

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

但我不想单独写这些字符。我想要类似的东西

#define S "ABCD"

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

但这不会编译(gcc 说'initializer element is not constant')。

我尝试将#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] };

【问题讨论】:

  • 为什么不直接使用 char a[]="ABCD";
  • 绝对应该可以。你是怎么编译的?您将哪些选项传递给 gcc?
  • 请解释为什么您希望使用单个字符分配将 char 字符串复制/分配给另一个 char 字符串。
  • @nik:我编辑了问题来解释这一点,请参阅“P.S.”下方的代码
  • 在引用 S 中的任何条目之前,编译器可能想知道 t 和 u 的大小。尝试将 t[] 更改为 t[4] 并将 u[] 更改为 u[4]。

标签: c


【解决方案1】:

你不能 - 在 C 中。在 C 中,全局和局部静态变量的初始化被设计为编译器可以将值静态地放入可执行文件中。它不能将非常量表达式作为初始值设定项处理。并且仅在 C99 中,您可以在聚合初始值设定项中使用非常量表达式 - 在 C89 中并非如此!

在您的情况下,由于您的数组是一个包含字符的数组,因此每个元素都必须是一个算术常量表达式。看看它是怎么说的

算术常量表达式应该有算术类型并且应该只有 整数常量、浮点常量、枚举常量、字符的操作数 常量和 sizeof 表达式。

您的初始化程序肯定不满足这一点,它使用指针类型的操作数。当然,另一种方法是使用字符串文字初始化数组,正如它所解释的那样

具有静态存储持续时间的对象的初始化程序中的所有表达式都应为常量表达式或字符串字面量。

所有引用均来自 C99 TC3 委员会草案。所以总而言之,你想做的事情——使用非常量表达式——不能用 C 来完成。你有几个选择:

  • 多次写你的东西 - 一次颠倒,另一次不颠倒。
  • 更改语言 - C++ 可以做到这一切。
  • 如果您真的想要这样做,请改用 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] };

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

地址常量是一个空指针,一个指向指定静态存储持续时间对象的左值的指针,或者一个指向函数指示符的指针;它应使用一元 & 运算符或转换为指针类型的整数常量显式创建,或通过使用数组或函数类型的表达式隐式创建。数组下标 [] 和成员访问。和 -> 运算符、地址 & 和间接 * 一元运算符以及指针转换可用于创建地址常量,但不得使用这些运算符访问对象的值。

您可能会幸运地调整您的编译器选项 - 另一个引用:

一个实现可以接受其他形式的常量表达式。

【讨论】:

    【解决方案2】:

    简单

    const char S[] = "ABCD";
    

    应该可以。

    你的编译器是什么?

    【讨论】:

    • 请注意,这会初始化一个 5 元素数组。最后还有 \0 。如果您不想要它,请将其设为 const char S[sizeof("ABCD")-1] = "ABCD"
    • 是的,只要将大小指定为 4,编译器就会忽略 \0。选择取决于您实际想要做什么。
    • 你试过了吗?我用 - ARM ADS 1.2 和 gcc (for x86) 进行了尝试,结果是一样的:两个编译器都抱怨输入 is not const.
    • 我刚刚使用 Leopard gcc 4.0.1 for x86 对此进行了测试,并且运行良好。它在标准中。如果它不起作用,我将编译器视为损坏。
    • 我想你应该在问题中澄清这一点。顺便说一句,如果您在 function 中声明它也可以,但不能用作全局变量。我正在考虑一种解决方法,但目前找不到。
    【解决方案3】:

    另一种选择是使用 sprintf。

    例如,

    char buffer[50];
    sprintf( buffer, "My String" );
    

    祝你好运。

    【讨论】:

      【解决方案4】:

      这在 gcc 版本 4.3.3 (Ubuntu 4.3.3-5ubuntu4) 上编译得很好。

      const char s[] = "cheese";
      
      int main()
      {
          return 0;
      }
      

      【讨论】:

      • Duh :-) 但是请添加一行 char t[] = { s[0], s[1] };因为这就是我想要做的!
      • Arnaud:所以你的问题在于那条线。你为什么要这样做?你到底想完成什么?
      • 我想要两个字符数组,内容相同,但顺序不同。而且这个顺序在编译时就知道了,所以我不想在运行时做任何改组!
      • 我建议如果你真的必须这样做,我建议改为在运行时这样做,然后通过自定义预处理器运行你的代码。例如perl -pe 'if (/^char t[] = "(.*?)"/) { $reversed = reverse $1;打印 qq{char u[] = "$reversed";\n}; }'
      【解决方案5】:
      const char S[] = "ABCD";
      

      这应该可行。我只使用这个符号,它对我来说非常好。不知道你是怎么用的。

      【讨论】:

      • 显然我没有很清楚地表达我的问题。尝试编译以下 行: const char S[] = "ABCD";字符 t[] = { S[0], S[1] };
      • 单独的 char s[] ="ABCD" 对你不起作用有什么需要?具体要求是什么
      【解决方案6】:

      奇怪的错误。

      你能测试一下吗?

      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] };
      

      【讨论】:

        【解决方案7】:

        这里是晦涩的解决方案:定义宏函数:

        #define Z(x) \
                (x==0 ? 'A' : \
                (x==1 ? 'B' : \
                (x==2 ? 'C' : '\0')))
        
        char x[] = { Z(0), Z(1), Z(2) };
        

        【讨论】:

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

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

        【讨论】:

          【解决方案9】:

          如果三个变量是全局的,编译问题只会发生在我身上(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;
          }
          

          【讨论】:

            【解决方案10】:

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

            #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;
            }
            

            【讨论】:

            • 这个答案已经试过了 :-) 问题是数组应该是全局的!
            【解决方案11】:

            也许您的字符数组需要保持不变。由于您使用常量字符串中的字符初始化数组,因此您的数组必须是常量。试试这个:

            #define S "ABCD"
            const char a[] = { S[0], S[1], S[2], S[3] };
            

            【讨论】:

            • 谢谢,但没有。我试过这个并得到同样的错误,这是合乎逻辑的,因为编译器抱怨我的“初始化元素”不是 const!
            • 应该,这就是为什么我不明白它不起作用:-)
            • 碰巧,文字字符串是 C 中的 char*,而不是 const char*,因此“ABCD”[0] 不会计算为 const char。然而这不是问题——全局初始化器必须是常量表达式。这与值是否为 const 是不同的概念。
            猜你喜欢
            • 2013-04-29
            • 2014-08-23
            • 2011-12-11
            • 1970-01-01
            • 2021-04-16
            • 1970-01-01
            • 2019-01-03
            • 1970-01-01
            相关资源
            最近更新 更多