4

I have the following code.

#include <stdio.h>
#include <string.h>

#define MAXLINE 1000

int main()
{
    int i;
    char s[MAXLINE];

    for (i = 0; i < 20; ++i) {
        s[i] = i + 'A';
        printf("%c", s[i]);
    }

    printf("\nstrlen = %d\n", strlen(s)); // strlen(s): 20
    return 0;
}

Should I write

s[i] = '\0';

explicitly after the loop executing to mark the end of the string or it is done automatically? Without s[i] = '\0'; function strlen(s) returns correct value 20.

alk
  • 69,737
  • 10
  • 105
  • 255
ljosja_
  • 91
  • 2
  • 8
  • 9
    `strlen` requires a terminated string. If you don't provide one (a properly terminated string) you're invoking *undefined behavior*. If the code you have above "works" it is by chance, not design. Don't code by chance. – WhozCraig Jan 01 '20 at 14:28
  • 2
    In your example it just happened that the array previously contained zeros, but it is not necessarily so. Always terminate the string. – Weather Vane Jan 01 '20 at 14:29
  • 1
    Before using `strlen` and after loop,do `s[i+1]='\0'` or even before loop use `memset(s,'\0',sizeof(s))`. Else functions like `strlen` won't work properly. – Gaurav Jan 01 '20 at 14:32
  • @Observer: "*use `memset(s,'\0',sizeof(s))`*" doing just `char s[MAXLINE] = "";` then would be simpler, I feel. – alk Jan 01 '20 at 14:33
  • @alk True - but that holds validity only at initialization for subsequent times `memset` will be needed. – Gaurav Jan 01 '20 at 14:36
  • @Observer @alk In the context of that program, zeroing the **whole** `char` array is completely useless and just wasting time, though not wrong. – Lxer Lx Jan 01 '20 at 14:38
  • 1
    @Observer `s[i]='\0'` after the loop is simplest and requires one byte only to be written. – Weather Vane Jan 01 '20 at 14:39
  • 4
    besides `strlen` returns `size_t` so you must [print the result with `%zu`](https://stackoverflow.com/q/940087/995714) – phuclv Jan 01 '20 at 14:49

3 Answers3

5

Yes, you need to add a null terminator yourself. One is not added automatically.

You can verify this by explicitly initializing s to something that doesn't contain a NUL at byte 20.

char s[MAXLINE] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

If you do that strlen(s) won't return 20.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
5

Yes, you should add the null terminator after the loop. Alternatively, you could initialize the entire array with 0. That way, you don't have to add a 0 after the loop because there is one already:

...
char s[MAXLINE] = {0};
...
machine_1
  • 4,266
  • 2
  • 21
  • 42
  • 4
    ... and the particular syntactic variant presented here is a standard idiom for default-initializing *any* automatic variable, of any type. One should note that it only works as an initializer, though, not as an assignment statement. – John Bollinger Jan 01 '20 at 14:54
  • This is Sub-Optimal, as this will result in more code. This approach will write zeros on more memory than needed, writing 1000 zeros instead of just one (and some of the zeros will be overwritten). – Myst Jan 01 '20 at 15:43
1

You MUST add a NUL terminator to mark the end of a C string.

Adding a NUL terminator character isn't automatic (unless documentation states that a function call writes the NUL terminator character for you).

In your case, use:

s[20] = 0;

As mentioned in the comments, C strings are defined by the terminator NUL character. The NUL character is required also by all the strXXX C functions.

If you don't mark the end of the string with a NUL, you have a (binary) sequence of characters, but not a C string. These are sometimes referred to as binary strings and they cannot use the strXXX library functions.

Why do you get Correct Results

It is likely that you get correct results mostly by chance.

The most probable explanation for the correct results is that the OS you are using provides you with a "clean" memory stack (the initial stack memory is all zero)... this isn't always the case.

Since you never wrote on the stack memory prior to executing your code, the following byte is whatever was there before (on your OS, that byte was set to zero when the stack was first initialized).

However, this will not be true if the OS does not provide you with a "clean" stack or if your code runs on a previously used stack.

Myst
  • 18,516
  • 2
  • 45
  • 67
  • The wording "You MUST add the NUL terminator to the end of the string" doesn't sound correct to me. _By definition_, the terminating null character is already contained in the string. Basically, a string is a sequence of characters terminated by (and including) the null character. So, "to add a null character to string" means to add an extra null character to the end of string, which is unnecessary. – Lxer Lx Jan 01 '20 at 15:29
  • @LxerLx - I understand your point of view. I updated the answer. Any better? – Myst Jan 01 '20 at 15:40
  • 2
    It seems better now. I think it is important, in the context of this question, to emphasize that if a sequence of characters does not end with the null character then it is not a string. – Lxer Lx Jan 01 '20 at 15:53