You are here:

C++/Another question, about strings.

Advertisement


Question
I'm trying to find out, if a string consists of all numbers or not.
I have basically coded something to test in a simplier environment, but still can not understand why it's not working.  Here it goes.

#include <string.h>
#include <iostream.h>

int main(){
string str = "12345";

cout << atoi(&str[0]);
//There's a problem here, it will cout 12345
//I want just a single '1' to be couted.

for( int i = 0; i < strlen(str) - 1; i++) {
  for(int j = 0; j <= 9; j++) {
     if(atoi(&str[i]) == j) {
        cout << "yes!";
     }
     else {
        cout << "no!";
     }
  }
}

//Thus, because atoi(&str[0]) is not just a
//single number, this for function doesn't work.
//and another thing, keeps giving me error
//could not find a match for strlen(string).

return 0;
}

Thank you again.
Once I'm done with this, I'll show you the completed program.

Answer
OK, let's go through a few things. First you need to differentiate between C-style character strings which are just built in arrays of char which are terminated by a zero character and the C++ library std::string class - and note that it is in the std namespace.

In C there are a set of library functions that work with C-style strings - such as strlen, atoi, strcmp, strcpy etc. Their declarations are in the C header file string.h or the C++ header file cstring.

In C++ the std::string class is defined in the header file string (note: no .h extension). It is a class so objects of std::string have member functions - including ones to obtain the length of the string - in your example str.size() or str.length(). They also have value semantics so can be copied like ints (for example), viz:

       std::string str1("12345");
       std::string str2( str1 );
       std::string str3;
       str3 = str2;

Now &str[0] returns the address of the first character of str - which may or may not be usable as a pointer to a C-style string - depending on the implementation of std::string. This is because there is no requirement to store the characters of a strd::string either in one contiguous area of memory, nor if its does to terminate the string with a zero character. To obtain a pointer to a buffer containing a C-string equivalent to a std::string you should use the c_str() member function e.g. str.c_str().

So if you use, for example, atoi with std::string you should obtain a C-string by calling c_str on the string and passing the result to atoi, viz:
       atoi( str.c_str() );

Now to trying to find out if a string contains only digit characters. In this case atoi will not help - its use is intended to convert a C-string to an integer value - in fact an int type. It does not work on individual characters of the string, and anyway converting from a string to an integer value is much too heavy handed for what you wish to do. The C library contains a set of character classification functions. They are declared in the C header file ctype.h or the C++ header file cctype. They all are similar in that they start with 'is', take a character as their single input parameter (in fact they take an int as the input value so that the special value called EOF may be passed in), and their return value is an int that is non-zero if the argument is of the class of character tested for by the function or false if it is not. The function we are interested in here is isdigit and it can be used like so:

       if ( isdigit(str[i]) )
       {
         std::cout << str[i] << " is a digit\n";
       }
       else // not a digit
       {
         std::cout << str[i] << " is NOT a digit\n";
       }

Or more briefly using the conditional expression ternary operator ?: :

       std::cout << str[i] << " is "
         << ( isdigit(str[i]) ? "a digit\n"
         : "NOT a digit\n" );

(If you have not met this operator before it works like so:

   boolean_expression ? true_expression : false_expression

If boolean_expression is true then true_expression is evaluated and that is the value of the conditional expression otherwise false_expression is evaluated and that is the value.)

Notice that to output one character I just pass the character to the output stream, which in this case is obtained by the expression str[i].

I notice that you are also using iostream.h - either you are using a really old C++ implementation in which case you might find that your implementation does not support namespace std, and some things may not work as intended or your implementation supports a newer more standard implementation of the C++ standard library but ships with the old header files so as not to break existing code and you are using it by mistake.

Assuming the latter case, and that you do in fact have a reasonably up to date implementation of the C++ standard library available to you I suggest you modify your code as follows:

#include <cctype>      // for isdigit
#include <iostream>    // for std::cout
#include <string>      // for std::string

int main()
{
       std::string const str("12345"); // str unmodified make it const

       std::cout << str[0] << "\n"; // output only the 1st character

       for( std::string::size_type i(0); i != str.size(); ++i )
       {
         std::cout << str[i] << " is "
         << ( isdigit(str[i]) ? "a digit\n"
         : "NOT a digit\n" );
       }
}

Note that you do not have to return a value from main - the compiler will add a return 0 implicitly for you. Note also this rule is _only_ for main and no other functions. Lastly note that some compilers get it wrong - most notably MS VC6 so if you are using this compiler you have to add in the return 0 at the end of main.

I have re-written your code to do what I think you were trying to in the code and not what you stated in your question.

To achieve what you stated you were trying to do in your question modify the code so that the loop is executed only until a non-digit is found and set a flag if such a character is found:

#include <cctype>      // for isdigit
#include <iostream>    // for std::cout
#include <string>      // for std::string

int main()
{
       std::string const str("12345"); // str unmodified make it const

       bool allDigits(true);
       for( std::string::size_type i(0); i != str.size(); ++i )
       {
         if ( ! isdigit(str[i]) )
         {
         allDigits = false;
         break;
         }
       }
       std::cout << str << " is "
         << ( allDigits ? "all digits\n"
         : "NOT all digits\n" );

}

Now std::string provides member functions to locate parts of a string. One function in particular might be useful here: find_first_not_of. You pass it another string containing characters that are to be searched for and find_first_not_of returns the position of the first character of the string that does not match any of the passed set of characters or the special position value std::string::npos if all characters of the string are in the passed in set of characters.

To use this to check for all digits we need to define a string that contains all the digit characters 0123456789 then we pass this string to find_first_not_of for our string str. If str contains all digits then find_first_not_of will not find any characters out of place and it will return its special fail value std::string::npos. If any characters are not digits (i.e. they are not in the passed in digits string) then the position will be a valid character position and not std::string::npos. Main now look like this:

int main()
{
       std::string const Digits("0123456789");
       std::string const str("12345"); // str unmodified make it const

       bool allDigits
         ( str.find_first_not_of(Digits)==std::string::npos );

       std::cout << str << " is "
         << ( allDigits ? "all digits\n"
         : "NOT all digits\n" );
}

It could be made even briefer. In effect find_first_not_of does the work the previous version of main was doing in its for loop. Oh, and this final version does not need to include cctype as isdigit is not used as we defined our own set of digit characters.

Finally, please do not bother to post me the final program as I will not have time to look at it - I am a working developer so I do get to see a lot of code in my work!  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.