我自己的子串函数 | valgrind 显示一些我不明白的 malloc 错误

My own substring function | valgrind showing some malloc errors I do not understand

任务:

Allocate (with malloc(3)) and return a substring from the string s. The substring begins at index start and is of maximum size len.

Return value: The substring. NULL if the allocation fails.

你好,几个小时后我决定要求澄清。我有以下功能和一些我无法理解的来自 Valgrind 的错误,即使一切正确也会出现。 (ft_strlen(s) 我从我自己的库中调用,其中还放置了 malloc 的库)。

char    *ft_substr(char const *s, unsigned int start, size_t len)
{
    unsigned int x;
    char        *a;
    unsigned int i;

    i = 0;
    if (s == NULL)
        return (0);
    if (start > ft_strlen(s))
    {   
        if (!(a = (char *)malloc(0*sizeof(char))))
            return (0);
        return (a);
    }
    if ((start + len) < ft_strlen(s))
        x = len;
    else
        x = ft_strlen(s) - start;
    if (!(a = (char *)malloc((x + 1) * sizeof(char))))
        return(0);
    while (i < x)
    {
        a[i] = s[start + i];
        i++;
    }
    a[i] = '[=10=]';
    return (a);
}

我故意留下一处错误。如果我假设如果分配失败 return null,为什么下面而不是 0 应该是 1?无论如何,它不会改变下面显示的错误。

if (!(a = (char *)malloc(0 * sizeof(char))))

错误:

==4817== Invalid read of size 1
==4817==    at 0x483FED4: strcmp (in /usr/lib/x86_64-linux-gnu/valgrind vgpreload_memcheck-amd64-linux.so)
==4817==    by 0x4039BC: main (ft_substr_test.cpp:28)
==4817==  Address 0x4dad0d0 is 0 bytes after a block of size 0 alloc'd
==4817==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4817==    by 0x403B58: ft_substr (in /home/tony/42cursus/0lvl_libft_1week/libftTester/a.out)
==4817==    by 0x4039A4: main (ft_substr_test.cpp:27)
==4817==

你的函数有多个问题:

  • startxi 的类型应该是 size_t
  • malloc(0) 具有实现定义的行为。您应该为空终止符分配至少 1 个字节,并在 return 将指针指向空字符串之前设置它,或者 return NULL 如果规范要求您应该这样做。
  • 函数应该只调用 ft_strlen() 一次。
  • start > ft_strlen(s) 的特殊情况可以在一般情况下处理,如果一个空字符串应该 returned。

这是修改后的版本:

char *ft_substr(char const *s, size_t start, size_t len) {
    size_t i, slen;
    char *a;

    if (s == NULL) {
        return NULL;
    }
    slen = ft_strlen(s);
    if (start > slen) {
        start = slen;
    }
    if (len > slen - start) {
        len = slen - start;
    }
    if (!(a = malloc((len + 1) * sizeof(char)))) {
        return NULL;
    }
    for (i = 0; i < len; i++) {
        a[i] = s[start + i];
    }
    a[i] = '[=10=]';
    return a;
}

PS:您可能需要重新格式化代码以适应本地 42 norminette...

在 Linux 系统上,调用 malloc(0) 不一定会 return NULL 指针。它可以 return 一个您不能写入但可以传递给 free 的指针。

因此,当您 return 来自函数的 malloc(0) 的结果时,调用函数会看到一个非空指针并尝试取消引用它。由于这个指针本质上指向一个大小为 0 的缓冲区,因此尝试读取它会读到缓冲区末尾,这就是 valgrind 所抱怨的。

您可以通过 returning NULL 解决此问题:

if (start > ft_strlen(s))
{   
    return NULL;
}

或者通过为空字符串分配 space 并设置空字节:

if (start > ft_strlen(s))
{   
    if (!(a = malloc(1)))
        return NULL;
    *a = 0;
    return a;
}

其他一些注意事项:

  • sizeof(char) 定义为 1,因此您可以将其排除在大小计算之外
  • 不要转换 malloc 的 return 值。
  • 对空指针使用 NULL 而不是 0
  • return 语句中的表达式不需要括号。