splitting a string of integers...

Pages: 12
Hi guys, I am having trouble with a specific problem. Is there a way to split a string of integers? For example, I want the user to input a big number, such as 32101234567890987654, and then have the program split the string into a string of 8 integers starting from the end of the string. "32101234567890987654" would be stored as x1=90987654, x2=12345678, x3=3210... I'm thinking that vectors need to be used, but not entirely sure about that..Anyone have any idea?
Vectors need not be used, although they sure can be.

1
2
std::string pirategoarr* = new std::string[stringname.size() / 8 + 1]; //For storing the string fragments.
//A similar array could be used for storing the integers. 


-Albatross
Thanks Albatross, but can you explain why you would divide the size by 8+1 instead of just 8? I'm having a hard time understanding..
1
2
3
4
5
6
7
8
9
10
11
  string test = "32101234567890987654";
  int noBlock = test.length()/8;
  int remainBlock = test.length()%8;
  int len = test.length()-8;
  for(int i=0; i<noBlock; i++) {
    cout << test.substr(len,8) << "\n";
    len -= 8;
  }
  if (remainBlock) {
    cout << test.substr(0, remainBlock) << "\n";
  }
Last edited on
Oh, I think I understand now. It's for the remainder, right?
Thanks sohguanh...This seem to work also, but how can I make it store the strings into variables x1, x2, x3, etc. in the for() and if() loops? In the for() loop, I'm not able to store it into xi(says xi is not declared, although that is what I would want it to do. Sorry, I am still a beginner with only one month of C++ experience. I am learning as much as I can though.
You'd need a type conversion from a string to an integer (atoi is a possible one; remember to use std::string::c_str()). After that, I recommend a dynamically allocated array.

-Albatross
Since the number of variables is dynamic depending on input string length, I opt to store them into a vector.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  string test = "32101234567890987654";
  int noBlock = test.length()/8;
  int remainBlock = test.length()%8;
  vector<string> vecStr;
  int len = test.length()-8;
  for(int i=0; i<noBlock; i++) {
    cout << test.substr(len,8) << "\n";
    vecStr.push_back(test.substr(len,8));
    len -= 8;
  }
  if (remainBlock) {
    cout << test.substr(0, remainBlock) << "\n";
    vecStr.push_back(test.substr(len,8));
  }
  copy(vecStr.begin(),vecStr.end(),ostream_iterator<string>(cout,"\n"));
There's no need for a vector, is there? It's not like your array will have to be changing length and you can determine its final size before you even reserve memory for it (see above).
Use: int* arr = new int[count];

And, sohguanh, you're coming very close to giving a full solution. Please do not.

-Albatross
Last edited on
Ok got it. Actually I don't need new int[count] since I compute earlier I can just do a

 
string vecStr2[noBlock+1];
That's... either deprecated or illegal, I forget which. Lots of compilers seem to support it, but I think that syntax for declaring an array was supposed to require a constant.

-Albatross
Ok using your advice I change to dynamic. Now it seems strange lots of compiler support declaration of an array with variable in the square bracket.

1
2
3
string *vecStr2 = new string[noBlock+1];
...
copy(vecStr2,vecStr2+noBlock+1,ostream_iterator<string>(cout,"\n"));
Thank you both for the help, I will study these topics a bit and let you know how it goes. This is actually part of a larger program, in which I need to convert a string of integers into a coefficient vector, then be able to add two inputted numbers, and then convert the solution back to a string. Although sohguanh has shown me a few topics which I need to touch upon to get started with this program, he has not really given me a full solution, so no worries. Once again, thank you for the help. I will update if I have any more trouble with this.
Since it is part of a large program, I list down two methods vector and dynamic array for your research purposes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  string test = "32101234567890987654";
  int noBlock = test.length()/8;
  int remainBlock = test.length()%8;
  vector<string> vecStr;
  string *vecStr2 = new string[noBlock+1];
  int len = test.length()-8;
  for(int i=0; i<noBlock; i++) {
    cout << test.substr(len,8) << "\n";
    vecStr.push_back(test.substr(len,8));
    vecStr2[i] = test.substr(len,8);
    len -= 8;
  }
  if (remainBlock) {
    cout << test.substr(0, remainBlock) << "\n";
    vecStr.push_back(test.substr(len,8));
    noBlock==0 ? vecStr2[0] = test.substr(0, remainBlock) : vecStr2[noBlock] = test.substr(0, remainBlock);
  }
  copy(vecStr.begin(),vecStr.end(),ostream_iterator<string>(cout,"\n"));
  copy(vecStr2,vecStr2+noBlock+1,ostream_iterator<string>(cout,"\n"));
  delete [] vecStr2;
Ok, I've reseached quite a bit and have come up with a solution. The only problem is that it does not work as intended. I have a header file, an implementation file, and a test file. I want the program to ask the user to input a big natural number. Then I want to convert the string into an integer and store it a vector. I want to store it in a vector in blocks of 8 integers starting from the end of the string. Example: if s = "12345678910987654321", then vec[0]=87654321, vec[1]=56789109, and vec[2]=1234. Here is what I have so far:

big_nat.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef big_nat_h
#define big_nat_h
#include <iostream>
#include <string>
#include <vector>

class Big_Nat {
private:
	int sub_strings;
	int rem_sub_strings;
	int len;
	int num_strings;
	int current_coefficient;
	std::string current_substring;

public:
	Big_Nat(std::string);
	std::string to_string();
};
#endif 


big_nat.cpp
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
31
32
33
34
35
#include <iostream>
#include "big_nat.h"
#include <string>

Big_Nat::Big_Nat(std::string s)
{
	sub_strings = s.length()/8;
	rem_sub_strings = s.length()%8;
	num_strings = sub_strings + rem_sub_strings;
	std::vector<int> vec;
	len = s.length()-8;
	for(int i=0; i<sub_strings; i++)
	{
		current_substring = s.substr(len, 8);
		current_coefficient = atoi(current_substring.c_str());
		vec.push_back(current_coefficient);
		len-=8;
	}
	if(rem_sub_strings)
	{
		current_substring = s.substr(len, 8);
		current_coefficient = atoi(current_substring.c_str());
		vec.push_back(current_coefficient);
	}
	
/*the next for() loop is just a test to see what was stored in the vector*/
	for(int j=0;j<num_strings;j++)
	{
		std::cout<<vec[j]<<std::endl;
	}
};
std::string Big_Nat::to_string()
{
	return vec;	
};


Big_Nat_test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "big_nat.h"
#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s;
	cout << "Give x : "; getline(cin,s,'\n');
	Big_Nat x(s);
	cout << "---> x : " << x.to_string() << endl;
	cout << "Give y : "; getline(cin,s,'\n');
	Big_Nat y(s);
	cout << "---> y : " << y.to_string() << endl;

	return 0;
}


I get an error saying that vec isn't declared in big_nat.cpp. Also, if I change the to_string() to return something I know will work, the program compiles, but crashes if I input any number with more than 8 integers... This program is making me go crazy! Someone help please! =)
It almost hurts watching the struggle here!
Perhaps a different approach would be easier for khris to work with.

The following is not a full solution for at least 2 reasons:

1) The calls to test.copy() generate warnings about the use of "unsafe" parameters. The program works anyways though (for the couple of test runs I gave it) because the parameter values are correct. Looks like I need to learn about "iterators".

2) The 8 digit #'s generated are not being saved, they are found one-by-one then overwritten with the next value. You would need to create an array of integers of the right size to store them in (or use a vector ).

Hope this helps:
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
31
32
33
34
35
36
37
38
39
40
41

#include <iostream>
#include <string>
using namespace std;

int main()
{
	string test;// = "32101234567890987654";// 20 chars
	cout << "Enter a big number: ";
	cin >> test;
	cout << test << endl;

	int len = test.length();
	cout << "len = " << len << endl;

	int lastLen = len%8;
	cout << "lastLen = " << lastLen << endl;

	int Nsubs = len/8;
	cout << "Nsubs = " << Nsubs << endl;

	char sub_str[9];
	int n = 0;
	for(int j=1; j<= Nsubs; j++)// all of the full 8 char cases
	{
		test.copy( sub_str, 8, len - 8*j );// last arg reveals reason for indexing from 1 not 0
		n = atoi( sub_str );
		cout << n << endl;
	}

	if( lastLen )// the last < 8 digit case
	{
		test.copy( sub_str, lastLen, 0 );// this generates a warning about unsafe parameters
		sub_str[lastLen] = '\0';// it works because the correct values are being used
		n = atoi( sub_str );
		cout << n << endl;
	}

	system("PAUSE");	
	return 0;
}// end of main() 
Last edited on
fun2code, thanks for this. This makes much more sense to me and I was able to compile it without any errors. I am having one problem though..I was able to store the integers in a vector, but I want to be able to pop it back out and convert it to a string for outputting to the screen. I think I am doing it correctly, but the compiler doesn't think so. Can you or anyone look through the to_string() fuction I have in big_nat.cpp and let me know where I went wrong?

big_nat.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef big_nat_h
#define big_nat_h
#include <iostream>
#include <string>
#include <vector>

class Big_Nat {
private:
	int num_strings;
	std::vector<int> vec;

public:
	Big_Nat(std::string);
	std::string to_string();
};
#endif 

big_nat.cpp
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "big_nat.h"
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>

Big_Nat::Big_Nat(std::string s)
{
	int current_coefficient;
	int sub_strings;
	int rem_sub_strings;
	int len;
	char holder[9];

	sub_strings = s.length()/8;
	rem_sub_strings = s.length()%8;
	len = s.length();

	for(int i=1; i<=sub_strings; i++)
	{
		s.copy(holder,8, len-8*i);
		current_coefficient = atoi(holder);
		vec.push_back(current_coefficient);
	}

	if(rem_sub_strings)
	{
		s.copy(holder,rem_sub_strings,0);
		holder[rem_sub_strings]='\0';
		current_coefficient = atoi(holder);
		vec.push_back(current_coefficient);
		num_strings=sub_strings+1;
	}
	
};

std::string Big_Nat::to_string()
{
	std::stringstream ss;
	for(int j=0;j<num_strings;j++)
	{
		std::string vec_string = vec.pop_back();
		ss << vec_string;
		return ss.str();	
	}
};

Big_Nat_test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "big_nat.h"
#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s;
	cout << "Give x : "; getline(cin,s,'\n');
	Big_Nat x(s);
	cout << "---> x : " << x.to_string() << endl;
	cout << "Give y : "; getline(cin,s,'\n');
	Big_Nat y(s);
	cout << "---> y : " << y.to_string() << endl;

	return 0;
}
Ok, I found one mistake...std:string vec_string should have been int vec_string...but I am still getting an error, "void value not ignored as it ought to be".

1
2
3
4
5
6
7
8
9
10
std::string Big_Nat::to_string()
{
	std::stringstream ss;
	for(int j=0;j<num_strings;j++)
	{
		int vec_string = vec.pop_back();
		ss << vec_string;
		return ss.str();	
	}
};
I found another mistake. I should be using vec.back(), before the pop_back()...The problem is that it only outputs vec[0] instead of the whole string...Anyone know how to go about storing each vector element into separate variables and then concatenating them? Or is there a more efficient way to do this?
You're welcome. I'm glad my code was helpful.
I'm not sure I see what you are trying to do. I can't troubleshoot your to_string() function because I am not familiar with the methods used there. I would be using a dynamic array instead of a vector (as suggested by Albatross in an earlier post this thread).

I see this clue though:
The problem is that it only outputs vec[0] instead of the whole string..


What whole string? The one entered by the user? This was stored in the string 'test' and ought to be intact, so cout << test << endl; should still display it. But this is too simple, I must have the task wrong. Please clarify the nature of the remaining task.
Last edited on
Pages: 12