这种基于指针的strcat在C中如何工作?

我对C有一些基本的经验,但是通常我需要一些时间来弄清楚如何实现某些东西。使用指针,这样对我来说还是个谜。

然后我看到一个类似strcat implementation的示例,因此我无法继续。有人介意向C新手解释吗?

char *
my_strcat(char *dest,const char *src)
{
    char *rdest = dest;

    while (*dest)
      dest++;
    while (*dest++ = *src++)
      ;
    return rdest;
}

当我读到那本书时,我认为“最= =,也许是真正的目的地”。因此,设置指向原始目的地的指针。然后“ while(* dest)dest ++;”,这是做什么的?与下一行相同。我不跟随。

是否在原始两部分(src和dest)中使用了额外的内存?像在JS中一样,如果连接2个字符串,它会为合并了这两个字符串的第三个字符串创建内存,因此您的内存增加了一倍。在这种C实现中(如果有)如何避免这种情况?

iCMS 回答:这种基于指针的strcat在C中如何工作?

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不是像高级语言那样的现成方法。用例如下:

  1. char* buffer = malloc(strlen(string1) + strlen(string2) +1)创建一个足以容纳两个字符串的缓冲区。
  2. strpy(buffer,string1)将第一个字符串复制到缓冲区
  3. strcat(buffer,string2)将第二个字符串追加到第一个字符串结束的缓冲区。

++--运算符允许指针用作枚举器。可以将它们视为.next().prev()。需要注意的是,它们在移动枚举器之前会返回(或接受)该值。在这里这很关键,基本上这就是使C如此困难的原因;)如果要在更高级别上重新创建,它将为getAndNext()setAndNext()

*是访问器,可双向工作,因此它是枚举数的getValue()setValue()

第一个块只是跳过dest缓冲区,直到到达其中的字符串末尾-而不是缓冲区的末尾。

while (*dest)
    dest.next();
伪代码中的

是:

while (dest.get() != '\0')
    dest.next();

这是因为\0int的意义上是一个实零,而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++)最终返回了已复制的字符。就像内联函数一样,它先复制,前进然后返回所复制的内容。

指针可以合法地指向数组之外。就像枚举器已经到了尽头,仅此而已。最大的区别在于,高级枚举器可以(通过异常)告诉您,而指针将继续运行,即使它不再有意义。这就是srcdest指针一次被++++的原因,但是我们不在乎,因为在那之后我们从不使用它们。

rdest只是缓冲区开始位置的保存位置。我们无法返回dest,因为该枚举数已用完,现在它在字符串的结尾,而我们需要返回开头。 “ r”可能代表“返回”,因为该变量的全部要返回。

本文链接:https://www.f2er.com/2228564.html

大家都在问