Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I don't remember how I got to the thread, but I was reading its replies and one of them states that you should never initialize a char[] with a string literal.

My question: Is initializing a character array with a string literal a bad practice or is that just the author's opinion?


Here is the original question:

strlen vs sizeof

Code:

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

share|improve this question
2  
And your question would be? –  thorsten müller Jan 16 '13 at 16:27
1  
and your question is? –  ratchet freak Jan 16 '13 at 16:27
5  
Could you please include as much external material as reasonable so that one doesn't need to go to external sites to understand the nature of the question (once the question is identified)? –  MichaelT Jan 16 '13 at 16:36
    
Whoever stated it was confused, simple as that. –  user29079 Jan 17 '13 at 11:57
2  
Isn't this more appropriate for Stack Overflow? –  Keith Thompson Jan 17 '13 at 21:51
show 2 more comments

4 Answers

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

share|improve this answer
2  
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 Jan 16 '13 at 17:03
1  
@JohnBode - thanks, and those are good points. I have incorporated your comment into my answer. –  GlenH7 Jan 16 '13 at 17:16
1  
More precisely, most references to the array name string result 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 string[0] is 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
add comment

you should never initialize a char[] 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";

or

char string[8] = "october";

or

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

or

char string[8];
string = "october";

etc. In the first case, the declaration of string is incomplete because no array size has been specified. 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. Also, 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.

By that same token, you can't write

char string[] = foo;

where foo is another array of char. This form of initialization will only work with string literals.

EDIT

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

or

char string[] = {111, 99, 116, 111, 98, 101, 114, 0}; // assumes ASCII

but it's easier on the eyes to use string literals.

EDIT2

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

or

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!
share|improve this answer
2  
    
@KeithThompson: not disagreeing, just added it for completeness' sake. –  John Bode Jan 17 '13 at 21:58
    
You have a syntax error. 99. 116 is a float, not 'c', 't'... –  Cole Johnson Apr 29 '13 at 16:23
    
This was clearly a typo, now fixed. –  JBRWilkinson May 6 '13 at 20:38
    
Please note that char[8] 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 seprate to separate will break if size not updated. –  djechlin May 14 '13 at 21:22
add 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.

share|improve this answer
    
Incorrect. The initialization copies the contents of the string literal into the array. The array object isn't const unless 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. –  Dainius 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
    
Logically, given char c[] = "abcd";, the string literal denotes a 5-byte array that may (or may not) be stored in some kind of read-only memory, and the initialization copies its contents into c, which is writable. Since the literal is only referred to once, and its address is not used, the compiler has chosen to optimize it away, storing the bytes directly into c -- which is a perfectly valid optimization. No compiler will allocate c to read-only memory (unless perhaps it can prove that the program never modifies it). I promise you that c is modifiable. –  Keith Thompson Jan 18 '13 at 8:20
    
"And in generally "asdf" is a constant, so it should be declared as const." -- The same reasoning would call for a const on int n = 42;, because 42 is a constant. –  Keith Thompson Jan 18 '13 at 8:21
show 2 more comments

The only problem I recall is assigning string literal to char *:

char var1[] = "september";
var1[0] = 'S'; // Ok - 10 element char array allocated on stack
char const *var2 = "september";
var2[0] = 'S'; // Compile time error - pointer to constant string
char *var3 = "september";
var3[0] = '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[0] = '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[32] = "May";
strncpy(buf, "September", sizeof(buf));

As last remark - I wouldn't use strcpy at all:

char buf[8];
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[1024];
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.
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.