char * my_strcat(char *dest,const char *src)
{
// Standard dictates strcat() to return dest.
// That is pretty useless (returning a pointer to the
// *end* of dest would have been better),but that's
// the way it is.
// Since we iterate dest as part of the implementation,// we need to "remember" its original value.
char *rdest = dest;
// Iterate over the characters pointed to by dest until
// we found the end (null byte terminator),which is "false"
while (*dest)
dest++;
// An assignment evaluates to the value assigned. So assigning
// one character at a time (*dest = *src) will eventually
// evaluate to false when we assigned the null byte terminator
// from src (incidentially also terminating dest). Since we
// postfix-increment both pointers during the assignment,we
// don't need any actual body for the loop.
while (*dest++ = *src++)
;
// Return the "remembered" original dest value.
return rdest;
}
是否在原始两部分(src和dest)中使用了额外的内存?像在JS中一样,如果连接2个字符串,它会为合并了这两个字符串的第三个字符串创建内存,因此您的内存增加了一倍。在这种C实现中(如果有)如何避免这种情况?
strcat
的前提是dest
必须有足够的空间来容纳最终结果。因此,不,它不需要/分配额外的内存。您要确保有 个足够的内存,或者在呼叫realloc
之前,有strcat
个内存。
,
const char *src
src
不应被该函数修改,因此请使用常量正确性将其标记为只读。
char *rdest = dest;
保存原始位置直到以后,因为要求strcat
返回指向合并字符串(return rdest;
)第一个元素的指针。
while (*dest)
dest++;
while循环隐式地寻找空终止符。含义:找到第一个字符串的结尾,以便在此循环之后,dest
指向该字符串的空终止符。
while (*dest++ = *src++)
这是一个常见的用法,尽管在C中确实使人感到困惑。(它实际上在这一行中实现了strcpy
。)运算符优先级表示后缀++
的优先级高于前缀*
的优先级高于分配{ {1}}。
因此,首先评估每个指针,然后将++应用于指针,而不是指向的数据。但是由于它是后缀,所以指针地址的实际增量要到表达式末尾才发生。
=
在此增量之前获取每个指针的内容,然后*
将内容从=
复制到*src
。同样,这是在地址递增之前发生的。
最后,对空终止进行隐式检查,因为实际上可以检查*dest
操作数的结果-它等于其左操作数,在这种情况下为=
。并且请注意,空终止符也会被复制。
您可以用一种不太混乱的方式重写while循环:
*dest
,
在此代码中要理解的关键是C处理字符串的方式(以'\0'
终止的字符数组)。首先要做的是抛弃类比字符串作为单词,并逐个值地考虑它。
函数的dest
自变量表示指向目标字符串的第一个字符的指针。要在dest
字符串后添加更多字符,我们需要到达其'\0'
终止符,因为这是第二个字符串所在的位置。这就是该循环的目的:
while (*dest)
dest++;
((*dest)
的条件等效于(*dest != '\0')
,因为'\0'
的数值为0
,其等效于false
)
到达第二个字符串需要开始的位置之后,我们开始逐个字符地复制它:
while (*dest++ = *src++)
;
请注意,(*dest++ = *src++)
有一个'='字符,表示它是一个分配,而不是一个比较。括号内要测试的值是要分配的东西,即*src
。因此,它将持续到(*src != '\0')
,恰好是第二个字符串的结尾。还要注意,'\0'
字符在这些分配中也已复制,这是绝对必须的,因为没有它,结果字符串就不会终止(因此,从技术上讲,它甚至都不是有效的字符串)。
太好了,既然我们已经将字符串复制到需要的位置,我们需要将指针返回到第一个字符。啊,但是我们已经在第一个循环中移动了指针!这就是rdest
进入的地方,在循环之前保存了初始位置,以便我们可以在结束时返回它。希望这会有所帮助。
,
让我们从函数声明开始:
char * my_strcat(char *dest,const char *src)
此函数将返回一个指向char的指针,其参数也是指向char的指针,它们将指向作为参数传递的每个char数组的开头。由于src
不会被更改,因此可以将其作为const
传递。
此作业:
char *rdest = dest;
声明一个指针,使其指向通过dest
指针传递的数组的开头。
周期:
while (*dest)
dest++;
您可能知道C中的任何字符串都以'\0'
终止,因此该终止符的ASCII值为0,因此可以将其用作停止条件。
因此本质上,指向dest
开头的指针一直递增,直到找到字符串的结尾。
周期:
while (*dest++ = *src++)
;
现在dest
指针指向dest
字符串的末尾,它只是增加两个指针,并从{中的第一个字符开始,附加src
字符串中的每个字符。 {1}}和src
字符串的结尾。当添加dest
时,这将再次成为停止条件,该表达式的值将为0,false,并且该字符串将具有空终止符。
返回:
\0
此指针在该函数中保持不变,并指向return rdest;
字符串的开头,该字符串现在还附加了dest
。那就是我们要返回的东西。
,
如果您进行一些更改,最重要的角色将更加清晰
char * my_strcat(char *dest,const char *src)
{
char *workdest = dest;
while (*workdest) workdest++;
while (*workdest++ = *src++);
return dest;
}
现在,我们使用工作指针来迭代并返回原始目标
是否在原始两部分(src和
目标)?就像在JS中一样,如果连接2个字符串,它会为
第三个字符串将两者结合在一起,因此您的内存增加了一倍。
在这种C实现中(如果有)如何避免这种情况?
此版本(以及标准库strcat
)不分配任何内存,调用者必须确保dest
可写且大小足以容纳连接的字符串>
您需要编写另一个版本的函数:
char * my_strcat_s(char *dest,const char *src)
{
size_t destlen = strlen(dest);
char *workdest = malloc(destlen + strlen(src) + 1);
if(workdest)
{
strcpy(workdest,dest);
strcpy(workdest + destlen,src);
}
return workdest;
}
但是释放分配的内存是程序员的责任
,
string
只是char
s的数组(缓冲区)。基本上是8位unsigned int
数组。数组中的最后一个元素是'\0'
。实际的数组可能比占用它的字符串大得多,并且strcat实际上要求dest
足够大,才能同时包含dest
字符串和source
字符串。 strcat
不是像高级语言那样的现成方法。用例如下:
-
char* buffer = malloc(strlen(string1) + strlen(string2) +1)
创建一个足以容纳两个字符串的缓冲区。
-
strpy(buffer,string1)
将第一个字符串复制到缓冲区
-
strcat(buffer,string2)
将第二个字符串追加到第一个字符串结束的缓冲区。
++
和--
运算符允许指针用作枚举器。可以将它们视为.next()
和.prev()
。需要注意的是,它们在移动枚举器之前会返回(或接受)该值。在这里这很关键,基本上这就是使C如此困难的原因;)如果要在更高级别上重新创建,它将为getAndNext()
和setAndNext()
*
是访问器,可双向工作,因此它是枚举数的getValue()
和setValue()
。
第一个块只是跳过dest
缓冲区,直到到达其中的字符串末尾-而不是缓冲区的末尾。
while (*dest)
dest.next();
伪代码中的
是:
while (dest.get() != '\0')
dest.next();
这是因为\0
在int
的意义上是一个实零,而int零在布尔意义上是false
。非零是true
。这意味着-1、42和'A'
与true
一样为1。因此,在C语言中,我们跳过了!= 0
,这与用一种语言编写!= false
一样毫无意义。有真正的布尔值。
while (*dest++ = *src++)
;
可以重述为:
while (dest.setAndNext(src.getAndNext()) != '\0')
或不进行复利:
char value;
do
{
dest.set(src.get());
value = src.get();
src.next();
dst.next();
}
while (value != '\0');
那是因为在C中,赋值具有一个值。因此(*dest++ = *src++)
最终返回了已复制的字符。就像内联函数一样,它先复制,前进然后返回所复制的内容。
指针可以合法地指向数组之外。就像枚举器已经到了尽头,仅此而已。最大的区别在于,高级枚举器可以(通过异常)告诉您,而指针将继续运行,即使它不再有意义。这就是src
和dest
指针一次被++++的原因,但是我们不在乎,因为在那之后我们从不使用它们。
rdest
只是缓冲区开始位置的保存位置。我们无法返回dest
,因为该枚举数已用完,现在它在字符串的结尾,而我们需要返回开头。 “ r”可能代表“返回”,因为该变量的全部要返回。
本文链接:https://www.f2er.com/2228564.html