Home > Back-end >  String appending integers from a vector of int won't print anything
String appending integers from a vector of int won't print anything

Time:04-17

Background: I just finished an exercise that involved making a stack using linked lists, and then using a vector of char stack to perform various functions such as converting decimal numbers to binary, hexadecimal, and octal, and reversing a string. The final step of the conversion involved pushing each character (e.g. remainder in a number system pushed in the stack) in a string for printing. Check out the Decimal to Octal program below for a better understanding:

Stack <int> stack; //Using a stack of char to store each remainder.

   int input; //Store user input.
   int remainder; //Store remainder for each step.
   string converter("01234567"); //Map the octal number system.
   string octal; //Store the final octal number.

   do { //Ask the user to input a positive number.
      cout << "Please enter a postive number to be converted to its equivalent octal number: ";
      cin >> input;
   } while (input <= 0);

   while (input != 0) { //Creation of the octal numbers and pushing them into the stack.
      remainder = input % 8; //Get the remainder of the input after dividing it by 8.
      stack.push(converter[remainder]); //Add the remainder in the stack.
      input = input / 8; //Get the quotient (whole number) of the input after its division by eight.
      //Repeat until the quotient is less than 1 (i.e. '0' in the terms of an integer).
   }

   while (!stack.empty()) { //Push the contents of the stack into the string octal and clear the stack.
      octal.push_back(stack.top()); //Add each octal digit last in first out.
      stack.pop(); //Clear the stack.
   }

   //Print the octal number.
   cout << "The octal number is: " << octal;

Problem: I tried imitating the stack using a vector of integers, and tried the above method, but printing the string in the code below does not output anything:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<int> v;
    
    for(int i = 0; i < 10; i  ) {
        v.push_back(i);
    }
    
    string s;
    
    for(int j = 0; j < v.size(); j  ) {
        s.push_back(v.back());
        v.pop_back();
    }
    
    cout << s;
    
    return 0;
}

Note:

I did notice that if I try something such as s.pushback('c');, the char 'c' gets added to the string and could be printed.

Also, the stack program is built on a template implementation of linked list. So I have four files: list.h, list.cpp, stack.h, and stack. cpp. And the main.cpp for experimenting with different functions.

CodePudding user response:

First, the char elements that you are adding to your string (s) will have values of (potentially) 0 thru 9; assuming your platform uses the ASCII representation, none of these corresponds to a visible character. To convert numerical values into the printable digits they represent, you need to add the value '0'.

Next, your vector (v) is being reduced in size on each loop, but you are also incrementing the j count; so, the for loop will only run through half the vector; at that point, the incremented j will overtake the v.size() value. Use a while(v.size()) loop, instead:

int main()
{
    std::vector<int> v;
    for (int i = 0; i < 10; i  ) {
        v.push_back(i);
    }
    std::string s;
    while (v.size()) { // Will stop when v is empty
        s.push_back(v.back()   '0'); // Add '0' to convert to a digit
        v.pop_back(); // This removes an element and decreases .size()
    }
    std::cout << s << "\n";
    return 0;
}

CodePudding user response:

std::string.push_back takes a char as its argument.
You are pushing v.back() to the string but v.back() is an int.
Therefore, it is implicitly converted to char which does not have the behavior that we want here.

Think of it as the ASCII table. The number 0 is not the character '0' but NULL.
The character '0' is 48 decimal.

Turning single digits to char is pretty simple (and is guaranteed by the standard to work in all character encodings):

char c = '0'   i;

So '0' v.back() here.

CodePudding user response:

Another solution is to use std::transform, thus not requiring any loop:

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <numeric>

int main()
{
    std::vector<int> v(10);
    std::iota(v.begin(), v.end(), 0);
    std::string s;
    std::transform(v.rbegin(), v.rend(), 
                   std::back_inserter(s), [&](int n) { return n   '0'; });    
    v.clear();
    std::cout << s << "\n";
    return 0;
} 

Output:

9876543210

Basically, the std::transform is the "loop". Note that the iteration is done backwards by giving std::transform the reverse iterators. The std::back_inserter simply calls s.push_back() for each character that the lambda produces.

The std::iota function is basically a shortcut for producing values 0,1,2,3,... within the vector.

CodePudding user response:

The main problem is that while iterating you're changing the size of the vector. That is, j gets incremented in each iteration v.size() is decremented in each iteration because of the v.pop_back(). Thus the loop will only be executed half number of times of the original v.size(). For example, if v.size() was 10 originally, then loop will be executed only 5 number of times. And if v.size() was an odd positive integer say n then the loop will iterate (n/2) 1 integer number of times.

Additionally, the elements that you're currently adding inside the vector v are non-printable(not visible) characters, assuming the underlying platform uses ASCII.

You can change v.push_back(i) to:

v.push_back(i   '0');

to verify that the final string contains only half number of characters.

Demo

Solution 1

You can also use std::vector::rbegin and std::vector::rend as shown below:

int main()
{
    std::vector<int> v;
    
    for(int i = 0; i < 10; i  ) {
        v.push_back(i   '0');
    }
    
    std::string s(v.rbegin(), v.rend());
    std::cout<<s<<std::endl;
    
    return 0;
}

Solution 2

You can use a while loop or change the for loop to what is shown below:

int main()
{
    std::vector<int> v;
    
    for(int i = 0; i < 10; i  ) {
        v.push_back(i   '0');
    }
    
    std::string s;
    
//-------vvvvvvv--------->changed the condition
    for(;v.size();) {  //or use while(v.size()) here
        s.push_back(v.back());
        v.pop_back();
       
    }
    std::cout<<s<<std::endl;
    
    return 0;
}
  • Related