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] };
9
  • 5
    why not just use char a[]="ABCD"; Commented Jun 8, 2009 at 8:41
  • It definitely should work. How did you compile? What options do you pass to gcc? Commented Jun 8, 2009 at 8:46
  • 1
    Please explain why you want a char string to be copied/assigned to another char string using individual character assignment. Commented Jun 8, 2009 at 8:53
  • @nik: I edited the question to explain this, see the code below the 'P.S.' Commented Jun 8, 2009 at 9: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]. Commented Jun 8, 2009 at 9:05

12 Answers 12

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.

Sign up to request clarification or add additional context in comments.

Comments

8

Simply

const char S[] = "ABCD";

should work.

What's your compiler?

6 Comments

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"
Yes, just specifying the size to 4 will make the compiler omit the \0. The choice depends on what you actually want to do.
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.
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.
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.
|
5

Another option is to use sprintf.

For example,

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

Good luck.

Comments

0

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

const char s[] = "cheese";

int main()
{
    return 0;
}

4 Comments

Duh :-) But please add a line char t[] = { s[0], s[1] }; because that is what I'm trying to do!
Arnaud: So your problem is with that line. Why do you want to do that? What exactly you're trying to accomplish?
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!
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}; }'
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.

2 Comments

Apparently I didn't phrase my question very clearly. Try to compile the following two lines: const char S[] = "ABCD"; char t[] = { S[0], S[1] };
and whats the need for that did char s[] ="ABCD" alone wont work for you? what is the exact requirement
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] };

Comments

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

5 Comments

Move them outside the main function. They won't work as global vars.
It's exactly as Mehrdad says: my problem occurs not within a function, but when these variables are global (or static, but not part of a function)
@Mehrdad, @Arnaud: Ok, I see. I now changed the solution to another one.
Nice, but an even simpler solution would be #define Z0 'A', #define Z1 'B', etc... And that is exactly my starting point that I didn't like :-)
Hehe nice :) If you would define Z0, Z1, etc. as "A", "B", etc. (notice double quotes) then you wouldn't have to use commas in initializer, simple char x[] = {Z1 Z2 Z3 } would work.
0

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

Comments

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

Comments

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

1 Comment

This answer was tried already :-) The problem is that the array should be global!
0
#define S    "ABCD"
char a[sizeof(S) -1] = {S};

This should work as you would like to in C

Comments

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

3 Comments

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!
It should, that's why I don't understand that it doesn't work :-)
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.