的C指针算术 [英] C pointer arithmetics

查看:106
本文介绍了的C指针算术的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是code,我不明白,它只是反转的字符串。

 的#include<&stdio.h中GT;无效strrev(字符* P)
{
  字符* Q = P;
  而(Q&安培;&放大器; * Q)+ q;
  为( - q; P&下,Q ++ P,--q)
    * p = * P ^ * Q,
    * Q = * P ^ * Q,
    * p = * P ^ * Q;
}INT主(INT ARGC,字符** argv的)
{
  做{
    的printf(%S的argv [ARGC-1]); strrev(ARGV [ARGC-1]);
    的printf(%S \\ N的argv [ARGC-1]);
  }而( - ARGC);  返回0;
}

code,我不明白的唯一的一块是这个:而(Q&安培;&放大器; * Q)+ q; ,它是用来找到 EOS
是不是一样的而(* Q)+ q; ,因为被永远不会是0?在code的作者如何才能确保 * Q 将是0 <? / p>

这code来自这个问题:<一href=\"http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c?lq=1\">How你扭转一个字符串代替C或C ++?


解决方案

大卫·赫弗南的评论是正确的。这code是的惨不忍睹的。

在code则是问有关的一点是要跳过反引用如果是空。因此,code的作者认为,可能为空。在什么情况下可以为空?最明显的是:如果 P 为空

让我们看到了code做什么时, P 为null。

 无效strrev(字符* P)//假设:P为null
{
  字符* Q = P; //现在q是空
  而(Q&安培;&放大器; * Q)+ q; //循环被跳过,所以q和p都还空。
  为( - q;

所以,我们要做的第一件事是递减Q,这是空。这很可能将环绕,我们会尽快为的结果Q包含的最大可能的指针

  P&LT; q;

由于空比,除了空一切变小,和q不再为空,这是事实。我们进入环...

  ++ P,--q)
    * p = * P ^ * Q,

和及时提领空。

  * Q = * P ^ * Q,
    * p = * P ^ * Q;
}

顺便说一句,在我们Coverity公司将其称为向前空瑕疵 - 也就是模式在一个code路径指示值,预计将可能为null,再后来就在同一code路线假定它是不为空。这是非常普遍的。

OK,所以这code完全如果给null作为一个参数打破。是否有其他的方式,它坏了?如果我们给它一个空字符串会发生什么?

 无效strrev(字符* P)//假设:* p是0
{
  字符* Q = P; // * q是0
  而(Q&安培;&放大器; * Q)+ q; //第二个条件不满足所以身体被跳过。
  为( - q; // q现在指向*前有效的内存*。
       P&LT; q //我们无效指针比较有效的。

我们有一个在C保证说,当你减去一个从指针到有效的内存中,然后该指针比较另一个指针,这比较是明智?因为这给我的印象极其危险的。我不知道C标准不够好,说这是不确定的行为与否。

此外,该code使用可怕的交换两个字符与异的把戏。 究竟为什么会有人这样做?它会产生更大,更慢的机器code和是难以阅读,理解和维护。如果你想换两件事情,交换它们

它还使用逗号操作符把多个语句在单个语句,从而避免牙套周围的的身体恐怖。这是什么古怪的目的是什么? code的目的不是为了显示你知道有多少运营商来说,首先是要的传达给code读者的。

该功能还修改其形式参数,这使得它很难调试。

This is the code that I don't understand, it simply reverse a string.

#include <stdio.h>

void strrev(char *p)
{
  char *q = p;
  while(q && *q) ++q;
  for(--q; p < q; ++p, --q)
    *p = *p ^ *q,
    *q = *p ^ *q,
    *p = *p ^ *q;
}

int main(int argc, char **argv)
{
  do {
    printf("%s ",  argv[argc-1]); strrev(argv[argc-1]);
    printf("%s\n", argv[argc-1]);
  } while(--argc);

  return 0;
}

The only piece of code that I don't understand is this one: while(q && *q) ++q;, it is used to find the eos. Isn't it the same as while(*q) ++q;, since q is never going to be 0? How can the author of the code be sure that q or *q are going to be 0?

This code comes from this question: How do you reverse a string in place in C or C++?

解决方案

David Heffernan's comment is correct. That code is appalling.

The point of the code you are asking about is to skip dereferencing q if it is null. Therefore the author of the code believes that q could be null. Under what circumstances can q be null? The most obvious is: if p is null.

So let's see what the code does when p is null.

void strrev(char *p) // Assumption: p is null
{
  char *q = p; // now q is null
  while(q && *q) ++q; // The loop is skipped, so q and p are both still null.
  for(--q; 

So the first thing we do is decrement q, which is null. Likely this will wrap around and we will get as a result q containing the largest possible pointer.

    p < q; 

Since null is smaller than everything except null, and q is no longer null, this is true. We enter the loop...

    ++p, --q)
    *p = *p ^ *q,

And promptly dereference null.

    *q = *p ^ *q,
    *p = *p ^ *q;
}

Incidentally, at Coverity we refer to this as a "forward null defect" -- that is, the pattern where a code path indicates that a value is expected to be potentially null, and then later on the same code path assumes that it is not null. It is extremely common.

OK, so this code is completely broken if given null as an argument. Are there other ways that it is broken? What happens if we give it an empty string?

void strrev(char *p) // Assumption: *p is 0
{
  char *q = p; // *q is 0
  while(q && *q) ++q; // The second condition is not met so the body is skipped.
  for(--q; // q now points *before valid memory*.
       p < q  // And we compare an invalid pointer to a valid one.

Do we have a guarantee in C that says that when you subtract one from a pointer to valid memory, and then compare that pointer to another pointer, that the comparison is sensible? Because this strikes me as incredibly dangerous. I do not know the C standard well enough to say whether this is undefined behaviour or not.

Moreover, this code uses the terrible "swap two chars with xor" trick. Why on earth would anyone do this? It generates larger, slower machine code and is harder to read, understand and maintain. If you want to swap two things, swap them.

It also uses the comma operator to put multiple statements in a single statement so as to avoid the horror of braces around the body of the for. What is the purpose of this oddity? The purpose of code isn't to show how many operators you know, it is first and foremost to communicate to the reader of the code.

The function also modifies its formal parameter, which makes it hard to debug.

这篇关于的C指针算术的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆