How does C know the end of my string?

I have a program in which I wanted to remove the spaces from a string. I wanted to find an elegant way to do so, so I found the following (I've changed it a little so it could be better readable) code in a forum:

char* line_remove_spaces (char* line)
{ char *non_spaced = line; int i; int j = 0; for (i = 0; i <= strlen(line); i++) { if ( line[i] != ' ' ) { non_spaced[j] = line[i]; j++; } } return non_spaced;
}

As you can see, the function takes a string and, using the same allocated memory space, selects only the non-spaced characters. It works!

Anyway, according to Wikipedia, a string in C is a "Null-terminated string". I always thought this way and everything was good. But the problem is: we put no "null-character" in the end of the non_spaced string. And somehow the compiler knows that it ends at the last character changed by the "non_spaced" string. How does it know?

2

7 Answers

This does not happen by magic. You have in your code:

for (i = 0; i <= strlen(line); i++) ^^

The loop index i runs till strlen(line) and at this index there is a nul character in the character array and this gets copied as well. As a result your end result has nul character at the desired index.

If you had

for (i = 0; i < strlen(line); i++) ^^

then you had to put the nul character manually as:

for (i = 0; i < strlen(line); i++)
{ if ( line[i] != ' ' ) { non_spaced[j] = line[i]; j++; }
}
// put nul character
line[j] = 0;
3

Others have answered your question already, but here is a faster, and perhaps clearer version of the same code:

void line_remove_spaces (char* line)
{ char* non_spaced = line; while(*line != '\0') { if(*line != ' ') { *non_spaced = *line; non_spaced++; } line++; } *non_spaced = '\0';
}

The loop uses <= strlen so you will copy the null terminator as well (which is at i == strlen(line)).

You could try it. Debug it while it is processing a string containing only one space: " ". Watch carefully what happens to the index i.

How do you know that it "knows"? The most likely scenario is that you're simply having luck with your undefined behavior, and that there is a '\0'-character after the valid bytes of line end.

It's also highly likely that you're not seeing spaces at the end, which might be printed before hitting the stray "lucky '\0'".

A few other points:

  • There's no need to write this using indexing.
  • It's not very efficient to call strlen() on each loop iteration.
  • You might want to use isspace() to remove more whitespace characters.

Here's how I would write it, using isspace() and pointers:

char * remove_spaces(char *str)
{ char *ret = str, *put = str; for(; *str != '\0'; str++) { if(!isspace((unsigned char) *str) *put++ = *str; } *put = '\0'; return ret;
}

Note that this does terminate the space-less version of the string, so the returned pointer is guaranteed to point at a valid string.

1

The string parameter of your function is null-terminated, right? And in the loop, the null character of the original string get also copied into the non spaced returned string. So the non spaced string is actually also null-terminated!

For your compiler, the null character is just another binary data that doesn't get any special treatment, but it's used by string APIs as a handy character to easily detect end of strings.

If you use the <= strlen(line), the length of the strlen(line) include the '\0' so your program can work. You can use debug and run analysis.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like