C++ Hates Me Part II (Strings and Char)

MrColin

Platinum Member
May 21, 2003
2,403
3
81
[Scroll down to post #9 for more current questions please, thanks for reading]
My goal is one problem per day on Project Euler and so far I'm on track. I may need to change that if they get too hard or I get too busy.

My code for Question 4 works pretty well. I initially wanted to write a function that took an integer, converted to a string and reversed it, returning it as an integer (for testing of palindromicity). The stuff I tried would often give errors like "invalid casting of int to char" or sometimes it would compile but on execution it raped my mom and laughed at me and I needed task manager to make it stop.

Ultimately I used a math based approach to reverse the digits like so:
Code:
int revint(int sourcenum){
	int temp = sourcenum;
	int sum = 0;
	while (temp){
		sum *= 10;
		sum += temp%10;
		temp /= 10;
	}
	return sum;
}
(I confess, the code above came from http://www.cplusplus.com/forum/beginner/812/ ). I feel ok about using it because I can understand what it does.

My question is however, how might you do the int --> string --> int conversion? "cast..." and "static_cast..." or "char = someintegervarialbe;" eluded me somehow and my mom will never be the same.
 
Last edited:

iCyborg

Golden Member
Aug 8, 2008
1,353
62
91
I would personally use atoi() and itoa(), but for educational purposes, you could use for your problem something like the following:
Code:
char buffer[10];
int pos = 0;

while (number>0)
{
	buffer[pos++] = char(number%10) + char('0');
	number /= 10;
}
buffer[pos] = 0;

This will construct it in reverse order, which is what you need in the problem, it's not hard to get in proper order. char and int are sort of interchangeable in C/C++ with some due care.
string to int is similar, you just inspect individual characters and update 'number'
 

Crusty

Lifer
Sep 30, 2001
12,684
2
81
Well the C++ way of doing it would use istringstream and ostringstream.

To convert int -> string and then reverse the string you could do something like the following.

Code:
stringstream ss;
ss << integer;
string int_string = ss.str();
string rev_int_string(ss.rbegin(), ss.rend());

However, in practice I would use boost::lexical_cast to do the casting.
 

esun

Platinum Member
Nov 12, 2001
2,214
0
0
I agree with using boost::lexical_cast, this is what it was made for. itoa is a non-standard function, too, so I wouldn't recommend it. With boost::lexical_cast your code would look like this:

int x = 5;
std::string s = boost::lexical_cast<std::string>(x);

Just a warning, installing boost can be a bit daunting if you have never done it before.
 

MrColin

Platinum Member
May 21, 2003
2,403
3
81
I agree with using boost::lexical_cast, this is what it was made for. itoa is a non-standard function, too, so I wouldn't recommend it. With boost::lexical_cast your code would look like this:

int x = 5;
std::string s = boost::lexical_cast<std::string>(x);

Just a warning, installing boost can be a bit daunting if you have never done it before.

Am I correct in thinking that boost is this FOSS library http://www.boost.org/ and/or libboost-dev for packaged dev headers under Linux?
 

DaveSimmons

Elite Member
Aug 12, 2001
40,730
670
126
One C approach would use sprintf or itoa to make the char string, then either in-place swapping of characters or copying to a second string buffer.

Code:
char buff1 [ 32 ], buff2 [ 32 ] ;
int len, num;

num = 12345;
sprintf ( buff1,  "%d",  num ) ;
len = strlen (buff1) ;
for (int i = 0; i < len; i++ )
{
buff2[i] = buff1[(len-1)-i];
}
buff2[len] = 0;  // must terminate string
 

tatteredpotato

Diamond Member
Jul 23, 2006
3,934
0
76
I agree with using boost::lexical_cast, this is what it was made for. itoa is a non-standard function, too, so I wouldn't recommend it. With boost::lexical_cast your code would look like this:

int x = 5;
std::string s = boost::lexical_cast<std::string>(x);

Just a warning, installing boost can be a bit daunting if you have never done it before.

I would suggest OP learn the standard C++ (or even standard C) way of doing things before he concerns himself with boost.
 

MrColin

Platinum Member
May 21, 2003
2,403
3
81
One C approach would use sprintf or itoa to make the char string, then either in-place swapping of characters or copying to a second string buffer.

Code:
char buff1 [ 32 ], buff2 [ 32 ] ;
int len, num;

num = 12345;
sprintf ( buff1,  "%d",  num ) ;
len = strlen (buff1) ;
for (int i = 0; i < len; i++ )
{
buff2[i] = buff1[(len-1)-i];
}
buff2[len] = 0;  // must terminate string
I'm going to look into this. However googling around the net it seems like a lot of people are saying itoa is bad and sprintf is dangerous.


Anyway, I'm still kind of hung up on casting strings to integers. I have an Ubuntu box with boost and I've been trying to use that, among other things. Getting my but kicked. Here's my code for Euler problem 8. The compiler errors I get are commented in the getfive function. I'm probably not doing the string array correctly either.
Code:
/*
 Problem 8:
 Find the greatest product of five consecutive digits in the 1000-digit number:

 73167176531330624919225119674426574742355349194934
 96983520312774506326239578318016984801869478851843
 85861560789112949495459501737958331952853208805511
 12540698747158523863050715693290963295227443043557
 66896648950445244523161731856403098711121722383113
 62229893423380308135336276614282806444486645238749
 30358907296290491560440772390713810515859307960866
 70172427121883998797908792274921901699720888093776
 65727333001053367881220235421809751254540594752243
 52584907711670556013604839586446706324415722155397
 53697817977846174064955149290862569321978468622482
 83972241375657056057490261407972968652414535100474
 82166370484403199890008895243450658541227588666881
 16427171479924442928230863465674813919123162824586
 17866458359124566529476545682848912883142607690042
 24219022671055626321111109370544217506941658960408
 07198403850962455444362981230987879927244284909188
 84580156166097919133875499200524063689912560717606
 05886116467109405077541002256983155200055935729725
 71636269561882670428252483600823257530420752963450
*/
#include <iostream>
#include</usr/include/boost/lexical_cast.hpp>

using namespace std;

const string knum[] = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";

int getfive(int p);

int main(){
int highnum = 0;
    for(int i = 0; i <=1000; i++){
        if(getfive(i) > highnum){
            highnum = getfive(i);
        }

    }
cout << "Answer: " << highnum;
}

int getfive(int p){
    int product;
    for(int j = 1; j <= 5; j++){

       //shot my dog
       //[color=red]product *=  boost::lexical_cast<int>(knum[p]);[/color]
       //boost exception (maybe close though?).

       // boiled my rabbit
       //[color=red]product *=  boost::lexical_cast<std::int>(knum[p]);[/color]
       // error: no matching function for call to &#8216;lexical_cast(std::string&)&#8217;

        // emailed photoshopped pics of me in a compromising position
        // [color=red]product *= atoi(knum[p]);[/color]
        // error: cannot convert &#8216;const string {aka const std::basic_string<char>}&#8217; to &#8216;const char*&#8217; for argument &#8216;1&#8217; to &#8216;int atoi(const char*)&#8217;

       p++;
    }
    return product;
}
 
Last edited:

mv2devnull

Golden Member
Apr 13, 2010
1,526
160
106
Boost is a collection of libraries. The C++11 Standard did include some of them. Therefore, some of the boost is already the "standard C++ way".
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,696
4,658
75
A nice thing about ASCII is that the numbers 0-9 are sequential. Therefore, subtracting '0' from a char gets you the numeric value, assuming it was a numeric character to begin with.
 

esun

Platinum Member
Nov 12, 2001
2,214
0
0
To encourage you to figure out the problem yourself, I would suggest writing the minimum example code that does what you want to do (e.g., takes an integer and converts it to a std::string using boost). If you're not sure how to use std::string, don't just guess, look up the documentation. That's how people learn to code.
 

DaveSimmons

Elite Member
Aug 12, 2001
40,730
670
126
> const string knum[] = ....
> // product *= atoi(knum[ p ]) ;
> // error: cannot convert &#8216;const string {aka const std::basic_string<char>}&#8217; to &#8216;const char*&#8217; for argument &#8216;1&#8217; to &#8216;int atoi(const char*)&#8217;


Keep in mind that a character string and string type are not the same thing. If you had used const char* charstring = 'aaaa" that would have compiled.

A character string is just an array of characters with a 0 (not "0") character at the end to terminate it.

itoa and sprintf are character string functions.

Also this:
> A nice thing about ASCII is that the numbers 0-9 are sequential. Therefore, subtracting '0' from a char gets you the numeric value, assuming it was a numeric character to begin with.

So for single characters, int sum = (a - '0') + (b - '0') will work as long as a and b are characters in the range '0' ... '9'.
 

MrColin

Platinum Member
May 21, 2003
2,403
3
81
To encourage you to figure out the problem yourself, I would suggest writing the minimum example code that does what you want to do (e.g., takes an integer and converts it to a std::string using boost). If you're not sure how to use std::string, don't just guess, look up the documentation. That's how people learn to code.

I agree about the approach you propose for learning and testing, getting #'s to string or char works fine for me but it seems like if its a string or char c++ can never make it an int.

For this particular problem I have a 1000 digit number and even if there is appropriate numeric data type for such a number, it's easier to pick the digits from it as a string. It doesn't matter to me for this example whether it is a proper string or a char variable as long as I can pick the digits out of it and manipulate them as integers.

I'm mainly having the issues with casting string or char to int and it doesn't appear that even boost handles that. atoi(char[n]) always gives "error: invalid conversion from &#8216;char&#8217; to &#8216;const char*&#8217; [-fpermissive]" I find this confusing because according to http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ it does this:
Parses the C string str interpreting its content as an integral number, which is returned as an int value.
It sounds an awful lot like what I want to do. I'm guessing its something to do with pointers and arrays that I haven't learned yet.
So now I have this incomplete function that does what I expected atoi to do:
Code:
#include <iostream>
#include <cstdlib>
using namespace std;
int chartoint(char c);
char knum[] = "731671765313306249192251";
int main(){
    char asinglechar = knum[0];
    int iusedtobeachar = asinglechar;
    cout << iusedtobeachar << " is the decimal ASCII code of " << asinglechar << endl;
    cout << "chartoint function gets desired result if the following line is '7': " << endl;
    cout << chartoint(knum[0]);
}
int chartoint (char c){
    int temp = c;
    if(temp > 47 || temp < 58){
        temp -= 48;
    }else{
        // todo: add proper exception handling here
        temp = 0;
    }
    return temp;
}
which produces:
55 is the decimal ASCII code for 7
chartoint function gets desired result if the following line is '7':
7
I guess now, atoi doesn't like the array reference, I'm going to play with it some more and see (after I solve the Euler problem with my badly coded function, haha!)
 
Last edited:

esun

Platinum Member
Nov 12, 2001
2,214
0
0
"error: invalid conversion from &#8216;char&#8217; to &#8216;const char*&#8217; [-fpermissive]"
Parses the C string str interpreting its content as an integral number, which is returned as an int value.

Two questions for you to ponder:

1. What is the difference between a char and a const char*?

2. What is a C string?
 

DaveSimmons

Elite Member
Aug 12, 2001
40,730
670
126
Also realize that if you have

const char* foo = "123456789" ;

Then foo[4] is not a character string!

foo is a character string, which is an array of characters with a 0 terminator. Or rather, foo is really a pointer to an array of characters.

So what is the type of foo[4] ? It's not an array, or character string, or pointer. It's just a single character. In this case it is the character '5'.

If you say int i = atoi('5') ; you'll get a similar error. '5' = 1 character, not a string. "5" = an array of _2_ characters, '5' + 0, a string.


Edit: And if you want to really confuse yourself....

& foo[4] is a string, but not what you probably think it is. When you take the address of foo[4] you get the string "56789".
 
Last edited:

mv2devnull

Golden Member
Apr 13, 2010
1,526
160
106
Code:
const string knum[] = "73167..";

  for(int i = 0; i <=1000; i++){
   if(getfive(i) > highnum){
     highnum = getfive(i);
   }
 }

int foo = boost::lexical_cast(knum[p]);
Initializing an array of strings with single item is not what you want. What you get there is that string "kum[0]" contains a 1000-character string. What you really wanted was one string only.

A loop of fixed size is no C++ (and poor C too). If you iterate over array, you should use the size of the array. What you should have done here is to iterate through the characters of one string. Do not trust the string to have 1000 characters. Ask the string how many it has.

There is no point to call "heavy" funtions like getfive() twice. Call once, store result and use that.

Exception is no miracle. On knum[0], a 1000-digit number does not fit into int. Had you gotten to 0<p, well there were no such knum[p].

If knum is a std::string, then:
int foo = boost::lexical_cast<int>( knum.substr( p, 1 ) );
Should yield a number from one character.
 
Last edited:

iCyborg

Golden Member
Aug 8, 2008
1,353
62
91
Code:
/*
 Problem 8:
 Find the greatest product of five consecutive digits in the 1000-digit number:

 73167176531330624919225119674426574742355349194934
 96983520312774506326239578318016984801869478851843
 85861560789112949495459501737958331952853208805511
 12540698747158523863050715693290963295227443043557
 66896648950445244523161731856403098711121722383113
 62229893423380308135336276614282806444486645238749
 30358907296290491560440772390713810515859307960866
 70172427121883998797908792274921901699720888093776
 65727333001053367881220235421809751254540594752243
 52584907711670556013604839586446706324415722155397
 53697817977846174064955149290862569321978468622482
 83972241375657056057490261407972968652414535100474
 82166370484403199890008895243450658541227588666881
 16427171479924442928230863465674813919123162824586
 17866458359124566529476545682848912883142607690042
 24219022671055626321111109370544217506941658960408
 07198403850962455444362981230987879927244284909188
 84580156166097919133875499200524063689912560717606
 05886116467109405077541002256983155200055935729725
 71636269561882670428252483600823257530420752963450
*/
#include <iostream>
#include</usr/include/boost/lexical_cast.hpp>

using namespace std;

const string knum[] = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";

int getfive(int p);

int main(){
int highnum = 0;
    for(int i = 0; i <=1000; i++){
        if(getfive(i) > highnum){
            highnum = getfive(i);
        }

    }
cout << "Answer: " << highnum;
}

int getfive(int p){
    int product;
    for(int j = 1; j <= 5; j++){

       //shot my dog
       //[color=red]product *=  boost::lexical_cast<int>(knum[p]);[/color]
       //boost exception (maybe close though?).

       // boiled my rabbit
       //[color=red]product *=  boost::lexical_cast<std::int>(knum[p]);[/color]
       // error: no matching function for call to ‘lexical_cast(std::string&)’

        // emailed photoshopped pics of me in a compromising position
        // [color=red]product *= atoi(knum[p]);[/color]
        // error: cannot convert ‘const string {aka const std::basic_string<char>}’ to ‘const char*’ for argument ‘1’ to ‘int atoi(const char*)’

       p++;
    }
    return product;
}
Assuming problem 8 isn't about learning how to manipulate strings and ints, your approach, even if it worked, is quite inefficient. You shouldn't be reading a string of five chars, convert to int, and then find a product. Hint: having a product of 5 numbers starting at 'i', you can get a product of 5 numbers starting from i+1 with only 2 operations inspecting only 2 digits/chars. Some care is needed for dealing with 0s, but 0s actually speed up things.
 

MrColin

Platinum Member
May 21, 2003
2,403
3
81
Just want to thank everyone for the insight provided here. I often require some explanation when the documentation I find doesn't mean quite what I think it does.

For the problem I ultimately ended up using something like:
Code:
int integervariable = (constStringvariable[n] - '0');
 

Markbnj

Elite Member <br>Moderator Emeritus
Moderator
Sep 16, 2005
15,682
14
81
www.markbetz.net
Just want to thank everyone for the insight provided here. I often require some explanation when the documentation I find doesn't mean quite what I think it does.

For the problem I ultimately ended up using something like:
Code:
int integervariable = (constStringvariable[n] - '0');

An old trick :). Don't worry about asking questions, it's how we all learned.