strcat函数在C语言中的递归实现
我正在经历一场灾难!strcat函数在C语言中的应用。 我无法理解他们是如何使用递归和指针的 下面是该源代码的代码片段。strcat函数在C语言中的递归实现,c,string,pointers,recursion,C,String,Pointers,Recursion,我正在经历一场灾难!strcat函数在C语言中的应用。 我无法理解他们是如何使用递归和指针的 下面是该源代码的代码片段。 这是一个相当糟糕的实现,但我想它确实有效。第一个?:测试目标字符串是否在末尾。如果没有,它会碰撞目标指针,然后递归地调用自身。如果目标已经在末尾,那么它将复制一个字符,使指针和测试都为零。如果这不是src的尾随NUL,那么它会使用更新的指针递归地调用自己 哦,等等,有一个bug(或者可能是一个“特性”)。它假定dest结束后的所有字符最初都用NULs填充。我想您实际上可以利用
这是一个相当糟糕的实现,但我想它确实有效。第一个
?:
测试目标字符串是否在末尾。如果没有,它会碰撞目标指针,然后递归地调用自身。如果目标已经在末尾,那么它将复制一个字符,使指针和测试都为零。如果这不是src的尾随NUL
,那么它会使用更新的指针递归地调用自己
哦,等等,有一个bug(或者可能是一个“特性”)。它假定dest结束后的所有字符最初都用NUL
s填充。我想您实际上可以利用这一点,如果您可以依赖于实现继续具有此属性,并且有一个dest字符串,其中文本穿插着NUL
字符,它将填充src
中的NUL
,一次一个字符
更不用说过度使用递归了,这意味着堆栈上的调用帧数量与结果字符串中的字符数量相同。你从哪里得到这个愚蠢的strcat实现的?当然,没有真正的库会使用这种实现,迭代变体更容易理解,而且速度更快。这是一个非常糟糕的实现,但我想它确实可以工作。第一个
?:
测试目标字符串是否在末尾。如果没有,它会碰撞目标指针,然后递归地调用自身。如果目标已经在末尾,那么它将复制一个字符,使指针和测试都为零。如果这不是src的尾随NUL
,那么它会使用更新的指针递归地调用自己
哦,等等,有一个bug(或者可能是一个“特性”)。它假定dest结束后的所有字符最初都用NUL
s填充。我想您实际上可以利用这一点,如果您可以依赖于实现继续具有此属性,并且有一个dest字符串,其中文本穿插着NUL
字符,它将填充src
中的NUL
,一次一个字符
更不用说过度使用递归了,这意味着堆栈上的调用帧数量与结果字符串中的字符数量相同。你从哪里得到这个愚蠢的strcat实现的?当然,没有真正的库会使用此实现,迭代变体更容易理解,而且速度更快。将其分解为若干部分:
(*dest) /* Is *dest different than '\0' ? */
? my_strcat(++dest, src) /* *dest is different than '\0', so increment dest pointer so it'll point to the next character and call my_strcat() again. Here we're searching for the end of the string dest. */
: (*dest++ = *src++) /* *dest is equal to '\0', so we're at the end of *dest... We start to assign *src to *dest and increment both pointers to point to the next character. The lvalue of this assignment is also a comparison (is it different than '\0' ?). */
? my_strcat(dest, src) /* The previous comparison is different than '\0', so we'll call my_strcat() again (pointers have already been incremented and they now point to the next character) */
: 0; /* The previous comparison is '\0', so we've reached the end of the src, so we're done. */
用if/else替换三元运算符:
/* Is *dest different than '\0' ? */
if (*dest != '\0') {
/* *dest is different than '\0', so increment dest pointer so it'll point to the next character and call my_strcat() again. Here we're searching for the end of the string dest. */
my_strcat(++dest, src);
} else {
/* *dest is equal to '\0', so we're at the end of *dest... We start to assign *src to *dest and increment both pointers to point to the next character. The lvalue of this assignment is also a comparison (is it different than '\0' ?). */
if ((*dest = *src) != '\0') {
/* The previous comparison is different than '\0', so we'll call my_strcat() again (pointers have already been incremented and they now point to the next character) */
my_strcat(++ dest, ++ src); /* Moved increments down for readability */
} else {
/* The previous comparison is '\0', so we've reached the end of the src, so we're done. */
return;
}
}
If/else无注释(可能更具可读性):
把它打碎:
(*dest) /* Is *dest different than '\0' ? */
? my_strcat(++dest, src) /* *dest is different than '\0', so increment dest pointer so it'll point to the next character and call my_strcat() again. Here we're searching for the end of the string dest. */
: (*dest++ = *src++) /* *dest is equal to '\0', so we're at the end of *dest... We start to assign *src to *dest and increment both pointers to point to the next character. The lvalue of this assignment is also a comparison (is it different than '\0' ?). */
? my_strcat(dest, src) /* The previous comparison is different than '\0', so we'll call my_strcat() again (pointers have already been incremented and they now point to the next character) */
: 0; /* The previous comparison is '\0', so we've reached the end of the src, so we're done. */
用if/else替换三元运算符:
/* Is *dest different than '\0' ? */
if (*dest != '\0') {
/* *dest is different than '\0', so increment dest pointer so it'll point to the next character and call my_strcat() again. Here we're searching for the end of the string dest. */
my_strcat(++dest, src);
} else {
/* *dest is equal to '\0', so we're at the end of *dest... We start to assign *src to *dest and increment both pointers to point to the next character. The lvalue of this assignment is also a comparison (is it different than '\0' ?). */
if ((*dest = *src) != '\0') {
/* The previous comparison is different than '\0', so we'll call my_strcat() again (pointers have already been incremented and they now point to the next character) */
my_strcat(++ dest, ++ src); /* Moved increments down for readability */
} else {
/* The previous comparison is '\0', so we've reached the end of the src, so we're done. */
return;
}
}
If/else无注释(可能更具可读性):
你不明白的地方是什么?你考虑过发布一些关于好奇而不是实用性的帖子,因为他们想这样做是为了好玩看看你链接的页面标题,“为strcat()编写单行函数”。本页的重点是以一种不同寻常的方式为客户做事情fun@MAP虽然函数本身可能并不完美,但代码段作为一个整体是正确的。也就是说,
dest[100]
将用字符串后面的所有NUL填充。您不了解的是哪一位?考虑发布到哪个位置,它处理的是好奇而不是实用性,因为他们想这样做是为了好玩。请参阅您链接的页面标题,“为strcat()编写单行函数”。本页的重点是以一种不同寻常的方式为客户做事情fun@MAP虽然函数本身可能并不完美,但代码段作为一个整体是正确的。也就是说,dest[100]
将用字符串后面的所有NUL填充。我提到了源代码的链接。是的,这是一个反问句。我想你是对的,有一个错误,因为所有字符都不能为空,它们将为零。但是如果它们是零,那么也没关系,不是吗?字符不能是空的,只有指针可以。字符是NUL
,并且保证最后只有一个字符,数组的其余部分可以填充任何内容。顺便说一句,在几乎所有的实现中,NULL
和NUL
实际上都是零。@MAPNUL
被ASCII规范定义为0
。C规范只讨论值为零的字符,而不是NUL。我提到了源代码的链接。是的,这是一个反问句。我想你是对的,这是一个错误,因为所有字符都不能为零,它们将为零。但是如果它们是零,那么也没关系,不是吗?字符不能是空的,只有指针可以。字符是NUL
,并且保证最后只有一个字符,数组的其余部分可以填充任何内容。顺便说一句,在几乎所有的实现中,NULL
和NUL
实际上都是零。@MAPNUL
被ASCII规范定义为0
。C规范只讨论值为零的字符,而不是NUL。