编写代码以反转C风格的字符串

时间:2014-12-22 16:27:54

标签: c string

我知道此问题之前已被多次询问过,但我对下面的代码提出了一些问题。

所以下面的代码不起作用,因为在我的while循环中我有str != end而不是str < end。为什么必须str < end?我很困惑,因为似乎条件str != end应该以相同的方式工作,因为指针最终将指向相同的位置。

我的第二个问题是为什么我们必须while(*end){end++;}代替while(end){end++}。无论如何,当我们越过终点时,指针是否无效? while(end){end++}如果不正确,该怎么办?

我的最后一个问题是,在此代码的其他变体中,我已经看到在此函数顶部添加了一个条件if(!(*str)){return;}。这有必要吗?没有这个,我的代码似乎处理空字符串。此外,与*end vs end类似,为什么我们必须!(*str)代替!(str)

   void reverse(char *str){
       char *end = str;
       while(*end){
          end++;
       }
       end--;

       while(str != end){
          char tmp = *str;
          *str = *end;
          *end = tmp;
          str++; end--;
       }
    }

6 个答案:

答案 0 :(得分:2)

您同时递增str 递减endstr++; end--;)。因此,当你来比较它们时,它们可能会互相跳过,永远不会平等。

在当前的实现中,如果传递了一个空字符串(*str==0),那么无条件地递减endend--,第5行函数) 。所以现在看起来str 开始大于end这是坏消息如果str!=end是你的循环中的条件(我说&#34;看起来喜欢&#34;因为,作为pointed out by Cornstalks,它实际上是未定义的行为 - 在某些情况下,编译器可能会调整end以使得点太远 str)。无论如何,一旦你取消引用end,它就会出现更糟糕的消息,因为你很可能会搞乱未分配的内存。

至于你关于!(*str)的问题:if *str==0表示字符串为空,而str==0表示调用函数已经传递了一个NULL字符串指针。你应该检查两种可能性 - 具体来说,为了避免炸毁宇宙,首先检查指针是否为NULL,之前你试图取消引用它。

答案 1 :(得分:1)

  1. Why does it have to be str < end?
  2. 考虑具有偶数个字符的字符串会发生什么,例如“ABCDEF”。

    1. why we have to do while(*end){end++;} instead of while(end){end++}.
    2. 您正在寻找终止字符串的空字节,即当指针end指向空字节时。使用后一版本,只有当指针指向地址零时才使循环终止。

      1. I've seen a condition added to the top of this function that says if(!(*str)){return;}. Is this necessary?
      2. 是的!正确指出其他答案时,检查可以避免执行--end;

答案 2 :(得分:1)

您需要str < end,因为您str++; end--;。如果结束正好在str之上并且您str++; end--;,会发生什么?在那之后,str将正好在结束之后,它们会有所不同,但你不想继续你的循环。

结束总是一个指针。它可能指向一些有效的内存,或者它可能指向某个地方,如果您尝试访问该内存,它会给您一个段错误。增加指针只会使其指向更高的地址。它不会因为地址无效而变为NULL。这就是为什么你必须查看*end以找到空终止字符串的结尾。

使用当前代码,似乎没有必要检查if(!(*str)){return;},因为str和end变为相同的事实会捕获空字符串。但是,如果有人使用NULL指针调用您的函数,则添加if(!str){return;}以避免出现段错误可能是个好主意。

答案 3 :(得分:1)

  1. 只有当您的字符串具有奇数个字符时,条件str != end才能为您提供足够的结果。否则你很可能有以下顺序:

    str 0 1 2

    end 3 2 1

    此时,str != end仍然是正确的,尽管你的指针已经通过了字符串的中间。

  2. while(end)不检查指针是否有效,因为它指向您先前分配给该内存地址的值。它仅检查end是否与NULL不同。

  3. 这在技术上并不是必需的,但它确保在字符串为空时立即退出函数,而不进行任何额外的工作。

    修改:作为Cornstalks的pointed out 需要检查此内容。

答案 4 :(得分:1)

我想具体回答有关if(!(*str)){return;}是否必要的问题。

是的,您当前的代码是绝对必要的

没有它,end--将被执行。这意味着end将在有效范围[str, str + strlen(str) + 1]之外递减(您可以将指针递增到其内存块的末尾一个,但是您无法取消引用它)。

<强> Doing so is actually undefined behavior 即可。如果有效的内存范围是未定义的行为,则指向外部,即使您没有取消引用它。

例如,如果您的计算机使用segmented memory model,则您的比较(str < end)可能仍然为真,即使您有一个空字符串并且您递减了end(在这种情况下) ,end可以缠绕,str < end仍然是真的。)

例如,考虑一个aaaa:bbbb分段内存模型。 aaaa是细分,bbbb是细分中的偏移量。如果str是指向1234:0000的指针,并且您递减它,则它可能是新值1234:ffff。为什么段没有减少?因为编译器知道你不能跳段;指针只能指向当前段内的数据。因此,在进行指针运算时,它只会修改指针的偏移量(低两个字节)。现在,str < end仍然是真的,代码将继续并破坏。

答案 5 :(得分:0)

  

似乎条件str != end应该以相同的方式工作,因为指针最终将指向相同的位置。

这取决于字符串是偶数还是奇数字符。在前一种情况下,strend指针会相互移动过去,永远不会相等。

  

如果不正确,while(end){end++}正在做什么?

这是检查end是否为NULL,而您未将end设为NULL