4

A string constant in C is stored as a character array, while creating such an array element by element, is it necessary to supply the null character.

I need to store a string constant, say, S[number]= "hello\n". A string constant is stored as a character array in C, further, such a string is terminated by a null character '\0'. While storing the phrase in an array, do I need to account for the null character and allocate an additional space or do I just need to mention the number of characters that I need to store?

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Learner Boy
  • 41
  • 1
  • 4

3 Answers3

7

If you are going to use C-string functions, like strlen, - then answer is YES. Your string should be null-terminated. If you introduce your custom functions to deal with string - you can store it however you like.

It's important to mention, that if you create an array using string constant, it reserves space for null-character automatically. E.g. output for the following code:

char s[] = "hello";
printf("%d", sizeof(s) / sizeof(char));

is

6

which is 5 for 'h, 'e', 'l', 'l', 'o' and 1 for '\0'.

Denis Kulagin
  • 8,472
  • 17
  • 60
  • 129
  • As an aside, sizeof(char) is redundant. – Peter - Reinstate Monica Apr 25 '14 at 07:38
  • @PeterSchneider Why is it reduntant? If you imply, that we know sizeof(char) apriory - it's not a good practice to count on such assumptions in general. – Denis Kulagin Apr 25 '14 at 07:43
  • @DenisKulagin We do know it, `sizeof (char)` is 1. Always. – unwind Apr 25 '14 at 07:47
  • 2
    @unwind It's not the point! You can omit it in production code, but if it's a sample, which my snippet definitely is, I better write it this way to emphasize, that *sizeof* returns number of bytes and not number of elements. – Denis Kulagin Apr 25 '14 at 07:53
  • A char may (and if I may make a wild guess routinely will at some point in my life time) have more than 8 bits, but that will just indicate that it doesn't make any sense on that [machine|cloud|fuzzy hybrid borg computational entity] to address or move around less than n (n>8) bits and nobody cares about the wasted space. Because the space is vast and empty, yet. Even then sizeof(char) == 1 will hold. – Peter - Reinstate Monica Apr 25 '14 at 07:58
  • 1
    @DenisKulagin Sure, it's idiomatic for number of elements in an array. Still, I think it's better to write it `sizeof s / sizeof *s` in that case, stops you from repeating the type and (possibly) using the wrong type if the type of the array changes. – unwind Apr 25 '14 at 07:58
  • @PeterSchneider Just to clarify, even on those machines, `sizeof (char)` will be 1. – unwind Apr 25 '14 at 07:59
  • @unwind: True. That was my point but I may not have made it clear enough :-) – Peter - Reinstate Monica Apr 25 '14 at 08:01
  • 1
    More importantly, this causes undefined behaviour as `size_t` does not match `%d` ... either cast the value to `(int)`, or use `%zu` in C99 or later. – M.M Apr 25 '14 at 08:02
  • @MattMcNabb In Microsoft's compiler %zu is not exists then `%lu` should be used – Grijesh Chauhan Apr 25 '14 at 08:04
  • @DenisKulagin: so if i define a char Array[len], you mean to say that the location Array[len] contains '\0' ? because my string will go from 0 to len-1. – Learner Boy Apr 25 '14 at 08:39
  • @Mr. Sherlock. If you define a char array of size *len*, then null-character should be put to index *len - 1*. Which means, that you have one less byte for your string contents. E.g. to store string "hello" you should do: **char s[6] = "hello";** Otherwise it will result in errorneous and unpredictable behaviour. – Denis Kulagin Apr 25 '14 at 08:50
6

While storing the phrase in an array, do I need to account for the null character and allocate an additional space or do I just need t mention the number of characters that I need to store?

Yes, you should count null chars to allocate additional space. You must note Important point here:

S[number]= "hello\n";

Will append \0 in S[] array if number value is equals to (or grater than) length of string "hello\n" pule one for \0 char (or if you don't give size at all as s[] = "hello\n";).

From: ISO/IEC 9899:201x Committee Draft April 12, 2011 N1570:

6.7.9 [Initialization]

[...]
14: An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
[..]
EXAMPLE 8 The declaration

char s[] = "abc", t[3] = "abc";

defines ``plain'' char array objects s and t whose elements are initialized with character string literals. This declaration is identical to:

  char s[] = { 'a', 'b', 'c', '\0' },
       t[] = { 'a', 'b', 'c' }; // you are missing this point

The contents of the arrays are modifiable. On the other hand, the declaration

 char *p = "abc";

defines p with type pointer to char'' and initializes it to point to an object with typearray of char'' with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.

So as I commented to your question: it depends on value of number you give in declaration in declaration. it may add '\0' char (in most cases) or may not add (in one valid declaration). This is very important point that most answers are missing.

More preciously:

Note "hello" is six char long string (including string termination nul char '\0' )

S[6]= "hello";

is same as:

S[6]= {'h', 'e', 'l', 'l', 'o', '\0'};
// ^ is 6

But

S[5]= "hello";

is valid in C, But don't append nul \0 char. It is equivalent to:

S[5]= {'h', 'e', 'l', 'l', 'o'};
// ^  is 5 

Now this is very important to note, In this declaration, if size is given five = 5 in declaration then you can use loop to print chars as for(i = 0; i < sizeof(S); i++), but you can't use %s or functions like strcpy on S[] — using this call undefined behavior.

Beside this, I would also suggest you always use -Wall and -pedantic flag when you compiles your code. Now see how this works:

Lets compile this code, with char s[4] = "hello"; :

int main(){
  char s[4] = "hello";
  int i = 0;
  for (i = 0; i < sizeof s; i++) 
   printf("%c", s[i]);
  printf("\n");
  return 0;
}

You will get a warning as follows:

$ gcc -Wall -pedantic x.c
x.c: In function ‘main’:
x.c:3:15: warning: initializer-string for array of chars is too long 
[enabled by default]

But code is valid in C with char s[5] = "hello"; compile same code it will not give any warning to you that also implies it is a valid code but obviously it don't add \0.

#include <stdio.h>
int main(){
  char s[5] = "hello";
  int i = 0;
  for (i = 0; i < sizeof s; i++) 
   printf("%c", s[i]);
  printf("\n");
  return 0;
}

Check this (you should notice this time compiler don't emits any warning):

$ gcc -Wall -pedantic x.c
@:~$ ./a.out 
hello

But this time we should use printf("%s", s); it will call undefined behavior.

So when you create an array with string literal then better is to avoid size in declaration, as:

  char s[] = "hello";

But this is just same as char s[6] = "hello"; And you can't append a new char(s) to s[] as strcat(s, " world!").

If you intended to modify s[] latter in your code then you may like to create a string of sufficiently large size as:

 char s[100] = "hello";

Now strcat(s, " world!") is perfectly valid code.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • sir, suppose, i have allocated a char array as follows s[1000] and i now wish to store "hello\n" in it, so, in order for the program to take it as a string hello and then a new line, i must make the following assignments s[0]="h",s[1]="e",s[2]="l",s[3]="l",s[4]="o",s[5]="\n",s[6]="\0" ? what would be the issues i would face in case i don't make the last assignment? – Learner Boy Apr 25 '14 at 08:47
  • @Mr.Sherlock Yes, if you declares `char s[1000];` then contents of `s[]` are garbage that time you have to explicitly store `'\0'` as `s[6] = '\0'` (note use single **`'`**, not double `"` for chars). You could also use strcpy function as `strcpy(s, "hello\n");` Now you may like to read this answer [What does sizeof(&array) return?](http://stackoverflow.com/questions/15177420/what-does-sizeofarray-return/15177499#15177499) In which I tried to explain strings – Grijesh Chauhan Apr 25 '14 at 08:59
  • 1
    @Mr.Sherlock Point to be note `"1"` is a string, `'1'` is a char, `1` is an singed integer, `1u` or `1U` are unsigned integer one. All are different. – Grijesh Chauhan Apr 25 '14 at 09:05
  • correctly pointed out, my bad. thank you sir. just another doubt that i forgot to ask earlier. is char S[6]="hello\n" a valid assignment as a string ? – Learner Boy Apr 25 '14 at 09:38
  • @Mr.Sherlock Yes `char S[6]="hello\n"` is valid in C (but not in C++). Important point to note as I explained in my answer if you decelerates `S[]` as `char S[6]="hello\n"` then `'\0'` terminating null char **is not** append in `S[]` this declaration is same as `S[6]= {'h', 'e', 'l', 'l', 'o', '\n'};` (no null termination) and you must not use it in `printf()` with `%s`, or string.h functions like `strlen()` because these excepts a null terminated strings. I would suggest you read my answer again. – Grijesh Chauhan Apr 25 '14 at 10:04
  • yes sir i did, and that's why asked again to conform. Thank You very much :) – Learner Boy Apr 25 '14 at 10:42
2

No, but you should leave out number

char S[]= "hello\n";

will have the trailing 0 character and the array sized as needed.

With number too small you could accidentally cut off the 0 character.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177