在C中重新创建strlcat函数“无效操作数到二进制表达式('size_t'(又名'unsigned long')和'char *')”

时间:2017-10-03 06:52:48

标签: c string function gnu memcpy

我正在尝试从C函数库重新创建strlcat函数。我在网上四处看看它是如何工作的。基本上,strlcat允许将源字符串附加到NUL终止的目标字符串中。返回值必须是追加后的大小值。

为了简短起见,我将strlen函数拉入strlcat,以便同时获得目的地和来源的大小。我遍历我的新目标,以使我的新字符串的长度适合我的源字符串。为此,我使用memcpy复制内存。

这就是我所拥有的(假设我们有必要的标题):

char my_strlcat(char *dst, const char *src, size_t n)

    {
        size_t dsize;
        size_t len;
        size_t res;

        dsize = my_strlen(dst) - dst;
        len = my_strlen(src) - src;
        res = dsize + len;
        if(dsize < n)
        {
            dst+= dsize;
            n-=dsize;
            if(n <= len)
                len = n - 1;
            dst[len] = '\0';
            my_memcpy(dst,src,len);
        }
        return (res);
    }

void *my_memcpy(void *dst, const void *src, size_t num)
    {
        size_t i;

        i = -1;
        while (i++ != num)
            ((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
        return (dst);
    }

size_t  my_strlen(const char *str)
{
    int len;

    len = 0;
    while (str[len] != '\0')
        len++;
    return (len);
}

    int main()
    {
        char my_strlcat_src[7] = "banana";
        char my_strlcat_dst[12] = "good";
        printf("my_strlcat => 'banana', 'good', 12 expected: 10  => %c\n", my_strlcat(my_strlcat_dst, my_strlcat_src, 12));
        char my_strlcat_src2[6] = "whatt";
        char my_strlcat_dst2[15] ="he said.";
        printf("my_strlcat => 'he said.', 'whatt', 15 expected: 13  => %c\n",my_strlcat(my_strlcat_dst2, my_strlcat_src2, 15));
    }

执行此程序后,我收到此错误说 “二进制表达式的无效操作数('size_t'(又名'unsigned long')和'char *')” 我真的不明白是什么造成了麻烦。是因为我在我的memcpy函数中做了unsigned char吗?你们觉得怎么样?

1 个答案:

答案 0 :(得分:0)

我为没有更充分地理解你的约束而道歉。检查后:

$ man strlcat
No manual entry for strlcat

我认为你正在制作一个新的strlcat并相应准备一个会自行分配等等。我现在找到了strlcat的手册页,现在可以提供更多的帮助可以写strlcat

strlcat将两个字符串连接起来dst缓冲区的最大大小作为第三个参数(大小意味着必须包含终止 nul-character 的空间,而不是两个字符串的长度strlcat最多会附加size - strlen(dst) - 1 bytes,NUL - 终止结果。 strlcat会返回其尝试创建的字符串的总长度

使用这些约束,您可以编写strlcat函数,如下所示(使用字符串索引而不是指针,因为这可能对您更熟悉)

size_t strlcat (char *dst, const char *src, size_t size)
{
    /* dst length and general variable i */
    size_t  dlen = strlen (dst), i;

    if (!src || !*src)      /* validate src not NULL or empty */
        return dlen;

    /* concatenate at most size - 1 bytes & nul-terminate */
    for (i = 0; i < size - dlen - 1 && src[i]; i++)
        dst[i + dlen] = src[i];
    dst[i + dlen] = 0;

    return i + dlen;    /* dest + bytes of src concatenated */
}

将它放在一个简短的例子中,您可以执行以下操作:

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

#define MAXS 32

size_t strlcat (char *dst, const char *src, size_t size)
{
    /* dst length and general variable i */
    size_t  dlen = strlen (dst), i;

    if (!src || !*src)      /* validate src not NULL or empty */
        return dlen;

    /* concatenate at most size - 1 bytes & nul-terminate */
    for (i = 0; i < size - dlen - 1 && src[i]; i++)
        dst[i + dlen] = src[i];
    dst[i + dlen] = 0;

    return i + dlen;    /* dest + bytes of src concatenated */
}

int main (int argc, char **argv) {

    size_t n = 0, sz1 = 0;   /* length variables, total and 1st string */
    char str[MAXS] = "",
        *s1 = argc > 1 ? argv[1] : "hello",    /* string 1 */
        *s2 = argc > 2 ? argv[2] : "world";    /* string 2 */

    printf ("\nconcatenating empty src with\ns1: %s\ns2: %s\n\n", s1, s2);

    sz1 = strlcat (str, s1, MAXS);     /* concatenate s1 -> str */
    printf ("after 'strlcat (str, s1, n)', str : %s  (%zu chars)\n", str, sz1);

    n = strlcat (str, s2, MAXS);       /* concatenate s2 -> str */
    printf ("after 'strlcat (str, s2, n)', str : %s  (%zu chars)\n", str, n);

    return 0;
}

示例使用/输出

$ ./bin/strlcat

concatenating empty src with
s1: hello
s2: world

after 'strlcat (str, s1, n)', str : hello  (5 chars)
after 'strlcat (str, s2, n)', str : helloworld  (10 chars)

$ ./bin/strlcat strlcat _works

concatenating empty src with
s1: strlcat
s2: _works

after 'strlcat (str, s1, n)', str : strlcat  (7 chars)
after 'strlcat (str, s2, n)', str : strlcat_works  (13 chars)

测试MAXS长度限制(尝试连接总共33个字符(超过允许的2个):

$ ./bin/strlcat 12345678901234567890 1234567890123

concatenating emptr sry with
s1: 12345678901234567890
s2: 1234567890123

after 'strlcat (str, s1, n)', str : 12345678901234567890  (20 chars)
after 'strlcat (str, s2, n)', str : 1234567890123456789012345678901  (31 chars)

自定义自我分配版本(在找到man strlcat之前)

在这个版本中也有学习,所以我会保留最初发布的内容。

在编写strcat函数时,很难说出所有约束条件,但使用memcpy。无论如何,以下代码提供了一个有效的strlcat,以便我最清楚地了解您要实现的目标。

正如您在代码中所暗示的那样,有两种情况需要涵盖(1),其中dst为空,您基本上只为dst分配并复制{ {1}}然后(2),其中src -> dstsrc都包含字符串,您需要连接字符串(可能会在{}之间放置一个dst话)。您可以在代码中自由使用自己的space函数,我只需使用下面的my_strlen,因为它似乎不是您问题根源的区域。

将各个部分放在一起,你可以做类似以下的事情:

strlen

注意:我将#include <stdio.h> #include <stdlib.h> #include <string.h> char *strlcat (char **dst, const char *src, size_t *n) { size_t dlen, slen; /* dst & src lengths */ void *tmp = NULL; /* realloc variable */ if (!src) /* validate src not NULL */ return *dst; if (!*dst) /* realloc dst (1) if empty; (2) extending current length */ tmp = realloc (*dst, (dlen = 0) + (slen = strlen (src)) + 2); else tmp = realloc (*dst, (dlen = strlen (*dst)) + (slen = strlen (src)) + 2); if (!tmp) /* validate realloc */ return *dst; *dst = tmp; /* assign reallocated block to dst */ if (!dlen) { /* if no *dst, just copy src to *dst */ strcpy (*dst, src); *n = slen; /* update total length */ } else { /* if *dst non-empty */ (*dst)[dlen] = ' '; /* add ' ' between *src/dst */ strcpy (*dst + dlen + 1, src); /* copy src to end (after ' ') */ *n = dlen + slen + 1; /* update total length */ } return *dst; /* return pointer to new string */ } int main (int argc, char **argv) { size_t n = 0; /* length variaale */ char *s1 = argc > 1 ? argv[1] : "hello", /* string 1 */ *s2 = argc > 2 ? argv[2] : "world", /* string 2 */ *str = NULL; /* string to hold concatenated result */ strlcat (&str, s1, &n); /* concatenate s1 -> str */ strlcat (&str, s2, &n); /* concatenate s2 -> str */ printf ("src: %s\ndst: %s\nstr: %s\n", s1, s2, str); printf ("len: %zu chars.\n", n); free (str); /* don't forget to free allocated memory */ return 0; } 的地址传递给dst,这样就可以在函数中设置strlcat的新地址。目前有你的代码,你必须将函数返回类型更改为dst并将返回值分配给char *中的字符指针变量,否则将main()更改为dst永远不会反映在strlcat

示例使用/输出

main()

始终运行通过内存错误检查程序动态分配内存的任何程序。对于Linux,$ ./bin/strlcat src: hello dst: world str: hello world len: 11 chars. $ ./bin/strlcat C-Programming can-do src: C-Programming dst: can-do str: C-Programming can-do len: 20 chars. 是正常选择,但所有平台都有类似的工具,

内存使用/错误检查

valgrind

始终确保没有错误,并且已释放所有已分配的内存。

仔细看看,如果我明白你的问题所在,以及你是否还有其他问题,请告诉我。