-4

I am fairly novice to c/c++ and I was trying to determine the best way to terminate a string when I ran across this.

I think I understand whats going on with incrementing a pointer and dereferencing it to a value of '\0'. The problem is, when I do it it doesn't work.

    int main()
{
    const char* c = "1234567890";
    char* c1 = (char*) malloc(sizeof(char)*4);
    strncpy( c1, c, 3 );
    printf( "%s\n",c1 );
    *c1++ = '\0';
    printf( "%s\n",c1 );
}

The output is 123 23

It appears that the null value is being dropped at the beginning of the string as opposed to immediately after. Why?

Community
  • 1
  • 1
mreff555
  • 1,049
  • 1
  • 11
  • 21
  • 4
    `*c1++ = '\0';` doesn't do what you think it does. – tkausl Jun 21 '16 at 23:34
  • Doh! I think I just got it. Since it's a char, not an int, it's only advancing one byte. – mreff555 Jun 21 '16 at 23:38
  • This code exhibits undefined behavior. The call to `strncpy` copies the first three characters of `c` to `c1`, but it does *not* null-terminate the result. So the string pointed to by `c1` may or may not be properly terminated. Don't do it. In your case, it *happened* to have a null byte where you needed it, but you can't rely on that. – Tom Karzes Jun 21 '16 at 23:51
  • This code has an error. Since c is longer than3, stncpy will not add a null terminator. – stark Jun 21 '16 at 23:51
  • `c1++` don't alter a pointer that you (should) `free`. – Weather Vane Jun 22 '16 at 00:05
  • Tom, Weather Vane, I think you guys are missing the point. I realize pointers should be free in production code, but since this is a main function which abruptly ends I think it should be ok. Tom, I know the first print statement is not null terminated, but if you read the statement associated with the supplied code you will realize what I am trying to do is determine the best way to do that. – mreff555 Jun 22 '16 at 00:09
  • `c1` is never guaranteed to be null-terminated in either `printf`. You need to add `c1[3] = '\0';` before or after the call to `strncpy`. The answer you accepted is blatantly incorrect in its claim that `strncpy` will add a null byte that was not present in the source string. You just need to read the man page for `strncpy`. It's also trivial to test, since the `strncpy` call doesn't touch `c1[3]` at all. – Tom Karzes Jun 22 '16 at 00:37
  • Adding `c1[3] = '\0';` is guaranteed to solve the problem, since either a null byte was copied from `c` earlier in the string, or else it wasn't in which case this fixes it. – Tom Karzes Jun 22 '16 at 00:40

1 Answers1

1

This line:

*c1++ = '\0';

does:

  1. Evaluate the variable c1. It's a pointer to an allocated block of 4 bytes.

  2. De-reference the pointer with *, which is now the first byte pointed to by c1.

  3. Assign the value '\0' to that byte, overwriting the '1' that was there.

  4. Add 1 to c1. Now it points to the second byte of those 4 you allocated, which contains a '2'.

Later, when you print c1 as a string, it starts at the 2 where you left it, and ends at the terminating '\0' that just happened to be in the last byte of your allocated region that never got set.

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55
  • This is incorrect. `strncpy` does *not* insert a terminating null byte unless it was copied from the original string. The call to `strncpy` will not write more than 3 bytes of `c1`. The code posted by OP exhibits *undefined behavior*, since there is no guarantee that `c1` is properly terminated. Look at the man page for `strncpy`. – Tom Karzes Jun 22 '16 at 00:26
  • Hmm. I thought strncpy did add the zero. I'll look at it more closely. – Lee Daniel Crocker Jun 22 '16 at 00:29
  • It's very clear from the man page. If you want to test it, add `c1[3] = 'x';` before the call to `strncpy`. You will see the `x` appear in the output, which contradicts your claim. – Tom Karzes Jun 22 '16 at 00:33