c语言 - 为什么我的 strlcat 实现会出现分段错误,而原始的则没有?



我正在编写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_tsizeof比赛"%zu".


一些ft_strlcat()问题:

unsigned, intsize_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, srcNULL。 如果您愿意,请添加。

  • 不处理重叠destsrc。 除非库例程可用,否则这样做很棘手。

  • 使用指针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,则成功!

  1. s1甚至不足以容纳"Hello">

  2. 使用正确的尺寸类型。

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;
}   
  1. 此外,您的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

相关内容

  • 没有找到相关文章

最新更新