A String is given as an input which consists of numbers and I want to convert it into integer arrays in C++.
#include <string>
#include <iostream>
#include <sstream>
using std::string;
using std::stringstream;
using std::cout;
using std::endl;
int main(int argc,char** argv) {
string num="-24 2 90 24 50 76";
stringstream stream(num);
while(stream){
int n;
stream>>n;
cout<<n<<endl;
}
return 0;
}
Output(GCC) :
-24 2 90 24 50 76 76
Why am i getting extra value and what is the efficient to convert them into integer array ?
UPDATE:
What if the string stream contains delimiter other than space, How to parse this?
For eg:
string num="-24,2,90,24,50,76";
The end of file condition is not set upon a succesful parse, you have to check the state of the stream after parsing.
The second 76 is basically just pure chance. An unsuccesful parse leaves the target operand untouched, and because you did not initialize n, it can be anything.
A quickfix:
stream>>n;
if (stream)
cout<<n<<endl;
A cleaner fix:
int n;
while(stream >> n){
cout<<n<<endl;
}
To store those integers, the canonical way is to use std::vector if the number of elements is unknown. An example usage:
std::vector<int> values;
int n;
while(stream >> n){
...do something with n...
values.push_back(n);
}
However, you can use iterators over streams and use the following:
// Use std::vector's range constructor
std::vector<int> values(
(std::istream_iterator<int>(stream)), // begin
(std::istream_iterator<int>())); // end
Another means of dealing with a character separated integers list using a vector, which is even perhaps a little more simplistic is more like this:
string str = "50,2,25,38,9,16";
vector<int> ints;
stringstream ss(str);
int n;
char ch;
while(ss >> n) {
if(ss >> ch)
ints.push_back(n);
else
ints.push_back(n);
}
that way you can move past any character separations (if they exist) first and then default back to grabbing the integers and adding them to the list if they don't (AKA the end of the list)
i don't know if you find the answer for your updated question or not. if you don't you can easily do it by the code
for (string::iterator it = num.begin(); it != num.end(); ++it) {
if (*it == ',') {
*it = ' ';
}
else continue;
}
this code removes all your colons and replaces them by space. then you can do just normally
Related
The Input file:
1 4 red
2 0 blue
3 1 white
4 2 green
5 2 black
what I want to do is take every row and store it into 2D array.
for example:
array[0][0] = 1
array[0][1] = 4
array[0][2] = red
array[1][0] = 2
array[1][1] = 0
array[1][2] = blue
etc..
code Iam working on it:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int convert_str_to_int(const string& str) {
int val;
stringstream ss;
ss << str;
ss >> val;
return val;
}
string getid(string str){
istringstream iss(str);
string pid;
iss >> pid;
return pid;
}
string getnumberofcolors(string str){
istringstream iss(str);
string pid,c;
iss >> pid>>c;
return c;
}
int main() {
string lineinfile ;
vector<string> lines;
ifstream infile("myinputfile.txt");
if ( infile ) {
while ( getline( infile , lineinfile ) ) {
lines.push_back(lineinfile);
}
}
//first line - number of items
int numofitems = convert_str_to_int(lines[0]);
//lopps items info
string ar[numofitems ][3];
int i = 1;
while(i<=numofitems ){
ar[i][0] = getid(lines[i]);
i++;
}
while(i<=numofitems ){
ar[i][1] = getarrivel(lines[i]);
i++;
}
infile.close( ) ;
return 0 ;
}
when I add the second while loop my program stopped working for some reason!
is there any other way to to this or a solution to my program to fix it.
It's better to show you how to do it much better:
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
ifstream infile("myinputfile.txt"); // Streams skip spaces and line breaks
//first line - number of items
size_t numofitems;
infile >> numofitems;
//lopps items info
vector<pair<int, pair<int, string>> ar(numofitems); // Or use std::tuple
for(size_t i = 0; i < numofitems; ++i){
infile >> ar[i].first >> ar[i].second.first >> ar[i].second.second;
}
// infile.close( ) ; // Not needed -- closed automatically
return 0 ;
}
You are probably solving some kind of simple algorithmic task. Take a look at std::pair and std::tuple, which are useful not only as container for two elements, but because of their natural comparison operators.
The answer given is indeed a much better solution than your's. I figured i should point out some of your design flaws and give some tips too improve it.
You redefined a function that already exists in the standard, which is
std::stoi() to convert a string to an integer. Remember, if a function
exists already, it's OK to reuse it, don't think you have to reinvent what's
already been invented. If you're not sure search your favorite c++ reference guide.
The solution stores the data "as is" while you store it as a full string. This doesn't really make sense. You know what the data is beforehand, use that to your advantage. Plus, when you store a line of data like that it must be parsed, converted, and then constructed before it can be used in any way, whereas in the solution the data is constructed once and only once.
Because the format of the data is known beforehand an even better way to load the information is by defining a structure, along with input/output operators. This would look something like this:
struct MyData
{
int num1;
int num2;
std::string color;
friend std::ostream& operator << (std::ostream& os, const MyData& d);
friend std::istream& operator >> (std::istream& os, const MyData& d);
};
Then you could simply do something like this:
...
MyData tmp;
outfile << tmp;
vData.push_back(tmp);
...
Their is no question of intent, we are obviously reading a data type from a stream and storing it in a container. If anything, it's clearer as to what you are doing than either your original solution or the provided one.
I've populated a string vector with with numbers and characters (*,+,-,/). I want to assign each number and character to two new vector, and int vector and a char vector. Is there a way to convert the everything from string to the desired data type?
You can use string stream in the <sstream> header.
string myString = "123";
stringstream sStream( myString );
int convertedInt;
sStream >> convertedInt.
Include the <sstream> header and you can do something like this:
std::vector<std::string> stringVector = /* get data from somewhere */
std::vector<int> intVector;
std::vector<char> charVector;
for (std::vector<std::string>::const_iterator it = stringVector.begin(); it != stringVector.end(); it++)
{
if (it->length() == 0)
continue; // ignore any empty strings
int intValue;
std::istingstream ss(*it);
if (ss >> someValue) // try to parse string as integer
intVector.push_back(someValue); // int parsed successfully
else
charVector.pushBack((*it)[0]);
}
This assumes anything that cannot be parsed as an integer should be pushed into the char vector instead (so, 234, 100000 and -34 will be put into intVector, and /, + etc will be put into charVector). Only the first character of a non-integer value is pushed, so if you have *hello or *123, only * will be put into the charVector.
If you are using C++11, you can swap the std::vector<std::string>::const_iterator with auto to make it look a bit nicer.
I'm writing a program in C++ to take input from a text file (dates and the high/low temp of that day), split the dates and temps into two separate arrays. I have the process down; however, I can't seem to split the strings appropriately. I've tried different methods with getline() and .get, but I need to keep the strings as STRINGS, not an array of chars. I've looked into and read the answers for similar questions using vectors and strtock and there's only one problem: I'm still fairly new, and the more I look into them, the more confused I get.
If I am to use that method in solving my problem, I just need to be pointed in the right direction of how to apply it. Apologies for my noobishness, it's just easy to get overwhelmed with all of the different ways to solve one problem with C++ (which is the reason I enjoy using it so much. ;))!
Sample from text:
10/12/2007 56 87
10/13/2007 66 77
10/14/2007 65 69
etc.
The dates need to be stored in one array, and the temps (both high and low) in another.
Here's what I have (unfinished, but for reference nonetheless)
int main()
//Open file to be read
ifstream textTemperatures;
textTemperatures.open("temps1.txt");
//Initialize arrays.
const int DAYS_ARRAY_SIZE = 32,
TEMPS_ARRAY_SIZE = 65;
string daysArray[DAYS_ARRAY_SIZE];
int tempsArray[TEMPS_ARRAY_SIZE];
int count = 0;
while(count < DAYS_ARRAY_SIZE && !textTemperatures.eof())
{
getline(textTemperatures, daysArray[count]);
cout << daysArray[count] << endl;
count++;
}
Thanks everyone.
Try the following
#include <iostream>
#include <fstream>
#include <sstream>
//...
std::ifstream textTemperatures( "temps1.txt" );
const int DAYS_ARRAY_SIZE = 32;
std::string daysArray[DAYS_ARRAY_SIZE] = {};
int tempsArray[2 * DAYS_ARRAY_SIZE] = {};
int count = 0;
std::string line;
while ( count < DAYS_ARRAY_SIZE && std::getline( textTemperatures, line ) )
{
std::istringstream is( line );
is >> daysArray[count];
is >> tempsArray[2 * count];
is >> tempsArray[2 * count + 1];
}
Here is a simple program that read the formatted input. You can easily replace std::cin with your std::ifstream and do whatever you want with the data inside the loop.
#include <iostream>
#include <string>
#include <vector>
int main ()
{
std::vector<std::string> dates;
std::vector<int> temperatures;
std::string date;
int low, high;
while ((std::cin >> date >> low >> high))
{
dates.push_back(date);
temperatures.push_back(low);
temperatures.push_back(high);
}
}
The magic here is done by std::cin's operator>> which reads up to the first whitespace encountered (tabulation, space or newline) and stores the value inside the right operand.
string *parse(string str,int from){
int i=0,n=0,j,k;
i=j=from;
string *data=new string[6];
while(str[i]){
if(str[i]==' '){
for(k=0;k<(i-j-1);k++){
data[n][k]=str[j+k]; << Error takes place here
}
data[n][k]='\0';
j=i;
n++;
}
i++;
}
return data;
}
Thanks for your help. I tried to debug but without success, what am I missing?
The problem is that elements data[i] of the data array all have the length of zero. That is why the assignment data[n][k] is always outside of data[n]'s range.
One way of fixing this would be using concatenation:
data[n] += str[j+k];
A better approach would be eliminating the loop altogether, and using substr member function of std::string instead: it lets you cut out a portion of str knowing the desired length and the starting position.
In addition, you are returning a pointer to a local array, which is undefined behavior. You should replace an array with a vector<string>, and add items to it using push_back.
Finally, you need to push the final word when the str does not end in a space.
Here is your modified program that uses the above suggestions:
vector<string> parse(string str,int from){
int i=from, j=from;
vector<string> data;
while(str[i]){
if(str[i]==' '){
data.push_back(str.substr(j, i-j+1));
j=i+1;
}
i++;
}
if (j != str.size()) {
data.push_back(str.substr(j));
}
return data;
}
Here is a demo on ideone.
data starts with 0 length, data[n][k] out of boundry. data[n][k]='\0' is not correct way of using C++ string and string * is considered of bad practice.
To separate a string by space, try:
#include <string>
#include <vector>
#include <sstream>
std::string data("hi hi hi hi hi");
std::stringstream ss(data);
std::string word;
std::vector<std::string> v;
while(std::getline(ss, word, ' '))
{
v.push_back(word);
}
This is a basic c++ console application that I am working on, just to test things out before o do something a little bit more advanced. I would like to know how I would find out if the user input is part of my String array with an if statement here is the code so far...
#include <iostream>
#include <string>
using namespace std;
int main(){
string array[] = {"1","2","3"};
for(;;){
cout << "Enter a random number";
int randNum = 0;
cin >> randNum;
if(/* randNum is part of the array */)
{
//do something
}
else{
//do something
}
}
return 0;
}
First off, you clearly want to check your input after reading:
if (cin >> randNum) {
...
}
Next, I think you would want to align the types, i.e., if you read an int you probably want to have your array also to contain ints:
int array[] = { 1, 2, 3 };
If these are given you can just check like so:
if (std::end(array) != std::find(std::begin(array), std::end(array), randNum)){
...
}
(if you don't use C++ 2011, you need some other way to get the begin and end iterator your array but there are plenty ways, including defining templates begin() and end() as needed).
If you really want to check the int against an array of std::strings, you'd need a predicate which checks the int against a std::string.
You can utilize std::find for this, however, you'll need to convert randNum to a string first -
std::stringstream ss;
ss << randNum;
std::string to_check = ss.str();
if(std::find(array, array + 3, to_check) != (array + 3)) {
//Logic
} else {
//
}