我想知道是否有人可以通过跟踪代码的跟踪来帮助我理解这段代码,因为我对int pos变量实际执行或用于if语句时所使用的内容感到困惑。我的困惑主要与if语句有关。对于这段代码,我将给函数字符串“hello”,在运行data2之后,应该保存带有一个“l”的字符串“helo”,因为它删除了重复项。
我只是希望有人可以引导我深入了解代码,这样我就能更好地理解它,因为我的c ++书并不能很好地解释“.find()”函数。我希望这很容易解释,因为我真的想学习这个!!
三江源!
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;
}
答案 0 :(得分:1)
它返回空字符串,或者通过castimg调用未定义的行为,该符号超出int
范围。虽然signed
到unsigned
转换是安全且定义良好的,但是圆形跳闸只对两者都可以表示的值安全。一些编译器会利用它来消除只能通过UB访问的分支。
在C ++的特定实现上,它可能会特别做点什么。
编写这段代码的程序员搞砸了,每次测试时都可能有效。如果他们将pos
作为变量删除,则删除if
子句中的分配(keepimg右侧),并将-1
替换为std::string::npos
代码变得更容易理解和可能是编码员想要的。
我认为有问题的字符串是std::string
:
duplicates
通过引用获取std::string
data
(因此可以对其进行修改)并返回另一个std::string
:
std::string duplicates(std::string &data)
{
它有两个局部变量data2
和pos
。 data2
是std::string
,pos
是int
(&#34;默认&#34;编译器的有符号整数,通常是2s补码,至少16位,通常是32位):
std::string data2;
int pos;
我们将局部变量i
从0
循环到小于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将等待一个更有能力的人更完整的答案