0

I'm just learning about programming using the C language. Today, I'm trying to code my own strlcpy function and I am facing a problem.

To test my function I compare the results with the "official" function's ones. Everything works fine except... When I put 0 as the len arg. The strcpy function seems to put a garbage character in the destination string and I really don't understand why.

Here is the function's prototype: size_t strlcpy(char * restrict dst, const char * restrict src, size_t dstsize);

Thanks for your help!

Ok. I wanted to make a lot of tests, this is the reason why I'm calling the function inside of a loop.

Here is a part of my main function, testing the function:

do
{
    /* Ask for first string */
    printf("\nGive me a string (0 to stop): ");
    gets(str);

    /* Ask for a number */
    printf("Now, give me a number please: ");
    scanf("%d", &i);
    while (getchar() != '\n');

    /* I test with the "official function */
    j = strlcpy(str2, str, i);
    printf("Here is the expected result: %s\n", str2);
    printf("Num returned: %d\n", j);

    /* Now I test using my function */
    j = ft_strlcpy(str3, str, i);
    printf("Here is my result: %s\n", str3);
    printf("Num returned: %d\n", j);

}while (str[0] != '0');

And here is the function I've coded:

unsigned int    ft_strlcpy(char *dest, char *src, unsigned int size)
{
    unsigned int cpt;
    unsigned int i;

    cpt = 0;
    i = 0;
    while (src[cpt] != '\0')
        cpt++;
    if (size == 0)
        return (0);
    while (i < cpt && i < (size - 1))
    {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
    return (cpt);
}

In the function I'm not supposed to call any function from the standard library. My main is just here for testing. The function prototype is given by my teacher, this is the reason why I don't respect the original one.

Sorry fort the time I needed to put my code here and thank you for your help.

CodeKiwi
  • 71
  • 1
  • 9
  • Welcome to stackoverflow.com. Please take some time to read [the help pages](http://stackoverflow.com/help), especially the sections named ["What topics can I ask about here?"](http://stackoverflow.com/help/on-topic) and ["What types of questions should I avoid asking?"](http://stackoverflow.com/help/dont-ask). Also please [take the tour](http://stackoverflow.com/tour) and [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask). Lastly please learn how to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve). – Some programmer dude Jul 10 '18 at 09:40
  • Also please read [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/), and all of http://idownvotedbecau.se/ to learn some reasons your question might be down-voted. Finally, please [learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – Some programmer dude Jul 10 '18 at 09:40
  • 6
    _I'm trying to code my own strlcpy function_. Can you show your code? – H.S. Jul 10 '18 at 09:43
  • Can you show how do you call strlcpy function which results in that garbage character? – KamilCuk Jul 10 '18 at 10:48
  • Please post your code into your question and provide a [mcve] – Thomas Sablik Jul 10 '18 at 10:55
  • Yes sorry it was just a test I'm completely new here and I have some difficulties to put my code. Of course I didn't want you to check this unreadable bul***** – CodeKiwi Jul 10 '18 at 11:03
  • There is no `strlcpy` standard function. And **never ever** use `gets`! It has been removed from the standard 7 years ago and been deprecated for more than 19 years. – too honest for this site Jul 10 '18 at 13:28

3 Answers3

2

could you explain me where the "garbage character" comes from? What does the function do to find this character and to put it in the string? Even if it is not supposed to be called with a 0 len value.

The manual does not say that strlcpy is not supposed to be called with a 0 len value, it only says that it isn't NUL-terminating the result if dstsize is 0, i. e. it copies no characters at all to dst.

Your impression that it would put a "garbage character" into the destination string most probably results from dst being uninitialized from the start, and you looking at the unchanged, uninitialized dst.

Armali
  • 18,255
  • 14
  • 57
  • 171
  • 1
    You are completely right. This looks so stupid... Thanks a lot. Being a C newbie is not always easy... Have a nice day and thanks again. – CodeKiwi Jul 10 '18 at 11:38
1

First of all, I suppose you mistype in "...strlen function seems to put a garbage..." (strlcpy should be instead of strlen, because strlen put nothing to string - size_t strlen(const char *s);).

So you have a question about strlcpy.

As referencess said about the third argument of strlcpy (as well as strncpy) determies number of characters to be copied from src to dst. So, in case of 0-size no data should be copied. Read documentation carefully - prototype is:

strlcpy(char *dst, const char *src, size_t size);

and explanation for size has words:

as long as size is larger than 0

VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • Ok sorry for the question, the manual answers it. Thanks for your answer. But, even if my first question was stupid, could you explain me where the "garbage character" comes from? What does the function do to find this character and to put it in the string? Even if it is not supposed to be called with a 0 len value. – CodeKiwi Jul 10 '18 at 10:21
  • Oh and sorry for the manual misunderstanding. I'm french and sometimes I think I don't understand everything from 'IT English'. – CodeKiwi Jul 10 '18 at 11:41
0

There are several issues in your program.

First of all don't use gets(). It's not safe and moreover it has been obsoleted. Check this.
Instead use fgets(). Check this.

In this statement

printf("\nGive me a string (0 to stop): ");

0 to stop will actually not stop anything and execute all the statements below it until while loop checks the condition. May you want a put if condition, like this:

   if (str[0] != '0') {
       .....
       .....
   }
}while (str[0] != '0');

In this statement

    printf("Now, give me a number please: ");
    scanf("%d", &i);
    ....
    ....
    j = ft_strlcpy(str3, str, i);

You are passing this number as the destination size to your ft_strlcpy() function. Assume your source string contains "123456789" string and destination string size is 5 and user has given number input as 100. In function ft_strlcpy(), for the given input

    //cpt variable value would be 9
    //size variable value would be 100
    //initial value of i is 0
    while (i < 9 && i < (100 - 1))
    {
        dest[i] = src[i]; //buffer overflow!!!!, this statement will execute 9 times and dest buffer size is 5 
        i++;
    }

So, instead of taking the number of characters to be copy as input from user, you should give size of the destination buffer. Like this

j = ft_strlcpy(str3, str, sizeof(str3));

From strlcpy

strlcpy() copies up to dstsize - 1 characters from the string src to dst, NUL-terminating the result if dstsize is not 0.

That means if destination buffer size is 0, no copy is performed.

Check this also.

Putting these all together, you can do:

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

unsigned int  ft_strlcpy(char *dest, const char *src, unsigned int size) {
    unsigned int i = 0, j = 0;

    while (src[i] != '\0') {
        if (size && (i < (size - 1))) {
            dest[i] = src[i];
            j++;
        }
        i++;
    }
    dest[j] = '\0';
    return (i);
}

int main() {
    char str[100], str3[100];
    unsigned int j;

    do {
        /* Ask for first string */
        printf("\nEnter a string (press only enter key to stop): ");
        if (fgets(str, sizeof(str), stdin) == NULL) {
            fprintf (stderr, "Failed to read input");
            break;
        }

        /* If input is bigger than the size of buffer, discard the rest of input characters */
        if (strchr(str, '\n') == NULL) {
            int c;
            while((c = getchar()) != '\n' && c != EOF)
                /* discard the character */;
        }
        else {
            /* Remove the trailing newline character */
            str[strcspn(str, "\n")] = 0;
        }

        if (str[0] != '\0') {
            j = ft_strlcpy(str3, str, sizeof(str3));
            printf("Here is my result: %s\n", str3);
            printf("Num returned: %d\n", j);
        }
    }while (str[0] != '\0');

    return 0;
}
H.S.
  • 11,654
  • 2
  • 15
  • 32
  • Tkank you very much for all those advices. I have to be more conscientious in order to learn good habits. I just have one question about your comment on the `gets` use. I know that `fgets` is safer and I think I understand why. But I faced a problem using it. I had to create my own `atoi` function, and when I worked using a string "catched" by `fgets`, the last character of my string was always '\n'. I was running late and I didn't have time to truly understand what was happening but it looked interesting to me to save a string without the '\n' char. Is it possible using `fgets`? – CodeKiwi Jul 11 '18 at 11:26
  • Yes, thats how the `fgets` works. In my answer I have shared a link [fgets](https://en.cppreference.com/w/c/io/fgets). If you have gone through it, it mentions - _in which case str will contain that newline character_. Also, the code that I have posted in my answer, there is a comment in `main()` - `/* Remove the trailing newline character */`. When you read input using `fgets()` and it finds `\n` character, it includes the `\n` character as part of input string and you need to remove the `\n` character from input string. There are many ways to do it. One of them I have shown in my code. – H.S. Jul 11 '18 at 11:47
  • @Mad To answer your question - _it looked interesting to me to save a string without the '\n' char. Is it possible using fgets?_ No, its not possible. You have to explicitly remove the trailing `\n` character from the string read using `fgets()`. – H.S. Jul 11 '18 at 12:11
  • Ok perfect. I saw on your code that your removed it, but I just didn't know if there was a way of saving the string without that last char. But, actually, it's not really important because we can just remove it. Thanks a lot, that was a really interesting coding lesson :) . And sorry if I did not check the manual enough. – CodeKiwi Jul 11 '18 at 15:19