我正在编写strlcat的重新实现作为练习。我进行了几次测试,它们产生了类似的结果。但是,在一种特殊情况下,我的函数给出了分割错误错误,而原始函数没有,您能向我解释一下原因吗?我不允许使用任何标准库函数,这就是我重新实现 strlen() 的原因。
这是我编写的代码:
#include <stdio.h>
#include <string.h>
int ft_strlen(char *s)
{
int i;
i = 0;
while (s[i] != ' ')
i++;
return (i);
}
unsigned int ft_strlcat(char *dest, char *src, unsigned int size)
{
size_t i;
int d_len;
int s_len;
i = 0;
d_len = ft_strlen(dest);
s_len = ft_strlen(src);
if (!src || !*src)
return (d_len);
while ((src[i] && (i < (size - d_len - 1))))
{
dest[i + d_len] = src[i];
i++;
}
dest[i + d_len] = ' ';
return (d_len + s_len);
}
int main(void)
{
char s1[5] = "Hello";
char s2[] = " World!";
printf("ft_strcat :: %s :: %u :: sizeof %lun", s1, ft_strlcat(s1, s2, sizeof(s1)), sizeof(s1));
// printf("strlcat :: %s :: %lu :: sizeof %lun", s1, strlcat(s1, s2, sizeof(s1)), sizeof(s1));
}
使用 strlcat 的输出是 :strlcat :: Hello World! :: 12 :: sizeof 5
。我在macOS上,如果这能有所帮助,我正在使用clang进行编译。
ft_strlcat()
还不错,但它需要指向字符串的指针。main()
很麻烦:s1
缺少空字符:所以s1
不是字符串。
//char s1[5] = "Hello";
char s1[] = "Hello"; // Use a string
对于串联的字符串"HelloWorld"
来说,s1[]
太小
char s1[11 /* or more */] = "Hello"; // Use a string
"%lu"
匹配unsigned long
.size_t
从sizeof
比赛"%zu"
.
一些ft_strlcat()
问题:
unsigned, int
与size_t
对于长字符串来说unsigned, int
太窄了。 使用size_t
处理所有字符串。
测试太晚
if (!src || ...)
为时已晚,因为之前的ft_strlen(src);
在src == NULL
时调用 UB。
const
ft_strlcat()
应使用指向const
的指针,以允许将const
字符串与src
一起使用。
高级:restrict
使用restrict
,以便编译器可以假定dest, src
不会重叠并发出更有效的代码 - 假设它们不应该重叠。
极端情况
它不处理一些讨厌的角落情况,例如d_len >= size
,但我会将详细分析留待以后使用。
建议签名
// unsigned int ft_strlcat(char *dest, char *src, unsigned int size)
size_t ft_strlcat(char * restrict dest, const char * restrict src, size_t size)
一些未经测试的代码供您考虑:
试图模仿
strlcat()
。
返回字符串长度的总和,但不返回大于
size
。不检查超过
size
个字符以防止读取越界。当空间不足时不附加空字符。
不检查
dst, src
为NULL
。 如果您愿意,请添加。不处理重叠
dest
、src
。 除非库例程可用,否则这样做很棘手。使用指针
unsigned char *
正确处理罕见的有符号非 2 的补码char
。
size_t my_strlcat(char * restrict dst, const char * restrict src, size_t size) {
const size_t size_org = size;
// Walk dst
unsigned char *d = (unsigned char*) dst;
while (size > 0 && *d) {
d++;
size--;
}
if (size == 0) {
return size_org;
}
// Copy src to dst
const unsigned char *s = (const unsigned char*) src;
while (size > 0 && *s) {
*d++ = *s++;
size--;
}
if (size == 0) {
return size_org;
}
*d = ' ';
return (size_t) (d - (unsigned char*) dst);
}
如果返回值小于size
,则成功!
-
s1
甚至不足以容纳"Hello"> -
使用正确的尺寸类型。
size_t ft_strlcat(char *dest, const char *src, size_t len)
{
char *savedDest = dest;
if(dest && src && len)
{
while(*dest && len)
{
len--;
dest++;
}
if(len)
{
while((*dest = *src) && len)
{
len--;
dest++;
*src++;
}
}
if(!len) dest[-1] = 0;
}
return dest ? dest - savedDest : 0;
}
- 此外,您的
printf
调用未定义的行为,因为函数参数评估的顺序尚未确定。它应该是:
int main(void)
{
char s1[5] = "Hello"; //will only work for len <= sizeof(s1) as s1 is not null character terminated
char s2[] = " World!";
size_t result = ft_strlcat(s1, s2, sizeof(s1));
printf("ft_strcat :: %s :: %zu :: sizeof %zun", s1, result, sizeof(s1));
}
https://godbolt.org/z/8hhbKjsbx