views:

350

answers:

5

Suppose I've following initialization of a char array:

char charArray[]={'h','e','l','l','o',' ','w','o','r','l','d'};

and I also have following initialization of a string literal:

char stringLiteral[]="hello world";

The only difference between contents of first array and second string is that second string's got a null character at its end.

When it's the matter of initializing a char array, is there a macro or something that allows us to put our initializing text between two double quotation marks but where the array doesn't get an extra null terminating character?

It just doesn't make sense to me that when a terminating null character is not needed, we should use syntax of first mentioned initialization and write two single quotation marks for each character in the initializer text, as well as virgule marks to separate characters.

I should add that when I want to have a char array, it should also be obvious that I don't want to use it with functions that rely on string literals along with the fact that none of features in which using string literals results, is into my consideration.

I'm thankful for your answers.

+3  A: 

There is no way of doing what you want. The first way of initializing the array specifies separate initializers for each character, which allows to explicitly leave off the '\0'. The second is initializing a character array from a character string, which in C/C++ is always terminated by a null character.

EDIT: corrected: 'character pointer' --> 'character array'

hkaiser
Actually, I don't beleive the second case is initialising a pointer to a character string. Its creating an array and initialising its contents based on the content of the string. And yes the difference really does matter.
torak
never noticed the "separate character initializers" concept, thanks
Pooria
A: 

The basic answer is that the vast majority of char arrays are strings - in C, strings are null terminated. C++ inherited that convention. Even when that null isn't needed, most of the time it isn't a problem just to leave it there anyway.

Macros aren't powerful enough to do what you want. Templates would be, except they don't have any compile-time string handling.

Usually, when people want to mix numeric bytes and string literals in the same char-array sequence, they use a string literal but use hex character escapes such as \xFF.

Steve314
+5  A: 

It's allowed in C to declare the array as follows, which will initialize it without copying the terminating '\0'

char c[3] = "foo";

But it's illegal in C++. I'm not aware of a trick that would allow it for C++. The C++ Standard further says

Rationale: When these non-terminated arrays are manipulated by standard string routines, there is potential for major catastrophe.
Effect on original feature: Deletion of semantically well-defined feature.
Difficulty of converting: Semantic transformation. The arrays must be declared one element bigger to contain the string terminating ’\0’.
How widely used: Seldom. This style of array initialization is seen as poor coding style.

Johannes Schaub - litb
A: 

litb has the technically correct answer.

As for an opinion - I say just live with the 'waste' of the extra '\0'. So many bugs are the result of code expecting a terminating null where one isn't (this advice may seem to go directly against some other advice I gave just a day or two ago about not bothering to zero an entire buffer. I claim there's no contradiction - I still advocated null terminating the string in the buffer).

If you really can't live with the '\0' terminator because of some semantics in the data structure you're dealing with, such as it might be part of some larger packed structure, you can always init the array yourself (which I think should be no less efficient than what the compiler might have done for you):

#define MY_STRING_LITERAL "hello world"

char stringLiteral[sizeof(MY_STRING_LITERAL) - 1];

memcpy( stringLiteral, MY_STRING_LITERAL, sizeof(stringLiteral));
Michael Burr
i think your method should be as efficient as compiler's one for char arrays with automatic storage class, but for char arrays with static storage class or the ones in global scope i think there's no run-time copying done by compiler.
Pooria
@garrett2011: that's likely true for `const char[]` items, but I think that most often non-const arrays will have their initial values copied from the program image 'text' (which is non-writable on most platforms) into RAM before `main()` is invoked. As long as the `memcpy()` is done only once, efficiency wise it's pretty much six of one, half dozen of the other whether it's done by the runtime or your code.
Michael Burr
A: 

I might have found a way to do what i want though it isn't directly what I wanted, but it likely has the same effect.
First consider two following classes:

template <size_t size>
class Cont{
 public:
  char charArray[size];
};
template <size_t size>
class ArrayToUse{
 public:
  Cont<size> container;
  inline ArrayToUse(const Cont<size+1> & input):container(reinterpret_cast<const Cont<size> &>(input)){}
};

Before proceeding, you might want to go here and take a look at constant expression constructors and initialization types.
Now look at following code:

const Cont<12> container={"hello world"};
ArrayToUse<11> temp(container);
char (&charArray)[11]=temp.container.charArray;

Notice that container object is not used anywhere else than previous two lines of code in program. compiler likely considers container object as a constant expression that is not used for anything else than initialization purposes; so likely no memory is reserved for this object. Finally initializer text is written between two double quotations.

Pooria
Make sure to splatter some comments around that construct. As you might have guessed already by other answers and comments, **not** having a terminating '\0' is a rather unusual concept and should come with the appropriate warning signs.
DevSolar
@DevSolar: appreciated
Pooria