views:

132

answers:

5

I would like to compare a character literal with the first element of string, to check for comments in a file. Why use a char? I want to make this into a function, which accepts a character var for the comment. I don't want to allow a string because I want to limit it to a single character in length.

With that in mind I assumed the easy way to go would be to address the character and pass it to the std::string's compare function. However this is giving me unintended results.

My code is as follows:

#include <string>
#include <iostream>

int main ( int argc, char *argv[] )
{
  std::string my_string = "bob";
  char my_char1 = 'a';
  char my_char2 = 'b';

  std::cout << "STRING : " << my_string.substr(0,1) << std::endl
        << "CHAR : " << my_char1 << std::endl;
  if (my_string.substr(0,1).compare(&my_char1)==0)
    std::cout << "WOW!" << std::endl;
  else
    std::cout << "NOPE..." << std::endl;

  std::cout << "STRING : " << my_string.substr(0,1) << std::endl
        << "CHAR : " << my_char2 << std::endl;
  if (my_string.substr(0,1).compare(&my_char2)==0)
    std::cout << "WOW!" << std::endl;
  else
    std::cout << "NOPE..." << std::endl;

  std::cout << "STRING : " << my_string << std::endl
        << "STRING 2 : " << "bob" << std::endl;
  if (my_string.compare("bob")==0)
    std::cout << "WOW!" << std::endl;
  else
    std::cout << "NOPE..." << std::endl;
}

Gives me...

STRING : b
CHAR : a
NOPE...
STRING : b
CHAR : b
NOPE...
STRING : bob
STRING 2 : bob
WOW!

Why does the function think the sub-string and character aren't the same. What's the shortest way to properly compare chars and std::string vars?

(a short rant to avoid reclassification of my question.... feel free to skip)
When I say shortest I mean that out of a desire for coding eloquence. Please note, this is NOT a homework question. I am a chemical engineering Ph.D candidate and am coding as part of independent research. One of my last questions was reclassified as "homework" by user msw (who also made a snide remark) when I asked about efficiency, which I considered on the border of abuse. My code may or may not be reused by others, but I'm trying to make it easy to read and maintainable. I also have a bizarre desire to make my code as efficient as possible where possible. Hence the questions on efficiency and eloquence.

+2  A: 

You can use the operator[] of string to compare it to a single char

// string::operator[]
#include <iostream>
#include <string>
using namespace std;

int main ()
{
    string str ("Test string");
    int i; char c = 't';
    for (i=0; i < str.length(); i++)
    {
        if (c == str[i]) {
            std::cout << "Equal at position i = " << i << std::endl;
        }
    }
    return 0;
}
Leonid
+12  A: 

Doing this:

  if (my_string.substr(0,1).compare(&my_char2)==0)

Won't work because you're "tricking" the string into thinking it's getting a pointer to a null-terminated C-string. This will have weird effects up to and including crashing your program. Instead, just use normal equality to compare the first character of the string with my_char:

 if (my_string[0] == my_char)
   // do stuff
Colen
And don't forget to check that `0 < my_string.length()` before you try to access `my_string[0]`.
Roland Illig
+1  A: 

The behaviour of the first two calls to compare is entirely dependent on what random memory contents follows the address of each char. You are calling basic_string::compare(const char*) and the param here is assumed to be a C-String (null-terminated), not a single char. The compare() call will compare your desired char, followed by everything in memory after that char up to the next 0x00 byte, with the std::string in hand.

Otoh the << operator does have a proper overload for char input so your output does not reflect what you are actually comparing here.

Convert the decls of and b to be const char[] a = "a"; and you will get what you want to happen.

Steve Townsend
+3  A: 

Why not just use the indexing operator on your string? It will return a char type.

if (my_string[0] == my_char1)
Ferruccio
A: 

Pretty standard, strings in c++ are null-terminated; characters are not. So by using the standard compare method you're really checking if "b\0" == 'b'.

I used this and got the desired output:

if (my_string.substr(0,1).compare( 0, 1, &my_char2, 1)==0 )
    std::cout << "WOW!" << std::endl;
else
    std::cout << "NOPE..." << std::endl;

What this is saying is start at position 0 of the substring, use a length of 1, and compare it to my character reference with a length of 1. Reference

Tony
Strings in c++ are NOT null-terminated. They are null-terminated in C, because they are actually a pointer to char.
Draco Ater
@Draco: `std::string` is not required to be null-terminated (although that is changing in 0x), but there are still plenty of places in the C++ standard that assumes null-terminated array of char. Including a number of methods within `std::string`, as this question illustrates.
Dennis Zickefoose