C++/Error C2228 and what is std::string::npos?
Expert: Ralph McArdell - 2/27/2005
QuestionHi Mr.McArdell, thanks for the answers given for the subject: Count the number of occurrences of a word in string.
1) I applied the given samples into a function but I have error: "error C2228: left of '.find' must have class/struct/union type." Why?
2) When do we use "std::string::npos" ?
This is the code:
#include <iostream.h>
#include <string>
int countAnds(char str[]);
int main()
{
char myString[80];
int numberAnds;
cout << "Enter a string to be evaluated:\n";
cin.get(myString, 80);
numberAnds = countAnds(myString);
return 0;
}
int countAnds(char str[])
{ int count=0;
int and_pos=0;
while ( and_pos!=std::string::npos )
{
and_pos = str.find("and", and_pos );
if ( and_pos != std::string::npos )
{
++count;
and_pos += 3;
}
}
return count;
}
Thanks a lot for the explanation! I use Microsoft Visual C++ 6.
AnswerFirst I would like to point out that you should not freak out when you get errors from the compiler – it is a complete stickler for correctness as it sees it (even if the way it sees it is different from the C++ standard). You have to please it to get it to do its job. However, we all make mistakes – I still quite often see the very same error as you have here – but usually for different reasons! No one I know types in correct code to start with very often – even if all we did was mistype a name or forget to end a statement with a semicolon. In fact I usually expect the compiler to complain if I change or add more than a couple of lines and get suspicious if it says all is well – did it actually re-compile the changed code?
In this case you did not read my answer and samples carefully enough.
In your posted code I see the following:
int countAnds(char str[])
In my code I think you saw this:
int WordOccurrenceCount
( std::string const & str, std::string const & word )
Can you spot the difference?
My str is the type std::string – a class defined in the namespace std (in fact it is a reference to a constant object of that type – you can find out for yourself about reference types and const if you have not come across them before). Your str type is the type char str[] – a built in array of char.
The built in array types have no member functions such as the operation find. The compiler worked out that find refers to a member of the object str – but str in your code is a built in array – so the compiler gave you an error.
The error in this case is quite reasonable: '.find' must have class/struct/union type as using .find implies it is a member of some type and such things only apply to objects of user defined compound types – such as std::string and not to built in types such as arrays of char – which is the type of your str parameter.
Note that we speak of user defined types and built in types. User defined types are any types defined in code that is compiled by the compiler. Build in types are those the compiler knows about already such as int, double, char, and (built in) array, pointer and reference types of other types.
Now std::string, and other C++ library types, although not defined by you as a user but provided with the compiler, is defined in code you as a user include in your code and it therefore counts as a user defined type. It is not something the compiler knows about until it sees the code that defines it. In fact you can replace the provided C++ library with 3rd party alternatives – see
http://www.stlport.org/ for a free C++ library implementation that is usable by various compilers and
http://www.dinkumware.com/ for an example of commercial standard library vendor (in fact as far as I know Dinkumware provided MS with the VC6 C++ library but it is the same as the one for VC5 so the out-of-the-box VC6 C++ standard library is very old, not quite standard as some things were added or changed after it was written, and has a few bugs...check out the Dinkumware site for details on patches and upgrades).
As to std::string::npos – we use this with certain values that std::string returns to us – it is used to indicate no position and is most often the result of a failed find operation – in which cases no position can be read to mean not found.
Note that the various find operations of std::string return a value of the type std::string::size_type which is an alias for (i.e. another name for) an unsigned integer type – exactly which unsigned integer type depends on the specific C++ library implementation – it could be unsigned long or maybe unsigned short.
A potential problem is that the std::string::npos value is -1 represented as an unsigned integer which on pretty much all modern platforms will be the highest value supported by that integer type (all its bits will be 1s) – i.e. we loose the negativity and instead have the largest representable positive value. My C++ library reference (The C++ Standard Library A Tutotial and Reference by Nicolai M. Josuttis) indicates that this may be a problem if you store the found positions in a type other than std::string::size_type due to this oddity. I agree with this as in general mixing signed and unsigned values and integers of different sizes can have problems when the values cross the boundaries of the limits of these types.
However I tried it with various unsigned and signed types using -1 for VC7.1 and could not get a problem. If you would like to see what I mean try the following:
unsigned short npos(-1);
long pos(npos);
bool is_pos_npos( pos == npos );
bool is_npos_pos( npos == pos );
If you set a break point on the line after is_npos_pos and check out the values of npos, pos, is_pos_npos, and is_npos_pos in the debugger you should get 65535, 65535, true, true. Now try it with the following type combinations for npos and pos:
unsigned long npos(-1);
long pos(npos);
and
unsigned long npos(-1);
short pos(npos);
This should cover the cases where npos is has less bits than pos, npos is the same bit length as pos so the only difference is that npos is unsigned and pos is signed and npos has more bits than pos.
If you do not know how to use the VC6 debugger then I suggest you learn. Hint: to set a breakpoint set the typing position caret in the editor to somewhere on the line you wish execution to break at and press F9 (which may vary depending on your setup). A red circle appears to the left of the line. Pressing F9 again will remove the break point. Some lines cannot be broken on but VC will only complain when you start debugging the program (F5 or Build->Debug->Go or the Go button on the build toolbar). You might also like to enable the Debug tool bar (Tools->Customize->Toolbars). When broken you can use F5 or Go to continue, F10 to step over to the next line without entering a function etc.. You can also examine the value of variables – such as npos, pos etc.