谁能解释一下这个功能是如何工作的

时间:2014-02-17 04:06:18

标签: c++ string function duplicates

我想知道是否有人可以通过跟踪代码的跟踪来帮助我理解这段代码,因为我对int pos变量实际执行或用于if语句时所使用的内容感到困惑。我的困惑主要与if语句有关。对于这段代码,我将给函数字符串“hello”,在运行data2之后,应该保存带有一个“l”的字符串“helo”,因为它删除了重复项。

我只是希望有人可以引导我深入了解代码,这样我就能更好地理解它,因为我的c ++书并不能很好地解释“.find()”函数。我希望这很容易解释,因为我真的想学习这个!!

三江源!

字符串数据(“hello”);

string duplicates(string &data)
{
   string data2;
   int pos;
   for(int i=0;i<data.length();i++)
   {
      if((pos=data2.find(data[i]))<0){
         data2 += data[i];
      }
   }
   return data2;
}

4 个答案:

答案 0 :(得分:1)

它返回空字符串,或者通过castimg调用未定义的行为,该符号超出int范围。虽然signedunsigned转换是安全且定义良好的,但是圆形跳闸只对两者都可以表示的值安全。一些编译器会利用它来消除只能通过UB访问的分支。

在C ++的特定实现上,它可能会特别做点什么。

编写这段代码的程序员搞砸了,每次测试时都可能有效。如果他们将pos作为变量删除,则删除if子句中的分配(keepimg右侧),并将-1替换为std::string::npos代码变得更容易理解可能是编码员想要的。

我认为有问题的字符串是std::string

duplicates通过引用获取std::string data(因此可以对其进行修改)并返回另一个std::string

std::string duplicates(std::string &data)
{

它有两个局部变量data2posdata2std::stringposint(&#34;默认&#34;编译器的有符号整数,通常是2s补码,至少16位,通常是32位):

  std::string data2;
  int pos;

我们将局部变量i0循环到小于data.length()的1。因此,i会将有效索引变为data。请注意,如果data的长度超过int可以存储的最大值,则会调用未定义的行为(但这不太可能,除非int非常小,或者字符串非常长(数十亿个字符):

  for(int i=0;i<data.length();i++)
  {

我们一次做两件事。这通常被认为是不良编码实践。我们将data2.find(data[i])的返回值分配给pos(将std::size_t隐式转换为int),然后检查它是否小于0并且基于分支在那。

这里有一些问题。将std::size_t转换为int将调用未定义的标准行为。许多编译器会进行2s补码截断转换,但这不能保证,而其他编译器将使用std::size_t转换为小于零的int的唯一方法是未定义的行为,并且完全优化分支(gcc,例如,使用某些标志):

    if((pos=data2.find(data[i]))<0) {

另一个问题是不必要地同时做两件事。把它放在两行上没有任何伤害。

当且仅当data[i]中找不到data2时,程序员才会运行此行代码。如果是,则将该字符附加到data2。如上所述,程序员失败了,除非他们得到幸运和#34;未定义的行为:(他们的测试都得到了#34;幸运&#34;我确定):

      data2 += data[i];
    }
  }

然后我们返回程序员想要成为包含data中每个唯一字符的字符串的内容:

  return data2;
}

我会将代码重写为非可怕的。首先,C ++ 03风格:

std::string duplicates(std::string const&data) {
  std::string data2;
  for(int i=0;i<data.length();++i) {
    std::size_t pos = data2.find(data[i]);
    if(pos == std::string::npos) {
      data2 += data[i];
    }
  }
  return data2;
}

接下来,C ++ 11风格:

std::string duplicates(std::string const& data) {
  std::string data2;
  for( char c : data ) {
    auto pos = data2.find(c);
    if(pos == std::string::npos) {
      data2 += c;
    }
  }
  return data2;
}

答案 1 :(得分:0)

以下代码是关键代码:

 if((pos=data2.find(data[i]))<0){
     data2 += data[i];

data [i]将获取源字符串的每个字符。假装我们将它存储在'C'中。

data2.find(C)现在将在NEW字符串中搜索此字符。将此结果称为“R”

if((pos = R)&lt; 0){}正在检查是否找不到该字符。如果找不到,将返回-1。如果找不到,则使用data2 + = data [i];

将字符添加到目标字符串

请注意,这很复杂,因为它们存储了pos,但未使用它,所以它可以读取:

string duplicates(string &data)
{
   string data2;

   for(int i=0;i<data.length();i++)
   {
      if(data2.find(data[i])<0)
      {
         data2 += data[i];
      }
   }
   return data2;
}

答案 2 :(得分:0)

这里发生的事情非常简单。一个字符串被传入函数,我们遍历这个字符串,分别检查字符串中的每个字符。唯一的复杂因素是声明if((pos=data2.find(data[i]))<0)。让我们分解一下:

data2.find(data[i]) - 这会调用string类中的find函数。给定一些序列,它找到字符串中该序列的第一次出现的索引。如果未找到序列,则返回错误值。对于我们的意图,我们可以假设该值为-1。它实际上有点复杂,但现在这已经足够了。所以回顾一下:0和向上意味着找到序列,-1表示找不到。

pos=data2.find(data[i]) - 我们将该索引分配给变量。

pos=data2.find(data[i]))<0 - 我们检查返回的索引。因为如果未找到序列,则返回-1,如果返回-1,则此检查将评估为true

......基本上就是这样。如果我们像这样重构循环,那么读取代码会更容易:

for(int i=0;i<data.length();i++)
{
  pos=data2.find(data[i]);
  if(pos < 0) {
     data2 += data[i];
  }
}

答案 3 :(得分:0)

基本上,这个函数创建一个具有输入字符串唯一字符的字符串。

首先,您需要知道.find返回参数中给定的字符的位置,如果找不到该字符,则返回string :: npos(-1)。

所以,如果你把“你好”,它就是这样的:

data2 = ""
data2.find('h') == -1
data2 = "h"
data2.find('e') == -1
data2 = "he"
data2.find('l') == -1
data2 = "hel"
data2.find('l') == 2
data2 = "hel"
data2.find('o') == -1
data2 = "helo"
那么,pos的效用是什么? .find返回一个unsigned int,因此检查unsigned int是否低于0将始终返回false,因此我们将它存储在int中,我们可以进行比较。

但等等,还有更多。你可能会问一个unsigned int如何等于-1?你可以阅读this将等待一个更有能力的人更完整的答案