我正在尝试从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吗?你们觉得怎么样?
答案 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 -> dst
和src
都包含字符串,您需要连接字符串(可能会在{}之间放置一个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
始终确保没有错误,并且已释放所有已分配的内存。
仔细看看,如果我明白你的问题所在,以及你是否还有其他问题,请告诉我。