Converting string into int array - c++

I have a following problem. I want to convert a string like "10 15 30" to an int array with ints 10, 15, 30. I searched in google a lot, but usually solutions included vectors (which I am not familiar with) or other more complex solutions. I found a code like this:
#include <cstdio>
void foo ( char *line ) {
int num, i = 0, len;
while ( sscanf( line, "%d%n", &num, &len) == 1 ) {
printf( "Number %d is %d; ", i, num );
line += len;
i++;
}
}
int main ( ) {
char test[] = "12 45 6 23 100";
foo( test );
return 0;
}
It works and extracts numbers from string in a way I wanted, but I don't understand part with:
line += len;
Can someone explain how it works? Why are we adding len (which is int) to the string?

Solution for C++:
#include <iostream>
#include <sstream>
#include <vector>
std::vector< int > foo ( char *c_str ) {
std::istringstream line( c_str );
std::vector< int > numbers;
for ( int n; line >> n; )
numbers.push_back( n );
return numbers;
}
int main ( ) {
char test[] = "12 45 6 23 100";
std::vector< int > numbers = foo( test );
for ( int n : numbers )
std::cout << n << ' ';
return 0;
}
Output:
12 45 6 23 100

%n specifies the number of characters accessed by sscanf in its one execution and saved it in variable len.
so line + =len; is incrementing variable line, with number of characters accessed by sscanf
line + =len; is nothing but line =line+ len;

line += len; is equivalent to line = line + len;
line is a char pointer, thus the code increases the pointer by len, so that the pointer points to the next number, every time the loop is executed. Note than len is updated by the call to sscanf().

The "string" is a pointer to a character buffer. You are performing pointer arithmetic to increment the sscanf to parse the next int characters from the buffer. So, in your example:
char test[] = "12 45 6 23 100";
say *line points to test, and has some pointer value, we don't care what the value is per-se, so let's say it is 1000. After the 1st call to sscanf, you read "12" in. That is two characters, so len should return 2. line then gets set to 1002, and is now "pointing" to the next set of characters in the buffer. sscanf reads that, and this continues until no more characters in the buffer.

Look at sscanf docs. It receive format and additional params.
In params you have "%d%n" which you explain using format table from docs.
d or u
Decimal integer
Any number of decimal digits (0-9), optionally preceded by a sign (+ or -). d is for a signed argument, and u for an unsigned.
n
Count
No input is consumed.
The number of characters read so far from stdin is stored in the pointed location.
So you read integer from string and number of chars this integer consist from.
After reading part of string you move pointer into number of read chars.

sscanf( line, "%d%n", &num, &len)
This line reads a number from line, and put the digit into num and number of characters read into len.
We need len to move pointer to unread portion of the string.
Does it make sense ?
Useful links:
scanf
sscanf

Related

Parsing string to get comma-separated integer character pairs

I'm working on a project where I'm given a file that begins with a header in this format: a1,b3,t11, 2,,5,\3,*4,344,00,. It is always going be a sequence of a single ASCII character followed by an integer separated by a comma with the sequence always ending with 00,.
Basically what I have to do is go through this and put each character/integer pair into a data type I have that takes both of these as parameters and make a vector of these. For example, the header I gave above would be a vector with ('a',1), ('b',3),('t',11),(',',5)(' ',2),('\',3),('*',4),('3',44) as elements.
I'm just having trouble parsing it. So far I've:
Extracted the header from my text file from the first character up until before the ',00,' where the header ends. I can get the header string in string format or as a vector of characters (whichever is easier to parse)
Tried using sscanf to parse the next character and the next int then adding those into my vector before using substrings to remove the part of the string I've already analyzed (this was messy and did not get me the right result)
Tried going through the string as a vector and checking each element to see if it is an integer, a character, or a comma and acting accordingly but this doesn't work for multiple-digit integers or when the character itself is an int
I know I can fairly easily split my string based on the commas but I'm not sure how to do this and still split the integers from the characters while retaining both and accounting for integers that I need to treat as characters.
Any advice or useful standard library or string functions would be greatly appreciated.
One possibility, of many, would be to store the data in a structure. This uses an array of structures but the structure could be allocated as needed with malloc and realloc.
Parsing the string can be accomplished using pointers and strtol which will parse the integer and give a pointer to the character following the integer. That pointer can be advanced to use in the next iteration to get the ASCII character and integer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 100
struct pair {
char ascii;
int integer;
};
int main( void) {
char input[] = "a1,b3,!0,t11, 2,,5,\\3,*4,34400,";
char *pt = input;//start with pt pointing to first character of input
char *end = input;
int each = 0;
int loop = 0;
int length = 0;
struct pair pairs[SIZE] = { { '\0', 0}};
//assuming input will always end in 00, ( or ,00,)
//remove those three ( or 4 ??) characters
length = strlen ( input);
if ( length > 3) {
input[length - 3] = '\0';
}
for ( each = 0; each < SIZE; each++) {
//get the ASCII character and advance one character
pairs[each].ascii = *pt;
pt++;
//get the integer
pairs[each].integer = strtol ( pt, &end, 10);
//end==pt indicates the expected integer is missing
if ( end == pt) {
printf ( "expected an integer\n");
break;
}
//at the end of the string?
if ( *end == '\0') {
//if there are elements remaining, add one to each as one more was used
if ( each < SIZE - 1) {
each++;
}
break;
}
//the character following the integer should be a comma
if ( *end != ',') {
//if there are elements remaining, add one to each as one more was used
if ( each < SIZE - 1) {
each++;
}
printf ( "format problem\n");
break;
}
//for the next iteration, advance pt by one character past end
pt = end + 1;
}
//loop through and print the used structures
for ( loop = 0; loop < each; loop++) {
printf ( "ascii[%d] = %c ", loop, pairs[loop].ascii);
printf ( "integer[%d] = %d\n", loop, pairs[loop].integer);
}
return 0;
}
Another option is to use dynamic allocation.
This also uses sscanf to parse the input. The %n will capture the number of characters processed by the scan. The offset and add variables can then be used to iterate through the input. The last scan will only capture the ascii character and the integer and the return from sscanf will be 2.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct pair {
char ascii;
int integer;
};
int main( void) {
char input[] = "a1,b3,!0,t11, 2,,5,\\3,*4,34400,";
char comma = '\0';
char ascii = '\0';
int integer = 0;
int result = 0;
int loop = 0;
int length = 0;
int used = 0;
int add = 0;
int offset = 0;
struct pair *pairs = NULL;//so realloc will work on first call
struct pair *temp = NULL;
//assuming input will always end in 00, ( or ,00,)
//remove those three ( or 4 ??) characters
length = strlen ( input);
if ( length > 3) {
input[length - 3] = '\0';
}
while ( ( result = sscanf ( &input[offset], "%c%d%c%n"
, &ascii, &integer, &comma, &add)) >= 2) {//the last scan will only get two items
if ( ( temp = realloc ( pairs, ( used + 1) * sizeof ( *pairs))) == NULL) {
fprintf ( stderr, "problem allocating\n");
break;
}
pairs = temp;
pairs[used].ascii = ascii;
pairs[used].integer = integer;
//one more element was used
used++;
//the character following the integer should be a comma
if ( result == 3 && comma != ',') {
printf ( "format problem\n");
break;
}
//for the next iteration, add to offset
offset += add;
}
for ( loop = 0; loop < used; loop++) {
printf ( "ascii[%d] = %c ", loop, pairs[loop].ascii);
printf ( "value[%d] = %d\n", loop, pairs[loop].integer);
}
free ( pairs);
return 0;
}
Since you have figured out that you can just ignore the last 3 characters, using sscanf will be sufficient.
You can use sscanf to read one character (or getch functions), use sscanf to read an integer and finally even ignore one character.
Comment if you are having problems understanding how to do so.

How to parse out integers from a line with characters and integers

For a C/C++ assignment, I need to take an input line, starting with the character 's', followed by UP TO 3 separate integers. My issue is that, without vectors, I don't know how to account for an unknown number of integers (1-20).
For example, a test input would look like:
s 1 12 20
It was suggested to me to use cin.getline and take the whole line as a string, but how would I know where each integer would lie in a character array because of the possibility of single or double digits, let alone the number of integers in said string?
Construct a std::istringstream from the contents of the line, then keep using operator>> into an int, until it fail()s, stuffing each integer into a std::vector (after using the operator>> initially, once, to take care of the leading character).
You can mimic vectors using dynamic memory allocation. Initially create an array of size 2, using int *a = new int[2];
When this array fills up, make a new array of double the size, copy the old array in the new one and reassign a to the new array. Keep doing this until you have met the requirement.
EDIT
So getting the numbers through the string stream, if the array fills up, you could do:
int changeArr(int *a, int size){
int *b = new int[size*2];
for(int i=0;i<size;i++){
b[i] = a[i];
}
a = b;
return size*2;
}
int getNos(istringstream ss){
int *a = new int[2];
int cap = 2, i=0, number;
while(ss){
if(i>=cap){
cap = changeArr(a, cap);
}
ss >> a[i];
i++;
}
}
I have skipped the part about the first character, but I guess you can handle that.
Without vectors, you have a couple of approaches. (1) read an entire line at a time and tokenize the line with strtok or strsep, or (2) use the standard features built into strtol to walk down the string separating values with the pointer and end-pointer parameters to the function.
Since you know the format, you can easily use either. Both 1 & 2 above do the same thing, you are just using the tools in strtol to both tokenize and convert to a number in a single step. Here is a short example for handling a string followed by an unknown number of digits on each line:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
enum { BASE = 10, MAXC = 512 };
long xstrtol (char *p, char **ep, int base);
int main (void) {
char buf[MAXC] = "";
while (fgets (buf, MAXC, stdin)) { /* for each line of input */
char *p, *ep; /* declare pointers */
p = buf; /* reset values */
errno = 0;
printf ("\n%s\n", p); /* print the original full buffer */
/* locate 1st digit in string */
for (; *p && (*p < '0' || '9' < *p); p++) {}
if (!*p) { /* validate digit found */
fprintf (stderr, "warning: no digits in '%s'\n", buf);
continue;
}
/* separate integer values */
while (errno == 0)
{ int idx = 0;
long val;
/* parse/convert each number in line into long value */
val = xstrtol (p, &ep, BASE);
if (val < INT_MIN || INT_MAX < val) { /* validate int value */
fprintf (stderr, "warning: value exceeds range of integer.\n");
continue;
}
printf (" int[%2d]: %d\n", idx++, (int) val); /* output int */
/* skip delimiters/move pointer to next digit */
while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
if (*ep)
p = ep;
else
break;
}
}
return 0;
}
/** a simple strtol implementation with error checking.
* any failed conversion will cause program exit. Adjust
* response to failed conversion as required.
*/
long xstrtol (char *p, char **ep, int base)
{
errno = 0;
long val = strtol (p, ep, base);
/* Check for various possible errors */
if ((errno == ERANGE && (val == LONG_MIN || val == LONG_MAX)) ||
(errno != 0 && val == 0)) {
perror ("strtol");
exit (EXIT_FAILURE);
}
if (*ep == p) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
return val;
}
(the xstrtol function just moves the normal error checking to a function to unclutter the main body of the code)
Example Input
$ cat dat/varyint.txt
some string 1, 2, 3
another 4 5
one more string 6 7 8 9
finally 10
Example Use/Output
$ ./bin/strtolex <dat/varyint.txt
some string 1, 2, 3
int[ 0]: 1
int[ 1]: 2
int[ 2]: 3
another 4 5
int[ 0]: 4
int[ 1]: 5
one more string 6 7 8 9
int[ 0]: 6
int[ 1]: 7
int[ 2]: 8
int[ 3]: 9
finally 10
int[ 0]: 10
You can provide a bit of tidying up, but this method can be used to parse an unknown number of values reliably. Look it over and let me know if you have any questions.
Since vectors aren't allowed, you'll need to find out how many numbers are in the line before you can make an array to hold them.
I won't just give you the entire code, since this is homework, but I'll show you what I would do to solve your problem.
If your lines will always look like this: "s number" or "s number number" or "s number number number", then you can easily find the number of numbers in the line by counting the spaces!
There will be one space in any string with one number (between the s and that number), and one more space for each number that follows the first.
So let's count the spaces!
int countSpaces(string s) {
int count = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] == ' ') {
count++;
}
}
return count;
}
Passing these strings:
string test1 = "s 123 4 99999";
string test2 = "s 1";
string test3 = "s 555 1337";
to the countSpaces function will give us:
3
1
2
And with that information, we can make an array with the correct size to hold each value!
EDIT
Now I realize that you're having trouble grabbing the numbers from the string.
What I would do, is use the above method to find the number of numbers in the line. Then, I would use the std::string.find() function to determine where, and if, any spaces are in the string.
So let's say we had the line: s 123 45 678
countSpaces would tell us we have 3 numbers.
Then we make an array to hold our three numbers. I would also cut off the s part so you don't have to worry about it anymore. Note that you can use std::stoi to turn a string into a number!
Now we can loop while find(' ') doesn't return -1.
In our loop, I would take the substring from 0 to the first space, like so:
num = std::stoi( myLine.substr(0, myLine.find(' ') )
Then you can cut off the part you just used:
myLine = myLine.substr( myLine.find(' ') );
This will grab a number off the front of your string, then chop off that number from the string, and repeat the process while there is still a space in the string.
EDIT:
If you aren't guaranteed to have one space between each number, then you can delete excess spaces before doing this method or you can do it during the countSpaces loop. At that point, it would make more sense to call the function countNums or such.
An example function to remove stretches of spaces and replace them with one space:
void removeExtraSpaces(string s) {
bool inSpaces = (s[0] == ' ');
for (int i = 1; i < s.size(); i++) {
if (s[i] == ' ') {
if(inSpaces) {
s.erase(i);
} else {
inSpaces = true;
}
} else if(inSpaces) {
inSpaces = false;
}
}
}

Selecting only the first few characters in a string C++

I want to select the first 8 characters of a string using C++. Right now I create a temporary string which is 8 characters long, and fill it with the first 8 characters of another string.
However, if the other string is not 8 characters long, I am left with unwanted whitespace.
string message = " ";
const char * word = holder.c_str();
for(int i = 0; i<message.length(); i++)
message[i] = word[i];
If word is "123456789abc", this code works correctly and message contains "12345678".
However, if word is shorter, something like "1234", message ends up being "1234 "
How can I select either the first eight characters of a string, or the entire string if it is shorter than 8 characters?
Just use std::string::substr:
std::string str = "123456789abc";
std::string first_eight = str.substr(0, 8);
Just call resize on the string.
If I have understood correctly you then just write
std::string message = holder.substr( 0, 8 );
Jf you need to grab characters from a character array then you can write for example
const char *s = "Some string";
std::string message( s, std::min<size_t>( 8, std::strlen( s ) );
Or you could use this:
#include <climits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
If the max is 8 it'll stop there. But you would have to set
const char * word = holder.c_str();
to 8. I believe that you could do that by writing
const int SIZE = 9;
char * word = holder.c_str();
Let me know if this works.
If they hit space at any point it would only read up to the space.
char* messageBefore = "12345678asdfg"
int length = strlen(messageBefore);
char* messageAfter = new char[length];
for(int index = 0; index < length; index++)
{
char beforeLetter = messageBefore[index];
// 48 is the char code for 0 and
if(beforeLetter >= 48 && beforeLetter <= 57)
{
messageAfter[index] = beforeLetter;
}
else
{
messageAfter[index] = ' ';
}
}
This will create a character array of the proper size and transfer over every numeric character (0-9) and replace non-numerics with spaces. This sounds like what you're looking for.
Given what other people have interpreted based on your question, you can easily modify the above approach to give you a resulting string that only contains the numeric portion.
Something like:
int length = strlen(messageBefore);
int numericLength = 0;
while(numericLength < length &&
messageBefore[numericLength] >= 48 &&
messageBefore[numericLength] <= 57)
{
numericLength++;
}
Then use numericLength in the previous logic in place of length and you'll get the first bunch of numeric characters.
Hope this helps!

Compare many char variables in C++

I'm a beginner programmer and i'm confised. How can i compare many char variables?
So, i have in .in file smt like that:
n (an unsigned variable, like 7, how many char are down)
A B C C B D B
in .out file i must have which characters are repeated and how often repeat:
B 3
C 2
how can i do this? please help me. i think i can use a for and vectors... but how?
i tried somthing, but i don't know how to continue :( (litera mean character)
unsigned n,i;
char litera;
f>>n;
for (i=1;i<=n;i++)
f>>litera;
return 0;
use a counting array:
int array[256] = {};
unsigned int n,i;
char tmp;
f>>n;
for (i=1;i<=n;i++)
f>>tmp;
array[tmp] ++;
after that you can just print into the file all the values in the array that are not zero.
Simpler way is to use a std::map< char, int> that would store the count of each character.
unsigned n,i;
f>>n;
char ch;
std::map< char, int > myMap;
for (i=1;i<=n;i++) {
f>>ch;
if ( myMap[ch] )
myMap[ch]++;
else
myMap[ch] = 1;
}
Otherwise Use a vector of char.
unsigned n,i;
f>>n;
vector<char> litera( n );
for (i=1;i<=n;i++)
f>>litera[i];
For counting the number of repititions, there are many ways.
You can first sort the vector and iterate through the elements.
std::sort( litera.begin(), litera.end() );
int count = 1;
for ( int i = 0; i < litera.size(); i++ ) {
if ( litera[i] == litera[i+1] )
count++;
else if ( count > 1 ) {
std::cout << litera[i] << count << std:endl;
count = 0;
}
}
As number of possible chars is very limitted (256), you can define an array in size 255 which will represent how many instances of each chars exist.
Start by zeroing such an array. Then iterate your input characters and increment each cell you see. Finally print all non-zero element to output file.
I will not write the whole stuff for I guess you need/want to learn C++ and the best to do it is do stuff on your own. Here is idea, though.
Assuming you are reading ASCII characters only (as you are using char) I would declare a static array:
int counts[256] ;
and then filled it out initially with zeroes
You can use memset or a for loop to do that.
Next, when you read characters you increase specific cell of the counts array like that:
counts[litera]++ ;
At the end, when you are done reading, loop through the array and print out letter and corresponding number from the counts array:
for ( int i = 0 ; i < 256 ; i++ )
if ( counts[ i ] != 0 )
std::cout << static_cast< char >( i ) << " " << counts[ i ] << "\n" ;
I hope it will help.

Convert integer to array

I would like to convert an integer into an array, so that it looks like the following:
int number = 123456 ;
int array[7] ;
with the result:
array[0] = 1
array[1] = 2
...
array[6] = 6
Perhaps a better solution is to work backwards:
123456 % 10 = 6
123456 / 10 = 12345
12345 % 10 = 5
12345 / 10 = 1234
just use modular arithmetic:
int array[6];
int number = 123456;
for (int i = 5; i >= 0; i--) {
array[i] = number % 10;
number /= 10;
}
You can extract the last digit of the number this way:
int digit = number % 10;
number /= 10;
Note that you should also check whether number is positive. Other values require additional handling.
Here what I came up with, the integerToArray function returns a vector that is converted from the integer value. you can test it with the main function as well:
#include <iostream>
#include <vector>
using namespace std;
vector <int> integerToArray(int x)
{
vector <int> resultArray;
while (true)
{
resultArray.insert(resultArray.begin(), x%10);
x /= 10;
if(x == 0)
return resultArray;
}
}
int main()
{
vector <int> temp = integerToArray(1234567);
for (auto const &element : temp)
cout << element << " " ;
return 0;
}
//outputs 1 2 3 4 5 6 7
Take the log10 of the number to get the number of digits. Put that in, say pos, then, in a loop, take the modulo of 10 (n % 10), put the result in the array at position pos. Decrement pos and divide the number by 10. Repeat until pos == 0
What did you want to do with the sign if it's negative?
#include <cmath>
#include <vector>
std::vector<int> vec;
for (int i = log10(input); i >= 0; i--)
{
vec.push_back(input / int(std::pow(10, i)) % 10);
}
Might be a good approach, I think
The easiest way I can imagine now is:
char array[40];
int number = 123456;
memset(array, 0x00, sizeof(array));
sprintf(array, "%d", number);
Additionally you can convert each digit to int just subtracting the char value by 0x30.
EDIT: If this is a homework, your teacher you probably ask you to write the program using % operator though (example 12 % 10 = 2). If this is the case, good homework ;-)
You can use modulus to determine the last digit.
And you can use division to move another digit to the last digit's place.
You can't simply "convert" it. The integer is not represented in software in decimal notation. So the individual digits you want don't exist. They have to be computed.
So, given an arbitrary number, how can you determine the number of ones?
We could divide by ten, and then take the remainder: For 123, the division would give 12, and then there's a remainder of 3. So we have 3 ones. The 12 tells us what we have past the ones, so it can be our input for the next iteration. We take that, divide by 10, and get 1, and a remainder of 2. So we have 2 in the tens place, and 1 left to work with for the hundreds. Divide that by 10, which gives us zero, and a remainder of 1. So we get 1 in the hundreds place, 2 in the tens place, and 3 in the ones place. And we're done, as the last division returned zero.
See SO question Language showdown: Convert string of digits to array of integers? for a C/C++ version (as well as other languages).
if this is really homework then show it your teacher - just for fun ;-)
CAUTION! very poor performance, clumsy way to reach the effect you expect and generally don't do this at home(work) ;-)
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
typedef std::vector< int > ints_t;
struct digit2int
{
int operator()( const char chr ) const
{
const int result = chr - '0';
return result;
}
};
void foo( const int number, ints_t* result )
{
std::ostringstream os;
os << number;
const std::string& numberStr = os.str();
std::transform(
numberStr.begin(),
numberStr.end(),
std::back_inserter( *result ),
digit2int() );
}
int main()
{
ints_t array;
foo( 123456, &array );
std::copy(
array.begin(),
array.end(),
std::ostream_iterator< int >( std::cout, "\n" ) );
}
If you wanted to turn it into a string then it would be really easy, just do what everyone else is saying about using the % operator:
Let's say num = 123, we can do this:
string str;
while (num > 0)
{
str = (num % 10) + str; //put last digit and put it into the beginning of the string
num = num /10; //strip out the last digit
}
Now you can use str as an array of chars. Doing this with an array is a hassle because putting things in the beginning of an array requires you to shift everything else. What we can do is, instead of putting each digit into a string, we can put it into a stack. It will put it in a backwards order like this: 3 2 1. Then we can pop off the top number one by one and put that into an array in the correct order. You array will look like this: 1 2 3. I will leave the implementation to you since this is homework.
#Broam has a good solution, but like he stated, it's for working backwards. I think the OP or whoever comes looking into this thread will want it forwards and that's why I'm posting this. If you have a better solution, please reply, I'm interested as well.
To convert an integer to array, you can do the steps below:
Get the total number of digits in a number to which we want to convert to
array.For this purpose, we will use count_digits() function which will return total no of digits after ignoring leading zeros.
digits = count_digits(n);
Now we will dynamically allocate memory for our resulting array, just like
int* arr = new int[count_digits(n)]
After allocating memory, we will populate the array using the for loop below
int digits = count_digits(num);
for (int i = digits; i > 0; i--){
arr[i-1] = num % 10;
num = num / 10;
}
After performing the steps above, we will be able to convert an integer to array. Remember, num is the number that we want to convert into array and digits is the variable which gives us the number of digits in a given number ignoring leading zeros.