19

I want to do the following

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

But I do not want to write these characters separately. I want something like

#define S "ABCD"

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

But this won't compile (gcc says 'initializer element is not constant').

I tried replacing the #define line with

const char S[] = "ABCD";

But that doesn't seem to help.

How can I do this (or something similar) that lets me write the "ABCD" as a normal 'string', and not as four separate characters?

P.S. It seems that people do not read the question correctly...

I can't get the following code to compile:

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
    why not just use char a[]="ABCD"; – Tim Ring Jun 08 '09 at 08:41
  • It definitely should work. How did you compile? What options do you pass to gcc? – qrdl Jun 08 '09 at 08:46
  • 1
    Please explain why you want a char string to be copied/assigned to another char string using individual character assignment. – nik Jun 08 '09 at 08:53
  • @nik: I edited the question to explain this, see the code below the 'P.S.' – Arnaud Gouder de Beauregard Jun 08 '09 at 09:00
  • The compiler would probably like to know the size of t and u before referring to any entries in S. Try changing t[] to t[4] and u[] to u[4]. – Andrioid Jun 08 '09 at 09:05
  • @Android: tried that. Doesn't work. – Arnaud Gouder de Beauregard Jun 08 '09 at 09:27
  • Do you use only C? If you would use C++, then it would probably be possible to obtain the behavior you need, thanks to templates. –  Jun 08 '09 at 09:58
  • PS. C++ compiler allows the syntax that does not work with C compiler (i.e. global initialization with "macro array") –  Jun 08 '09 at 10:20
  • Why do you want the string without a null terminator? That is going to lead to problems. Also, you can do: char str[4] = "ABCD"; and the standard (and hence the compiler) should allow you have the stray null at the end of the string without an error. – Jonathan Leffler Jun 08 '09 at 18:43

12 Answers12

20

You can't - in C. In C initializing of global and local static variables are designed such that the compiler can put the values statically into the executable. It can't handle non-constant expressions as initializers. And only in C99, you can use non-constant expression in aggregate initializers - not so in C89!

In your case, since your array is an array containing characters, each element has to be an arithmetic constant expression. Look what it says about those

An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants, floating constants, enumeration constants, character constants, and sizeof expressions.

Surely this is not satisfied by your initializer, which uses an operand of pointer type. Surely, the other way is to initialize your array using a string literal, as it explains too

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

All quotes are taken out of the C99 TC3 committee draft. So to conclude, what you want to do - using non-constant expression - can't be done with C. You have several options:

  • Write your stuff multiple times - one time reversed, and the other time not reversed.
  • Change the language - C++ can do that all.
  • If you really want to do that stuff, use an array of char const* instead

Here is what i mean by the last option

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

That works fine, as an address constant expression is used to initialize the pointers

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators.

You may have luck tweaking your compiler options - another quote:

An implementation may accept other forms of constant expressions.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
8

Simply

const char S[] = "ABCD";

should work.

What's your compiler?

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 1
    Note that this initializes a 5-element array. There's also the \0 at the end. If you don't want it, make it a const char S[sizeof("ABCD")-1] = "ABCD" – laalto Jun 08 '09 at 08:41
  • Yes, just specifying the size to 4 will make the compiler omit the \0. The choice depends on what you actually want to do. – Mehrdad Afshari Jun 08 '09 at 08:42
  • Did you try this? I tried it with - ARM ADS 1.2 and gcc (for x86), and the result is the same: both compilers complain that the input **is not** const. – Arnaud Gouder de Beauregard Jun 08 '09 at 08:43
  • I just tested this with Leopard gcc 4.0.1 for x86 and worked perfectly. It's in the standard. If it doesn't work, I count the compiler as broken. – Mehrdad Afshari Jun 08 '09 at 08:44
  • See the other answer on this question: It's not this line that does not build! It's if you add a line 'char t[] = { S[0], S[1] };' that I can't get to work. – Arnaud Gouder de Beauregard Jun 08 '09 at 08:48
  • 1
    I guess you should clarify that in the question. By the way, that works too if you declare it in a *function* but won't work as a global variable. I'm thinking of a workaround but couldn't find one so far. – Mehrdad Afshari Jun 08 '09 at 08:55
5

Another option is to use sprintf.

For example,

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

Good luck.

0
#define S    "ABCD"
char a[sizeof(S) -1] = {S};

This should work as you would like to in C

Nancy
  • 1
  • 1
0

This compiles fine on gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4).

const char s[] = "cheese";

int main()
{
    return 0;
}
drxzcl
  • 2,952
  • 1
  • 26
  • 28
  • Duh :-) But please add a line char t[] = { s[0], s[1] }; because that is what I'm trying to do! – Arnaud Gouder de Beauregard Jun 08 '09 at 08:44
  • Arnaud: So your problem is with that line. Why do you want to do that? What exactly you're trying to accomplish? – Mehrdad Afshari Jun 08 '09 at 08:46
  • 1
    I want to have TWO char arrays, with the same contents, but in a differnt order. And this order is know at compile time, so I don't want to do any shuffling at runtime! – Arnaud Gouder de Beauregard Jun 08 '09 at 08:50
  • I suggest if you really must do this, and I recommend to do it at runtime instead, then run your code through a custom pre-processor. e.g. perl -pe 'if (/^char t\[\] = "(.*?)"/) { $reversed = reverse $1; print qq{char u[] = "$reversed";\n}; }' – Sam Watkins Feb 26 '13 at 05:24
0
const char S[] = "ABCD";

This should work. i use this notation only and it works perfectly fine for me. I don't know how you are using.

Meetu Choudhary
  • 1,373
  • 4
  • 14
  • 26
0

Here is obscure solution: define macro function:

#define Z(x) \
        (x==0 ? 'A' : \
        (x==1 ? 'B' : \
        (x==2 ? 'C' : '\0')))

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

Weird error.

Can you test this?

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] };
Nick Dandoulakis
  • 42,588
  • 16
  • 104
  • 136
0

I'm not sure what your problem is, but the following seems to work OK:

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

Edit 9 June 2009

If you need global access, you might need something ugly like this:

#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;
}
Michael J
  • 7,631
  • 2
  • 24
  • 30
0

The compilation problem only occurs for me (gcc 4.3, ubuntu 8.10) if the three variables are global. The problem is that C doesn't work like a script languages, so you cannot take for granted that the initialization of u and t occur after the one of s. That's why you get a compilation error. Now, you cannot initialize t and y they way you did it before, that's why you will need a char*. The code that do the work is the following:

#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;
}
Sambatyon
  • 3,316
  • 10
  • 48
  • 65
0

That's one of the cases a script to generate the appropriate code might help.

Markus Schnell
  • 1,075
  • 1
  • 10
  • 13
-1

Perhaps your character array needs to be constant. Since you're initializing your array with characters from a constant string, your array needs to be constant. Try this:

#define S "ABCD"
const char a[] = { S[0], S[1], S[2], S[3] };
Nate W.
  • 9,141
  • 6
  • 43
  • 65
  • Thanks, but no. I tried this and get the same error, which is logical, because the compiler complains that my 'initialization elements' are not const! – Arnaud Gouder de Beauregard Jun 08 '09 at 08:49
  • It should, that's why I don't understand that it doesn't work :-) – Arnaud Gouder de Beauregard Jun 08 '09 at 09:05
  • 1
    As it happens, literal strings are char* in C, not const char*, so "ABCD"[0] doesn't evaluate to a const char. However that's not the problem - global initializers have to be constant expressions. That's a separate concept from whether a value is const. – Steve Jessop Jun 08 '09 at 14:23