1

I have to rewrite for an assignment a function that mimics the behavior of the strncpy, after many trials and error, some external help, here's the final code :

 15 char    *ft_strncpy(char *dest, char *src, unsigned int n)
 16 {
 17     unsigned int i;
 18     unsigned int size;
 19
 20     i = 0;
 21     size = 0;
 22     while (src[i] && i < n)
 23     {
 24         dest[i] = src[i];
 25         i++;
 26     }
 27     while (i < n)
 28     {
 29         dest[i] = '\0';
 30         i++;
 31     }
 32     return (dest);
 33 }

It works flawlessly, but I don't get this part :

 while (i < n)
 {
     dest[i] = '\0';
     i++;
 }

At this point, the value of i should be (n - 1) right ? So '\0' goes into dest[n-1] and the loop ends because i becomes equal to n and then the function ends.

We're left with a string that would look something like this :

"string copied\0not copied part"

And be printed like : string copiednot copied part.

My question is :

  • Why does dest[n-1]='\0' or dest[n]='\0' instead of that while loop, return string copied instead of 'string copiednot copied part' when they basically do the same thing ?

  • Why does the \0 seem to be 'ignored' when printed out after the while loop, when it's considered a full stop when I use dest[n-1] = '\0' instead ?

Here's the main/alternative function I used to run test and try to understand :

int main()
{
     char str[] = "test de chaine";
     char *str2 = "chaine de test";

     ft_strncpy(str, str2, 6);
     printf("%s", str);
     return 0;
}

char    *ft_strncpy(char *dest, char *src, unsigned int n)
 {
     unsigned int i;
     unsigned int size;

     i = 0;
     size = 0;
     while (src[i] && i < n)
     {
         dest[i] = src[i];
         i++;
     }
         dest[n-1] = '\0';
     return (dest);
 }
Jib
  • 45
  • 1
  • 5

3 Answers3

2

the value of i should be (n - 1) right ?

This is not necessarily the case, since the first while loop exits when it encounters a \0 character (even if i is less than n-1).

The while-loop is used to ensure the remainder of the dest array is properly initialized to \0.

The "wrong" behavior you are seeing (the string being printed beyond the end of the copied string) is due to the fact that both loops exit with the same condition: the first loop exits when i becomes n and since the second loop has the check i<n, it does not run.

This corresponds to the behavior described in the manual:

The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

If you were to copy a string str with the value abc, it would properly display it in the example below:

#include <stdio.h>

char    *ft_strncpy(char *dest, char *src, unsigned int n)
{
    unsigned int i;
    unsigned int size;

    i = 0;
    size = 0;
    while (src[i] && i < n)
    {
        dest[i] = src[i];
        i++;
    }
    while (i < n)
    {
        dest[i] = '\0';
        i++;
    }
    return (dest);
}

int main()
{
     char str[] = "test de chaine";
     char *str2 = "abc";

     ft_strncpy(str, str2, 6);
     printf("%s\n", str);
     return 0;
}
Simon Doppler
  • 1,918
  • 8
  • 26
  • When you have a buffer passed as a param to write things in it, you always need to have another param for the size of this buffer. – Tsakiroglou Fotis Feb 19 '19 at 16:51
  • @TsakiroglouFotis this is true in general, but the C-library `strncpy` function does not, since it assumes the destination buffer is big enough (many C library functions do assume things like this), which is why it is acceptable in the case of a reimplementation like this. – Simon Doppler Feb 19 '19 at 17:01
  • Do you mean strcpy?Because -n- in strncpy is the size.It's truth that strcpy assumes that there is enough space.I was speaking though for function we make, like ft_strncpy here. – Tsakiroglou Fotis Feb 19 '19 at 17:10
  • 1
    I meant to say that `strncpy` does not really care about the size of the buffers but only the amount of characters you want to copy. It is still our job to ensure the number of copied bytes is correct (which is only a different way of making sure the stop condition will be met, in the same way we have to make sure there is a null byte at the end of the buffer with `strcpy`). You are however correct that using a buffer size argument is the good practice in C. – Simon Doppler Feb 19 '19 at 17:38
  • Failed corner case: Code is UB when `n==0` and code attempts `while (src[0] && ...` Better to use `while (i < n && src[i])` – chux - Reinstate Monica Feb 20 '19 at 01:27
  • `strncpy(char *dest, const char *src, size_t n)` uses `size_t`, not `unsigned int n`. – chux - Reinstate Monica Feb 20 '19 at 01:28
1

strncpy() is specified as writing exactly n bytes, independently of the length of the source string.

strncpy(dst, "foo", 5); // writes 'f', 'o', 'o', 0, and 0
strncpy(dst, "foo", 3); // writes 'f', 'o', and 'o': dst is not a string now (*)
strncpy(dst, "foo", 1); // write 'f': dst is not a string now (*)
// (*) unless you make sure there is a '\0' somewhere else in dst
pmg
  • 106,608
  • 13
  • 126
  • 198
  • 1
    ...and without the second `while` loop, the function will only write `strlen(src)` bytes. – Caleb Feb 19 '19 at 16:59
0

You need to understand that while they look similar,a char array is not a string while a string is a char array.Some functions (i.e. string.h ones) will read each byte one after the other and will stop when they meet '\0'.So check this example and you'll have a different view.

int main()
{
     char str3[] = "This is a test";

     printf("\n %s", str3);
     str3[5] = '\0';
     printf("\n %s \n", str3);
     int i = 0;
     for(i = 0 ; i < strlen(str3) ; i ++)
     {
         printf(" %c -",str3[i] );
     }
     printf("\n");
     for(i = 0 ; i < 12 ; i ++)
     {
         printf(" %c -",str3[i] );
     }
     return 0;
}

What we print is not what we have in memory.Especially using %s will stream the char array and stop when hit '\0'. Is what happens in this example clear to you?