【问题标题】:pointers strings指针字符串
【发布时间】:2012-07-31 12:18:14
【问题描述】:

复制到正确的位置,但在达​​到计数后不会停止。我认为我的代码应该如下工作

char har *orig, int start, int count, char *final);

int main(void)
{
    const char source[] = "one two three";
    char result[] = "123456789012345678";

    printf("%s\n",GetSubstring(source, 4, 3, result));

    return 0;
}

char r *orig, int start, int count, char *final)
{    
    char *temp = (char *)orig;

    final = temp;


   }

    for ( ; *temp && (count > 0) ; count--)
    {
    rn final;
}

【问题讨论】:

  • 我很难理解你在这里所做的事情;这是一件非常简单的事情,但你让它变得非常复杂。真正让我困惑的一件事是“final = temp”行。据推测,参数final 保存了复制字符串的目的地,但您已将其移动为指向原始字符串,因此复制任何字符都会导致原始字符串的某些部分被覆盖。我真的不知道你为什么要这样做,所以很难推荐任何具体的改变。
  • 相比之下,微软对strncpy() 的实现——一个标准库函数,基本上可以完成你在这里所做的工作——有四行,其中一个是return,其中一个是continue.
  • pointer substrings arrays 的可能重复项
  • 如果我不做 temp = final 字符串输出 char result [] 56789012345678,temp = final 我的输出是二三,虽然我虽然它应该只打印'二'然后应该达到计数
  • @Ernest:“我真的不知道你为什么这样做”我不想这么直率,但是,嘿,这就是错误所在。这就是这个问题的全部意义:修复它,找到错误。你不应该感到困惑,如果你在这里已经有一段时间了(而且你)。阅读没有经验的程序员的想法几乎是这里的工作定义。

标签: c string pointers


【解决方案1】:
  1. 第一个for 循环不检查temp 数组是否存在(它如何在不以某种方式询问内存管理器的情况下检查分配的内存是否存在?!)。 temp 只是一个指针。您正在检查的是 orig 字符串在第一个 start 字节内没有零。没关系,也许'这就是你所说的“存在”。

  2. 您的意图是从orig 复制到final,但您将final 重置为orig这就是您的错误所在。您必须删除该行才能解决问题。

  3. 您不需要创建temp 指针,您可以使用orig 指针。你可以随意修改它——记住,函数参数实际上是局部变量。 C 中的函数参数是按值传递的,您通过将指针(即值!)传递给数据来实现按引用传递。

我应该补充一点,这个函数的前提有些被打破了。它“有效”,但这不是人们合理预期的。值得注意的是:

  1. 没有迹象表明源字符串短于start

  2. 没有迹象表明源字符串短于start + count

    也许这些都可以,但在这些条件可能是错误的情况下,函数的用户应该可以得到它的指示。调用者会知道什么是预期的,什么不是,所以调用者可以确定它只要你向调用者提供一些反馈

  3. 您返回的位置是输出末尾之后的位置 - 超过了零终止符。那不是很方便。如果要使用返回值连接后续字符串,则必须先将其减一。

下面是固定代码,变量命名合理。

char *GetSub(const char *src, int start, int count, char *dst)
{
    for ( ; *src && (start > 0) ; start--)
    {
        src++; /* Note: *src++ works too, but is pointless */
    }

    for ( ; *src && (count > 0) ; count--)
    {
        *dst++ = *src++;
    }

    *dst++ = 0;
    return dst; /* Notice: This returns a pointer to the end of the
                memory block you just wrote. Is this intentional? */
}

【讨论】:

  • 虽然我同意将countstart 用于计数器“似乎”可以保存自动变量,但优化编译器会自行解决这个问题。 fors 缺少的初始化程序以及 start--count-- 的使用使这有点难以阅读。查看我在回答中写的版本,了解我的意思。
  • 顺便问一下,return dst 在增加了这么多次之后(它实际上可能已经增加超过目标数组的宽度)是怎么回事?我可以开个关于惯用 C 的笑话吗,你不应该试图回答吗? ;)
  • 我认为利用 C 的按值传递语义是实现短函数的明智方法。当函数变长时,在本地声明 C99 样式的循环变量肯定有助于使代码易于理解。在一个简短的功能 - 为什么要打扰。当然,我同意编写的这个函数的设计有点淫秽,但是如果那是当时所要求的,嘿,我可以接受;)我知道现代编译器可能不会关心额外的只是参数副本的局部变量。不过,可能没有初始化程序的 for 是不好的风格。
  • 无论如何,关键是要修复询问者的功能,以使其按预期工作。所要做的就是删除一个错误的行。这就是提问者的目的。
  • 也许您应该在最后一行添加注释,以明确您没有返回指向目标缓冲区开头的指针。这几乎可以肯定是一个错误,所以我认为将其称为“固定代码”是一种误导。
【解决方案2】:

您所写的内容存在几个问题。我们来列举一下:

  1. char *temp = (char *)orig; - 您将 const char *(您承诺不修改)分配给 char *(您违反了该承诺)。做错事了。

  2. final = temp。不,这根本不会使 original final(调用者持有的副本)发生变化。它一无所获。它会将final您的(函数)副本更改为指向temp 所指向的同一位置。

  3. *temp++; - 如果你不打算使用它,那么取消引用它是没有意义的。当然,增加它是正确的 [参见下面 KubaOber 的评论主题]。

  4. final++ = *temp++; - 这只是令人困惑。

  5. *final++ = 0; return final; - 您将地址 final 的值设置为“0”。然后你增加它(指向空间中的某个地方,可能指向一个黑洞)。然后返回该指针。这也是错误的。

真正应该做的是以方便的方式包装strncpy

但如果你坚持自己编写,你可能希望你的函数像这样简单:

char *GetSub(const char *orig, int start, int count, char *final)
{    
  int i;

  for (i = 0; i < count; i++)
    {
      final[i] = orig[i+start];

      if (final[i] == '\0')
        break;
    }
  final[i] = '\0';

  return final; /* Yes, we just return what we got.  */
}

【讨论】:

  • 您的#3 是错误的评估。您正在评论惯用的 C 代码,就好像它对您来说很陌生——也许您不应该这样? *temp++ 正在取消引用指针,并在取消引用之后的某个时间 递增它。就是这样。
  • 好的。它反其道而行之。这是一个错误,我会修复它。
  • @KubaOber - C 对我来说是陌生的判断可能有点苛刻。
  • 我只能通过评论来判断。您评论的那条线没有任何问题。这是一个明显的惯用 C 构造,在提问者的代码中正确使用。
  • @ArjunShankar,实际上,完全没有必要引用。
【解决方案3】:

问题出在以下行:

final = temp;

删除它,问题应该解决了。

【讨论】:

  • +1 用于 1 行修复。虽然,我希望 OP 考虑彻底重写甚至包装 strncpy
【解决方案4】:
char *a="abcdefgh";

我希望将字符串“cde”复制到另一个中。

我得到的索引是 3(你的起点)。

char *temp=malloc(3*sizeof(char))
strncpy(temp,a+3,3);

这是你需要的吗?

【讨论】:

  • 不,我必须使用我使用的函数制作自定义复制字符串。我只是想了解我的逻辑在哪里崩溃
【解决方案5】:

更改您的GetSub函数:

char *GetSub(const char *orig, int start, int count, char *final)
{
    char *temp = (char *)orig;

    // with original final = temp and final++ you loose final valid pointer
    char *final2 = final;


    for ( ; *temp && (start > 0) ; )
    {
        start--;

        // you don't need to dereference temp
        temp++;
    }

    for ( ; *temp && (count > 0) ; count--)
    {
        *final2++ = *temp++;
    }

    *final2 = 0;

    // return a valid pointer
    return final;
}

【讨论】:

  • 上帝帮助可怜的灵魂,他看到了一个带有局部变量的函数,称为 finalfinal2。这段代码的全部内容是有一个来源和一个目的地。所有这些origfinal 的命名都适得其反,而且风格不佳。
  • @KubaOber,关于错误的变量命名你是对的,但大多数变量名都是由提问者定义的。当然,我同意 'final2' 是变量的坏名称。但是,我认为这个答案是最直接的,因为它明确地解决了问题,而不会因代码的次要问题而分心。
【解决方案6】:

你的代码有一些错误:

char *GetSub(const char *orig, int start, int count, char *final)
{
    char *temp = (char *)orig;

    //final = temp; /* Why this? */

    for ( ; *temp && (start > 0) ; )
    {
        start--;
        temp++; /* Instead of *temp++ */
    }

    for ( ; *temp && (count > 0) ; count--)
    {
        *final++ = *temp++;
    }

    *(final+count) = '\0';
    return final;
}

希望对您有所帮助。

【讨论】:

  • 我认为这段代码是错误的。最后两行假设“final”指向原始目标缓冲区。
  • *(final+count) = '\0' 行不正确,因为它将超出目标缓冲区末尾的值(根据计数)设置为零。这可能会导致缓冲区溢出。
  • 您还返回了一个指向应该是空终止字符的指针。作者可能希望函数返回指向目标缓冲区的指针。
  • @Sam:你错了!此函数返回最终字符串,该字符串假定在此函数之外分配,并且具有精确的“count”个字符长度。否决票被滥用了!!
  • 实际上,我只是仔细检查了缓冲区溢出问题,看起来最后的空终止是正确的,尽管这似乎是一个意外。尽管如此,您的代码表明您认为“最终”是指最初提供的输出缓冲区的开始。返回的值也可能是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 2021-04-21
  • 2019-01-24
相关资源
最近更新 更多