C编程:len = 0的strlcpy

时间:2018-07-10 09:38:41

标签: c

我只是在学习使用C语言进行编程。 今天,我正在尝试编写自己的strlcpy函数,但遇到了问题。

为了测试我的功能,我将结果与“正式”功能的结果进行了比较。一切正常,除了...当我将0设为len arg时。 strcpy函数似乎在目标字符串中放入了垃圾字符,我真的不明白为什么。

这是函数的原型:         size_t strlcpy(char *限制dst,const char *限制src,size_t dstsize);

感谢您的帮助!

好的。我想进行很多测试,这就是为什么要在循环内调用该函数的原因。

这是我主要功能的一部分,测试该功能:

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');

这是我编写的函数:

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);
}

在函数中,我不应该从标准库中调用任何函数。我的主要对象是在这里进行测试。 函数原型是由我的老师给出的,这就是为什么我不尊重原始函数的原因。

抱歉,我需要在这里放置代码的时间,并感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

  

您能解释一下“垃圾字符”的来源吗?函数如何查找该字符并将其放入字符串?即使不应使用0 len值调用它。

手册没有说strlcpy 不应以0 len值调用,它只是说如果 NUL终止结果,则不会dstsize 0,即e。完全不复制任何字符到dst

您可能会在目标字符串中放入“垃圾字符”的印象很可能是由于dst从一开始就未初始化,而您看到的是未初始化的dst

答案 1 :(得分:1)

首先,我想您在“ ... strlen函数似乎会造成垃圾...”( strlcpy 而不是 strlen strlen不给字符串添加任何内容-size_t strlen( const char * s);)。

所以您对strlcpy有疑问。

正如references所说的,关于strlcpy(以及strncpy)的第三个参数确定要从 src 复制到 dst 的字符数。因此,如果大小为0,则不应复制任何数据。仔细阅读文档-原型为:

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

size 的解释为:

  

只要大小大于0

答案 2 :(得分:0)

程序中有几个问题。

首先不要使用gets()。这是不安全的,而且已经过时了。选中this
而是使用fgets()。选中this

在此声明中

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

0 to stop 实际上不会停止任何操作并执行其下的所有语句,直到while循环检查条件为止。可能需要放置if的情况,像这样:

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

在此声明中

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

您正在将此数字作为目标大小传递给ft_strlcpy()函数。假设您的源字符串包含"123456789"字符串,目标字符串大小为5,并且用户输入的数字为100。在函数ft_strlcpy()中,对于给定的输入

    //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++;
    }

因此,您应该提供目标缓冲区的大小,而不是将要复制的字符数作为用户的输入。像这样

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

来自strlcpy

  

strlcpy()最多将dstsize-1个字符从字符串src复制到dst,        如果dstsize不为0,则NUL终止结果。

这意味着如果目标缓冲区大小为0,则不会执行任何复制。

还要选中this

将所有内容放在一起,您可以执行以下操作:

#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;
}