Your use of Stack Overflow’s Products and Services, including the Stack Overflow Network, is subject to these policies and terms.
Code of Conduct .
Is initializing a char with a string literal bad practice?
I was reading a thread titled “strlen vs sizeof” on CodeGuru , and one of the replies states that “it’s anyways [sic] bad practice to initialie [sic] a
char array with a string literal.”
Is this true, or is that just his (albeit an “elite member”) opinion?
Here is the original question:
#include <stdio.h> #include<string.h> main() char string = "october"; strcpy(string, "september"); printf("the size of %s is %d and the length is %d\n\n", string, sizeof(string), strlen(string)); return 0;
right. the size should be the length plus 1 yes?
this is the output
the size of september is 8 and the length is 9
size should be 10 surely. its like its calculating the sizeof string before it is changed by strcpy but the length after.
Is there something wrong with my syntax or what?
Here is the reply :
It’s anyways bad practice to initialie a char array with a string literal. So always do one of the following:
const char string1 = "october"; char string2; strcpy(string2, "september");
- Note the "const" on the first line. Could it be that the author assumed c++ instead of c? In c++ it is "bad practice", because a literal should be const and any recent c++ compiler will give a warning (or error) about assigning a const literal to a non-const array.
Jan 23 at 9:24
- @André C++ defines string literals as const arrays, because that is the only safe way of dealing with them. That C doesn’t is the problem, so you have a social rule that enforces the safe thing
Jan 23 at 9:48
- @Caleth. I know, I was more trying to argue that the author of the reply was approaching the "bad practice" from a c++ perspective.
Jan 23 at 10:32
- @André it isn’t a bad practice in C++, because it isn’t a practice, it’s a straight up type error. It should be a type error in C, but it isn’t, so you have to have a style guide rule telling you "It’s forbidden"
Jan 23 at 10:35
add a comment |
It’s anyways bad practice to initialie a char array with a string literal.
The author of that comment never really justifies it, and I find the statement puzzling.
In C (and you’ve tagged this as C), that’s pretty much the only way to initialize an array of
char with a string value (initialization is different from assignment). You can write either
char string = "october";
char string = "october";
char string[MAX_MONTH_LENGTH] = "october";
In the first case, the size of the array is taken from the size of the initializer. String literals are stored as arrays of
char with a terminating 0 byte, so the size of the array is 8 (‘o’, ‘c’, ‘t’, ‘o’, ‘b’, ‘e’, ‘r’, 0). In the second two cases, the size of the array is specified as part of the declaration (8 and
MAX_MONTH_LENGTH, whatever that happens to be).
What you cannot do is write something like
char string; string = "october";
char string; string = "october";
etc. In the first case, the declaration of
string is incomplete because no array size has been specified and there’s no initializer to take the size from. In both cases, the
= won’t work because a) an array expression such as
string may not be the target of an assignment and b) the
= operator isn’t defined to copy the contents of one array to another anyway.
By that same token, you can’t write
char string = foo;
foo is another array of
char. This form of initialization will only work with string literals.
I should amend this to say that you can also initialize arrays to hold a string with an array-style initializer, like
char string = 'o', 'c', 't', 'o', 'b', 'e', 'r', 0;
char string = 111, 99, 116, 111, 98, 101, 114, 0; // assumes ASCII
but it’s easier on the eyes to use string literals.
In order to assign the contents of an array outside of a declaration, you would need to use either
strcpy/strncpy (for 0-terminated strings) or
memcpy (for any other type of array):
if (sizeof string > strlen("october")) strcpy(string, "october");
strncpy(string, "october", sizeof string); // only copies as many characters as will // fit in the target buffer; 0 terminator // may not be copied, but the buffer is // uselessly completely zeroed if the // string is shorter!
strncpyis rarely the right answer
– Keith Thompson
Jan 17 ’13 at 21:52
- @KeithThompson: not disagreeing, just added it for completeness’ sake.
– John Bode
Jan 17 ’13 at 21:58
- 14Please note that
char str = "october";is bad practice. I had to literally char count myself to make sure it wasn’t an overflow and it breaks under maintenance… e.g. correcting a spelling error from
separatewill break if size not updated.
May 14 ’13 at 21:22
- 1I agree with djechlin, it is bad practice for the reasons given. JohnBode’s answer doesn’t comment at all on the "bad practice" aspect (which is the main part of the question!!), it just explains what you can or cannot do to initialize the array.
Jun 11 ’15 at 11:46
- Minor: As ‘length" value returned from
strlen()does not include the null character, using
MAX_MONTH_LENGTHto hold the maximum size needed for
char stringoften looks wrong. IMO,
MAX_MONTH_SIZEwould be better here.
May 9 at 19:21
add a comment |
The only problem I recall is assigning string literal to
char var1 = "september"; var1 = 'S'; // Ok - 10 element char array allocated on stack char const *var2 = "september"; var2 = 'S'; // Compile time error - pointer to constant string char *var3 = "september"; var3 = 'S'; // Modifying some memory - which may result in modifying... something or crash
For example take this program:
#include <stdio.h> int main() char *var1 = "september"; char *var2 = "september"; var1 = 'S'; printf("%s\n", var2);
This on my platform (Linux) crashes as it tries to write to page marked as read-only. On other platforms it might print ‘September’ etc.
That said – initialization by literal makes the specific amount of reservation so this won’t work:
char buf = "May"; strncpy(buf, "September", sizeof(buf)); // Result "Sep"
But this will
char buf = "May"; strncpy(buf, "September", sizeof(buf));
As last remark – I wouldn’t use
strcpy at all:
char buf; strcpy(buf, "very long string very long string"); // Oops. We overwrite some random memory
While some compilers can change it into safe call
strncpy is much safer:
char buf; strncpy(buf, something_else, sizeof(buf)); // Copies at most sizeof(buf) chars so there is no possibility of buffer overrun. Please note that sizeof(buf) works for arrays but NOT pointers. buf[sizeof(buf) - 1] = '\0';
- There’s still a risk for buffer overrun on that
strncpybecause it doesn’t null terminate the copied string when length of
something_elseis greater than
sizeof(buf). I usually set the last char
buf[sizeof(buf)-1] = 0to protect from that, or if
bufis zero-initialized, use
sizeof(buf) - 1as the copy length.
Jun 24 ’16 at 18:30
snprintfif you have to.
Jan 23 at 1:30
- Fixed. Unfortunatly there is no easy portable way of doing this unless you have a luxury of working with newest compilers (
snprintfare not directly accessible on MSVC, at least orders and
strcpy_sare not on *nix).
– Maciej Piechotka
Jan 23 at 1:47
- @MaciejPiechotka: Well, thank god Unix rejected the microsoft-sponsored annex k.
Jan 23 at 2:12
add a comment |
One thing that neither thread brings up is this:
char whopping_great = "foo";
char whopping_great; memcpy(whopping_great, "foo", sizeof("foo"));
The former will do something like:
memcpy(whopping_great, "foo", sizeof("foo")); memset(&whopping_great[sizeof("foo")], 0, sizeof(whopping_great)-sizeof("foo"));
The latter only does the memcpy. The C standard insists that if any part of an array is initialized, it all is. So in this case, it’s better to do it yourself. I think that may have been what treuss was getting at.
char whopping_big; whopping_big = 0;
is better than either:
char whopping_big = 0;
char whopping_big = "";
p.s. For bonus points, you can do:
memcpy(whopping_great, "foo", (1/(sizeof("foo") <= sizeof(whopping_great)))*sizeof("foo"));
to throw a compile time divide by zero error if you’re about to overflow the array.
add a comment |
Primarily because you won’t have the size of the
char in a variable / construct that you can easily use within the program.
The code sample from the link:
char string = "october"; strcpy(string, "september");
string is allocated on the stack as 7 or 8 characters long. I can’t recall if it’s null-terminated this way or not – the thread you linked to stated that it is.
Copying “september” over that string is an obvious memory overrun.
Another challenge comes about if you pass
string to another function so the other function can write into the array. You need to tell the other function how long the array is so it doesn’t create an overrun. You could pass
string along with the result of
strlen() but the thread explains how this can blow up if
string is not null-terminated.
You’re better off allocating a string with a fixed size (preferably defined as a constant) and then pass the array and fixed size to the other function. @John Bode’s comment(s) are correct, and there are ways to mitigate these risks. They also require more effort on your part to use them.
In my experience, the value I initialized the
char to is usually too small for the other values I need to place in there. Using a defined constant helps avoid that issue.
sizeof string will give you the size of the buffer (8 bytes); use the result of that expression instead of
strlen when you’re concerned about memory.
Similarly, you can make a check before the call to
strcpy to see if your target buffer is large enough for the source string:
if (sizeof target > strlen(src)) strcpy (target, src); .
Yes, if you have to pass the array to a function, you’ll need to pass its physical size as well:
foo (array, sizeof array / sizeof *array);. – John Bode
sizeof stringwill give you the size of the buffer (8 bytes); use the result of that expression instead of
strlenwhen you’re concerned about memory. Similarly, you can make a check before the call to
strcpyto see if your target buffer is large enough for the source string:
if (sizeof target > strlen(src)) strcpy (target, src);. Yes, if you have to pass the array to a function, you’ll need to pass its physical size as well:
foo (array, sizeof array / sizeof *array);.
– John Bode
Jan 16 ’13 at 17:03
- 1@JohnBode – thanks, and those are good points. I have incorporated your comment into my answer.
Jan 16 ’13 at 17:16
- 1More precisely, most references to the array name
stringresult in an implicit conversion to
char*, pointing to the first element of the array. This loses the array bounds information. A function call is just one of the many contexts in which this happens.
char *ptr = string;is another. Even
stringis an example of this; the
operator works on pointers, not directly on arrays. Suggested reading: Section 6 of the comp.lang.c FAQ .
– Keith Thompson
Jan 17 ’13 at 21:47
- Finally an answer that actually refers to the question!
Jun 11 ’15 at 11:48
add a comment |
I think the “bad practise” idea comes from the fact that this form :
char string = "october is a nice month";
makes implicitly a strcpy from the source machine code to the stack.
It is more efficient to handle only a link to that string. Like with :
char *string = "october is a nice month";
or directly :
strcpy(output, "october is a nice month");
(but of course in most code it probably doesn’t matter)
- Wouldn’t it only make a copy if you attempt to modify it? I would think the compiler would be smarter than that
– Cole Johnson
Sep 2 ’15 at 23:38
- What about cases like
char time_buf = "00:00";where you’re going to be modifying a buffer? A
char *initialized to a string literal is set to the address of the first byte, so trying to modify it results in undefined behavior because the method of the string literal’s storage is unknown (implementation defined), while modifying the bytes of a
charis perfectly legal because the initialization copies the bytes to a writeable space allocated on the stack. To say that it’s "less efficient" or "bad practice" without elaborating on the nuances of
char* vs charis misleading.
– Braden Best
Aug 8 ’16 at 16:49
add a comment |
Never is really long time, but you should avoid initialization char to string, because, “string” is const char*, and you are assigning it to char*.
So if you pass this char to method who changes data you can have interesting behavior.
As commend said I mixed a bit char with char*, that is not good as they differs a bit.
There’s nothing wrong about assigning data to char array, but as intention of using this array is to use it as ‘string’ (char *), it is easy to forget that you should not modify this array.
- 2Incorrect. The initialization copies the contents of the string literal into the array. The array object isn’t
constunless you define it that way. (And string literals in C are not
const, though any attempt to modify a string literal does have undefined behavior.)
char *s = "literal";does have the kind of behavior you’re talking about; it’s better written as
const char *s = "literal";
– Keith Thompson
Jan 17 ’13 at 21:48
- indeed my fault, I mixed char with char*. But I wouldn’t be so sure about copying content to array. Quick check with MS C compilator shows that ‘char c = "asdf";’ will create ‘string’ in const segment and then assign this address to array variable. That’s actually a reason why I said about avoiding assignments to non const char array.
Jan 18 ’13 at 7:45
- I’m skeptical. Try this program and let me know what output you get.
– Keith Thompson
Jan 18 ’13 at 8:04
- 2"And in generally "asdf" is a constant, so it should be declared as const." — The same reasoning would call for a
int n = 42;, because
42is a constant.
– Keith Thompson
Jan 18 ’13 at 8:21
- 1It doesn’t matter what machine you’re on. The language standard guarantees that
cis modifiable. It’s exactly as strong a guarantee as the one that
1 + 1evaluates to
2. If the program I linked to above does anything other than printing
EFGH, it indicates a non-conforming C implementation.
– Keith Thompson
Jan 18 ’13 at 15:40
show 3 more comments
protected by gnat Apr 2 ’17 at 21:58
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count ).
Would you like to answer one of these unanswered questions instead?
Not the answer you’re looking for? Browse other questions tagged c programming-practices strings array or ask your own question .
5 years, 7 months ago
6 months ago
Best practice Java – String array constant and indexing it
When comparing a string variable to a string literal with .equals(), is there a standard practice for the order of items?
How to avoid the pitfalls of static analysis
Complex string matching with fuzzywuzzy
Is it considered bad practice to access a returned array by a key straight away?
exception for string literal conventions
Is “string literal” always the same as “hard-coded string”?
Should I add 1 to my unknown string size when I create a char array to hold it via malloc?
Is it bad practice to store certain values as strings?
Is it bad practice to force array key sequence on future maintainer/developer?
Hot Network Questions
How useful is an impregnable castle?
How to set up a persistent TCP gender-changer proxy?
Colleague blocks change request in peer review because of perceived mistakes in code, but suggested improvements do not work
Is there a less pejorative term than "woolgathering" to label purposeful thought that ranges a narrow gamut
S and P 500 Prediction
How can I adjust playing two keys an octave apart to something that I can reach with a spread of 8 keys?
Find files by pattern and copy to target location
Is it possible to define "Straight-line" logically? If it is possible, How you will define it?
How do I communicate to my players that a door is, for the time being, absolutely locked to them?
Are there examples of conjectures supported by heuristic arguments that have been finally disproved?
How can I explain why my mechs don’t sink into the ground?
Who’s not welcome here?
How would one attack or lay siege to a flying castle?
How to express my concerns to a pontentially new landlord?
Unity3d – Do I need to destroy gameobject AND script?
Kid throwing ice cream cone back to the vendor
g++ 8.1 template deduction ambiguity with std flag equal to c++17
I am what you might find in a ghost town
Is it possible to start a PhD at 36 without taking a huge hit financially?
Pokémon Go Friends Limit?
Short story about free will and a device which buzzes/lights up moments before you press it
Two long sharp teeth
IT will only give password over phone – but is that really more secure than email?
more hot questions
C++ (programming language)
C (programming language)
What is the difference between char* and char?
, works at Agicent Technologies
1) char *
Let’s start with two programs.
/ * Program1.c */ int main() char *p1 = "Hello"; p1 = A; // Error: Segmentation fault return 0;
int main() char chr = Z; char *p1 = "Hello"; p1 = &chr; // OK: Value of p1 can be changed return 0;
So, if you compile these two programs, both of them compile without any error. But when you execute Program1.c it will give Segmentation Fault (on Linux) or Access violation (on Windows).
Well, it’s predictable. You see, two things involved here:
p1 is just a char pointer, we have not written anything that makes it a constant. This guy will just hold the address of a memory location. And Data Type of that location shall be a char. However, "Hello" is a string literal, its a constant and p1 holds the starting address of this char array or string literal. Diagrammatically,
So p1 is innocent guy just holding a memory address, however, but the memory location starting from 3197 is read-only as it holds a string literal or string constant. So if you try to update that via p1 it will give segmentation fault or access violation. You are not allowed to modify that. You cant modify any location from 3197 to 3202.
2) char 
Before proceeding further lets have a look what the classical text on C Programming has to say about this:
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a variable; constructions like a=pa and a++ areillegal.
– The C Programming Language by Brain W. Kernighan & Dennis M. Ritchie
So, technically, when you write int a you declare a kind of constant pointer holding the address of first location of 10 consecutive memory locations.
Now the story is completely reversed. In this case
int main() char p1 = "Hello"; p1 = A; // Valid return 0;
Valid, because the location where string literal is not a CONSTANT (though bounded by length).
int main() char chr = Z; char p1 = "Hello"; p1 = &chr; // Error: p1 is not a valid L-Value return 0;
, C++ programmer
char* is a pointer to char. An object of that type may be initialized with the address of a char that exists elsewhere:
char c = a; char* p = &c;
(it may also point at a char that is an element of some char array, such pointers are often used for string manipulations in C)
char is an array of unknown number of char. That is an incomplete type, and an object of incomplete type cannot exist
char a; // error: cant allocate unknown number of bytes
However, incomplete type may be used in some ways:
extern char b; // okay: another file allocated the bytes char c = a, b, c; // okay: the initializer tells us // this is really char char d = "abc"; // okay: the initializer tells us // this is really char
A function declared to take a parameter of type char is automatically converted to a function that takes a parameter of type char* before it is compiled:
void f(char) // declares a function of type void(char*) void f(char*); // declares the same function
, Ph.D. from Polytechnic University of Catalonia (1993)
Here there are very good answers to this question, in particular Kaushik Krishnakumars answer to What is the difference between char* and char? , so I will not repeat.
However I want to coment some things:
- char*, char and char are three different things.
- char* is a pointer to a char
- char is an incomplete type of an array of chars, it is incomplete because the size is missing.
- char is an array of 10 chars
One problem is that the incomplete type char decays to char*.
I think that the incomplete type has been the worst very good idea of Brian Kernighan and Dennis Ritchie when they were inventing the C language.
The decay to char* has been the second worst very good idea of those genius.
C++ has been forced to sustain those (bugs, miss conceptions, imprecisions, historical errors or whatever) very good ideas.
P.D.: I sustain that today C++ is “the best computer language”, if such thing exists. But, surely isnt perfect.
, I code in C
Let’s consider examples and proceed to the differences.
char a = "abcd"; char *p = a; printf("%s\n", a); // prints abcd printf("%s", p); // prints abcd
char a = "abcd"; char *p = "efgh"; printf("%s\n", a); // prints abcd printf("%s", p); // prints efgh
From example 2, It’s clear that, String constants represents the address.
Below I’ve listed the differences:
Hope, this is clear to you.
, Software Engineer
Pointers and arrays are fundamentally different: an array is a sequence of contiguous objects, and a pointer is an object that holds the address of another object.
But C++ has some features that make them look similar. First: in a function parameter list, char is a synonym for char*. You cant pass an array by value to a function.
Second: in most contexts, an expression of array type "decays" into a pointer to the first element of that array. Thats why you can write:
char A = "hello"; char *B = A; // equivalent to: char *B = &A;
A and B are similar in some ways: for example, they compare equal with ==. But they are different:
- sizeof(A) is 6 (length of the string, plus one for the null terminator), but sizeof(B) is the size of a pointer
- you cannot assign to an array, but B can be reassigned to point to a different char
- &A is a pointer to the entire char array; its type is char(*). &A + 1 will point past the end of it, unlike B + 1, which points to the second char (e). &B is a pointer to a pointer (char**).
, Computer engineer
char *valA = "value";
allocates two objects: a char pointer in the programs data section (typically four or eight bytes in size) and a const array of (in this case six) chars in the read-only data section. A NUL terminator is included as the last char of the array. valA is initialized by the linker with the address of the first of these chars. The program may reassign valA to point somewhere else, but the chars that valA initially points to may not be modified. Where an element of valA such as valA is referenced, the compiler must use two load instructions, one to load the pointer from varA, and one to load a char from the pointed-to address. sizeof (valA) equals the pointer size, typically 4 or 8.
The completely different construct
char valB = "value";
allocates one object, an array of (in this case six) chars in the data section. valB is a fixed (immutable) symbol whose value is the address of the first of these chars. The program is free to modify these chars. Where an element of valB such as valB is referenced, the compiler need only use one char load instruction to an absolute address. sizeof (valB) equals the NUL-terminated array size, in this case 6.