C++用字符数组与字符串比较

53
我试图将一个字符数组与一个字符串进行比较,代码如下:
const char *var1 = " ";
var1 = getenv("myEnvVar");

if(var1 == "dev")
{
   // do stuff
}

这个if语句从未验证为true...当我输出var1时它是“dev”,我在想也许与空终止字符串有关,但“dev”和var1的strlen相等...我还以为也许var1==“dev”是将“dev”与var1的内存位置进行比较而不是值。* var1 ==“dev”会导致错误...尝试了很多东西,对于精通c++的开发人员来说可能是一个简单的解决方案(我已经很久没有编写c++代码了)。

编辑: 我们已经尝试过

if(strcmp(var1, "dev") == 0)

并且

if(strncmp(var1, "dev", 3) == 0)

谢谢

编辑:在家测试后,我建议我的同事将数据类型更改为字符串。 我相信他是将一个大尺寸的字符数组与一个字符串进行比较。 我编写了一个程序,输出sizeof,strlen等内容,以帮助我们解决问题。 感谢所有人的帮助。


1
看起来你正在使用原始的C字符串,而不是C++的String类。 - tchen
2
尝试使用调试器查看var1是否实际上被填充为“dev1”。此外,如果var1实际上是C++风格的字符串,请使用c_str()函数获取一个C风格的字符串,以便可以使用strcmp()函数将其与您的char*进行比较。 - NomeN
你尝试使用strcmp了吗?很好,结果是什么?(因为这是一个不错的方式) - xtofl
6个回答

91

使用strcmp()函数来比较字符串的内容:

if (strcmp(var1, "dev") == 0) {
}

解释:在C语言中,字符串是指向包含字节的内存位置的指针。使用等号运算符比较char*char*时,不会按预期工作,因为您比较的是字符串的内存位置而不是它们的字节内容。像strcmp()这样的函数将遍历两个字符串,检查它们的字节是否相等。如果它们相等,则strcmp()将返回0,否则返回非零值。有关更多详细信息,请参见manpage


4
@Chris:你能否发布一些使用strcmp()函数的示例?否则,我们将不知道它为什么“不能运行”。 - John Millikin
你确定你没有写成 if(strcmp(var1, "dev")) 吗?使用 strcmp 很容易掉进这个陷阱... - Martin B
@chris 另外,var1 是以 null 结尾的吗?(即代码示例是否100%准确,或者您是否使用以 null 结尾的 "" 字符串进行快速说明) - San Jacinto
我是这个项目的监督者,我的工作系统上没有C++来进行测试,所以我会在回家后进行测试并发布我的发现。 - Chris Klepeis

26
你所处理的并不是字符串,而是指针。
变量var1是一个char指针(const char*),它不是一个字符串。如果它以空字符结尾,那么某些C函数会像对待字符串一样来处理它,但从根本上讲它只是一个指针。

当你将它与char数组进行比较时,数组也会退化为指针,编译器接着会查找operator == (const char*, const char*)
这种运算符确实存在。它使用两个指针,并在它们指向相同地址时返回true。于是编译器调用该运算符,导致你的代码失效。
如果你想进行字符串比较,你需要告诉编译器你想要处理的是字符串,而不是指针
在C语言中,这可以通过使用strcmp函数来实现:
strcmp(var1, "dev");

如果这两个字符串相等,它将返回零。(如果左边的字符串按字典序大于右边的字符串,则返回大于零的值,否则返回小于零的值。)

因此,要进行相等比较,您需要执行以下操作之一:

if (!strcmp(var1, "dev")){...}
if (strcmp(var1, "dev") == 0) {...}

然而,C++拥有一个非常有用的string类。如果我们使用它,那么你的代码会变得更加简单。当然,我们可以从两个参数中创建字符串,但我们只需要用其中之一:

std::string var1 = getenv("myEnvVar");

if(var1 == "dev")
{
   // do stuff
}

现在编译器遇到了一个字符串和字符指针之间的比较。由于字符指针可以隐式转换为字符串,因此编译器可以处理它们,生成一个字符串/字符串比较。这些比较行为与您预期的完全相同。


1
这个解释非常好,而且还建议使用std::string!我第一次阅读时就注意到了 :) - xtofl
一个有趣的陷阱是字符串折叠,在发布版本中测试 "foo" == "foo" 可能会返回 true,因为它们变成了指向相同字符串的指针,但是在调试模式下,字符串折叠被关闭,这个测试将失败。 - paulm

1
在这段代码中,你并没有比较字符串的值,而是比较指针的值。如果你想要比较字符串的值,你需要使用一个字符串比较函数,例如strcmp。
if ( 0 == strcmp(var1, "dev")) {
  ..
}

4
哦,我讨厌把0放在左边(个人观点)。我认为把它放在右边更加直观,并且你正在将结果与函数进行测试,不会出现赋值的情况。 - Martin York
5
我称之为“Yoda编码”(反过来说,嗯?)。我更喜欢使用编译选项来捕获意外赋值。 - Fred Larson
1
@Fred,我不同意你的观点。 :) - JaredPar
最大编译器警告级别,将警告视为错误,不需要使用尤达式 :) - paulm

1
"dev" 不是一个字符串,它是一个像 var1 一样的 const char *。因此,您确实在比较内存地址。由于 var1 是一个 char 指针,*var1 是一个单个字符(准确地说是指向字符序列的第一个字符)。您不能将 char 与 char 指针进行比较,这就是为什么它不起作用的原因。
既然这被标记为 c++,使用 std::string 而不是 char 指针会更明智,这将使 == 正常工作。(您只需要做 const std::string var1 而不是 const char *var1。

1

有更稳定的功能,同时也消除了字符串折叠。

// Add to C++ source
bool string_equal (const char* arg0, const char* arg1)
{
    /*
     * This function wraps string comparison with string pointers
     * (and also works around 'string folding', as I said).
     * Converts pointers to std::string
     * for make use of string equality operator (==).
     * Parameters use 'const' for prevent possible object corruption.
     */
    std::string var0 = (std::string) arg0;
    std::string var1 = (std::string) arg1;
    if (var0 == var1)
    {
        return true;
    }
    else
    {
        return false;
    }
}

并在头部添加声明。
// Parameters use 'const' for prevent possible object corruption.
bool string_equal (const char* arg0, const char* arg1);

使用时,只需将'string_equal'调用放置在if(或三元)语句/块的条件中。

if (string_equal (var1, "dev"))
{
    // It is equal, do what needed here.
}
else
{
    // It is not equal, do what needed here (optional).
}

来源:sinatramultimedia/fl32编解码器(由我自己编写)


0

你对下面这个程序的想法是什么?

#include <stdio.h>
#include <string.h>

int main ()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts ("Looking for R2 astromech droids...");
for (n=0 ; n<3 ; n++)
if (strncmp (str[n],"R2xx",2) == 0)
{
  printf ("found %s\n",str[n]);
}
return 0;
}
//outputs:
//
//Looking for R2 astromech droids...
//found R2D2
//found R2A6

当你考虑将某些内容输入到数组中,然后使用类似上面程序中的strcmp函数时...请查看下面修改后的程序。
#include <iostream>
#include<cctype>
#include <string.h>
#include <string>
using namespace std;

int main()
{
int Students=2;
int Projects=3, Avg2=0, Sum2=0, SumT2=0, AvgT2=0, i=0, j=0;
int Grades[Students][Projects];

for(int j=0; j<=Projects-1; j++){
  for(int i=0; i<=Students; i++) {
 cout <<"Please give grade of student "<< j <<"in project "<< i  <<  ":";
  cin >> Grades[j][i];

  }
  Sum2 = Sum2 + Grades[i][j];
     Avg2 = Sum2/Students;
}
SumT2 = SumT2 + Avg2;
AvgT2 = SumT2/Projects;
cout << "avg is  : " << AvgT2 << " and sum : " << SumT2 << ":";
return 0;
}

将其转换为字符串,除了只读取1个输入并将其余部分丢弃 也许需要两个for循环和两个指针

#include <cstring>
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
char name[100];
//string userInput[26];
int i=0, n=0, m=0;
cout<<"your name? ";
cin>>name;
cout<<"Hello "<<name<< endl;

char *ptr=name;
for (i = 0; i < 20; i++)
{
cout<<i<<" "<<ptr[i]<<" "<<(int)ptr[i]<<endl;
}   
int length = 0;
while(name[length] != '\0')
{
length++;
}
                    for(n=0; n<4; n++)
                {
                            if (strncmp(ptr, "snit", 4) == 0)
                            {
            cout << "you found the snitch "    <<        ptr[i];
                            }
                }
cout<<name <<"is"<<length<<"chars long";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接