GoinOff
GoinOff

Reputation: 1802

overlapping memmove best practice

I have a question about the 3rd parm to memmove when manipulating a string. strlen(string) and strlen(string) + 1 seem to produce the same results. I would think that the +1 part would include a termination \0 but everything seems to work fine with both. Is there a best practice here to consider?? I've seen examples of both and I am not sure which way to go on this??

Consider the following c program:

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

int main()
{
   char string1[20]="Hello World";
   char string2[20]="Hello World";
   printf("\nstring1=\"%s\"\n",string1);

   memmove(string1,string1+6,strlen(string1) + 1);

   printf("\nstring1 after memmove \"%s\" using strlen(string1) + 1\n",string1);

   printf("\nstring2=\"%s\"\n",string2);

   memmove(string2,string2+6,strlen(string2));

   printf("\nstring2 after memmove \"%s\" using strlen(sting2)\n",string2);

   return 0;
}

Output:

string1="Hello World"

string1 after memmove "World" using strlen(string1) + 1

string2="Hello World"

string2 after memmove "World" using strlen(sting2)

Upvotes: 0

Views: 359

Answers (4)

John Kugelman
John Kugelman

Reputation: 361849

Since you're starting at index 6 both strlen(...) and strlen(...) + 1 are overkill and are copying extra NUL bytes past the end of the strings. It happens to work because you made oversized char[20] arrays so there are indeed extra NULs. Extra array slots are filled with zeros as if you'd written:

char string1[20] = "Hello World\0\0\0\0\0\0\0\0\0";

You should be subtracting 6 from both. If you do that you'll see that strlen(... + 6) + 1 or strlen(...) + 1 - 6 are what you want. Remove the + 1 from either of those and it won't copy the NUL terminator, leading to a different result:

string1 == "World\0World\0\0\0\0\0\0\0\0\0"  // with + 1, NUL copied
string2 == "World World\0\0\0\0\0\0\0\0\0"   // without + 1, NUL missing

Upvotes: 4

Petr Skocik
Petr Skocik

Reputation: 60067

You are moving extra nul bytes. The length of the right-hand side of is strlen(string1)-6. When you move strlen(string1), you're moving an extra 6 nul bytes after the right hand side of the string, and they're there because with char string1[20]="Hello World";, the uninitialized bytes get initialized to \0.

Upvotes: 0

Andrew Henle
Andrew Henle

Reputation: 1

The definition of a string includes the terminating '\0' character.

Not explicitly copying that terminating character but still treating the result as a null-terminated string is undefined behavior.

There is no "best practice" here other than not relying on undefined behavior.

Upvotes: 1

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215357

Your length logic is totally off and it's only working because the buffer is over-sized and the rest of it contains null bytes anyway. Rather than strlen(string1) vs strlen(string1)+1, it should be strlen(string1+6) vs strlen(string1+6)+1. You'll find in that case that the difference does matter, as you expect.

Upvotes: 2

Related Questions