Add value to beginning (left hand side) of string

Pages: 12
May 19, 2013 at 1:47am
This is probably a stupid question, but how do you add a value to the beginning of a string instead of the end?

This is for an assignment and I have to convert the user input (always assuming its a valid decimal number) to binary and store it in a string. I've got up to dividing by two to get the remainder ...
May 19, 2013 at 1:51am
You have to be more specific.

C or C++?

What do you mean by "value"? Integer? String?


[edit]
On re-reading your question, perhaps you want this:

1
2
3
string s = "234567";
char c = '1';
s = c + s;

Hope this helps.
Last edited on May 19, 2013 at 1:52am
May 19, 2013 at 2:14am
Yea, thanks, that helps heaps. I can't believe i didn't think of it
May 19, 2013 at 3:47am
Sorry about this, but how would you do the same thing but with an int, instead of a char? I'm having trouble with the conversion ...
May 19, 2013 at 4:39am
Take the initial binary number (any int variable,suppose b_num) as 0.
In a loop, assign b_num = remainder*(power of 10) + b_num.


Something like this :
bnum=(dnum%2)*pow(10,x)+bnum;

Each time, raise x by 1 and divide the decimal integer(dnum) by 2.

May 19, 2013 at 5:22am
or...
1
2
3
4
std::string s = "234567";
int i = 1;
s = ( char )( i + '0' ) + s;
std::cout << s << std::endl;


or
1
2
3
4
5
std::string s = "234567";
int i = 1;
char c = i + '0';
s = c + s;
std::cout << s << std::endl;
Last edited on May 19, 2013 at 5:24am
May 19, 2013 at 10:08am
corbett when i do it your way an error comes up saying no match for operator * in ((double)remain * pow(1.0e+1, (double)i)) + binary. At the moment i have:

1
2
3
4
5
6
string binary = "";
for (int i = 0; input != 0; i++) {
    int remainder = input%2;
    binary = (remainder * power(10, i))  + "" + binary;
    input = input/2;
}
May 19, 2013 at 10:57am
1
2
3
4
5
6
7
8
9
10
11
std::string binary;
binary.reserve( std::numeric_limits<unsigned int>::digits );

const unsigned int base = 2;
do
{
   unsigned int digit = input % base;
   binary += digit + '0';
} while ( input /= base );

binary.assign( binary.rbegin(), binary.rend() );
Last edited on May 19, 2013 at 11:00am
May 19, 2013 at 12:24pm
I don't think you need the power (or pow) in your code? Also, giblit's suggestion does make sense! If you alter line 4 accordingly, your code will work.

vlad's solution is the standard one -- add to back of string and then swap at the end -- but your add-to-the-front approach should produce the same result.

Note that the reserve is an optimization, to speed up operator++; the conversion code will work fine if it is omitted. If it is used, then you can remove the space capacity using binary.shrink_to_fit(); if you're using C++11 or [code]string(binary).swap(binary); .

Personally I would use reverse( binary.begin(), binary.end() ); (the std::reverse algorithm) rather than binary.assign( binary.rbegin(), binary.rend() );

As your code stands, it's line 4 which is very sick:

binary = (remainder * pow(10.0, i)) + "" + binary;

Breaking it down...

- pow(10.0, i) - returns a double [1]

Note that passing an int for the first parameter of pow() can confuse the compiler as there is more than one overload of pow(). But they do all return some sort of floating point number: float, double, long double.

- remainder * {value} - returns another double (int values are promoted to doubles before performing multiplication with a double.)

- {value} + "" - is invalid for a double value.

It's also invalid for an int value, so casting to an int would be a waste of time.

In this situation, "" is seen as the memory address of a blank string. And you can't add a memory address to an int. You can, however, add the value of the address:

1
2
    int i = 0;
    int j = i + (int)"";


or add an integer to an address; this is part of pointer arithmatic (see Pointer craft
http://www.cplusplus.com/articles/z186b7Xj/ )

1
2
    const char* p = "Hello world" + 6;
    cout << p << endl; // outputs "world" 


But there is a std::string overload of operator= which knows how to add a C null-terminated string to a C++ string. So you if you convert (not cast) the required value to a string, then you can add it on.

To convert a double or int to string you need to use an ostringstream (there are other ways, but this is the prefered method in C++ code.)

So, bearing all of this in mind, you could "fix" your code like this:

1
2
3
4
5
6
7
8
9
10
    string binary = "";
    for (int i = 0; input != 0; i++) {
        int remainder = input%2;
        //binary = (remainder * power(10, i))  + "" + binary;
        int j = (remainder * power(10, i))  + (int)"";
        ostringstream oss; // needs <sstream>
        oss << j;
        binary = oss.str() + binary;
        input = input/2;
    }


But the o/p value of this code for 64 is:

5329930432993043299304329930432993043299304329930


rather than the required

1000000


Andy
Last edited on May 20, 2013 at 1:17am
May 19, 2013 at 1:18pm
Recursive:
1
2
3
4
5
6
7
8
9
#include <string>

std::string to_binary( unsigned int v )
{
    if( v == 0 ) return "" ;
    else return to_binary(v/2) + char( v%2 ? '1' : '0' ) ;
}

std::string itob( unsigned int v ) { return v == 0 ? "0" : to_binary(v) ; }

May 19, 2013 at 2:19pm
1
2
3
4
5
std::string itob( unsigned int number ) 
{
	char digit = '0' + ( number & 1 );
	return ( ( number >>= 1 ) ? itob( number ) + digit : std::string( 1, digit ) );
}
May 19, 2013 at 2:36pm
Another recursive version, using bits stolen from both JLBorge's and vlad's code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void to_binary( unsigned int v, string& b )
{
	if( v == 0 ) return;
	b += v%2 ? '1' : '0';
	to_binary( v/2, b );
}

std::string itob( unsigned int v )
{
	if(0 == v)                  // Edit: Hack to fix the
		return string("0"); // 0 case...
	std::string binary;
	binary.reserve( std::numeric_limits<unsigned int>::digits );
	to_binary( v, binary );
	return string( binary.rbegin(), binary.rend() );
}


Note that in this case, the return sequence strips away any spare string capacity.

Andy
Last edited on May 20, 2013 at 12:45am
May 19, 2013 at 10:24pm
@andywestken


Your function returns an empty string in case when v is equal to 0. By the way 0 is a valid number
Also there is no any sence to call string( binary.rbegin(), binary.rend() ) for a recursive function..

So in my opinion your realization is not satisfactory.
May 20, 2013 at 12:38am
I have done it a similar way to Andy and an error comes up saying "cast from const chat to int looses perception":

1
2
3
4
5
6
7
8
string binary = "";
for (int i = 0; input != 0; i++) {
  int remain = input%2 + (int)"";
  ostringstream s;
  s << remain;
  binary = s.str() + binary;
  input = input/2;
}
May 20, 2013 at 12:52am
So in my opinion your realization is not satisfactory.

Well, maybe I should have put a smiley -- it was only a "whimscial" solution. I would use the standard while loop-plus swap in real life.

The point of previous feeble attempt was to avoid construction and destruction of strings during the iteration.

Andy

PS And I have put in a fix hack to fix the 0 case.
Last edited on May 20, 2013 at 12:53am
May 20, 2013 at 2:18am
By the way what is the difference between ostringstream, istringstream and stringstream? I googled some examples earlier and they used different ones, is there a preferred stream for this conversion?
Last edited on May 20, 2013 at 2:31am
May 20, 2013 at 2:54am
"cast from const chat to int looses perception":

I apologise for confusing the issue: I was saying you shouldn't use either (int)"" or ostringstream. You just need this:

1
2
3
4
5
6
string binary = "";
for (int i = 0; input != 0; i++) {
  int remain = input%2;
  binary = (char)(remain + '0') + binary;
  input = input/2;
}


As (a) the ascii code for '1' is one bigger than that for '0', and (b) remain is either 0 or 1, the (char)(remain + '0') will always evaluate to either (the char) '0' or '1', which can be added to the binary string.

But this version doesn't handle the 0 case: it input is 0, the for-loop neer runs. To ensure your loop runs once before terminating, you just need to swap to a do-while-loop:

1
2
3
4
5
6
7
8
string binary = "";
do {
  int remain = input%2; // no (int)""
  ostringstream s;
  s << remain;
  binary = s.str() + binary;
  input = input/2;
} while(input != 0);


This version handles the 0 case correctly, too.

Andy

PS By "perception", do you mean the same as "possible loss of data", which is what my compiler says)

PPS And regarding:
is there a preferred stream for this conversion?

Yes, to convert to a string you need an ostringstream.

o is for output, i is for input, the one with neither o nor i is both input and output.

You only need to output to the string stream to convert your string, so you should you use the output stream.

While it's not a good idea in this case, as each binary digit is either a '0' or '1' (which fits in a char) this code does do the same job using ostringstream and a string (but more slowly):

1
2
3
4
5
6
7
8
string binary = "";
for (int i = 0; input != 0; i++) {
  int remain = input%2; // no (int)""
  ostringstream s;
  s << remain;
  binary = s.str() + binary;
  input = input/2;
}

Last edited on May 20, 2013 at 3:24am
May 20, 2013 at 4:36am
When i don't include (int)"" in my code an the compiler gets an error saying i have an undefined reference on about every line. e.g.
undefined reference to "std::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const"
or
undefined reference to `std::basic_istream<char, std::char_traits<char> >::operator>>(int&)'
do you know why this is happening?

"cast from const char to int looses perception" i thought may just mean that the conversion can't be done that way?
Last edited on May 20, 2013 at 7:02am
May 20, 2013 at 12:23pm
What is your code now?

Andy
May 21, 2013 at 8:55am
I have started again and am trying to use bit shifting. the whole assignment is to convert a decimal number to hexadecimal uintvars (base 128 - http://en.wikipedia.org/wiki/Variable-length_quantity). At the moment my code looks like this (Note: this code isn't well thought through and isn't finished):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <string>
#include <array>

using namespace std;

int main(int argc, char *argv[]){
        unsigned int input;
        cin >> input;
        cout << input << ":\t";

        int binary[1000];
        int count = 0;

        for(int i = 1000; input >= 0; i--) {
                int remain = input%2;
                input /= 2;
                binary[i] = remain;
                count++;

                if (count == 7) {
                        binary = binary * 0x7F;
                } else if ((count%7 == 0) && (count != 7)) {
                        binary = binary * 0xFF;
                }
        }
        cout << setbase(16);
        cout << bianry;
        return 0;
}
Last edited on May 21, 2013 at 9:42am
Pages: 12