6

I'm writing a program that prompts the user for:

  1. Size of array
  2. Values to be put into the array

First part is fine, I create a dynamically allocated array (required) and make it the size the user wants.

I'm stuck on the next part. The user is expected to enter in a series of ints separated by commas such as: 1,2,3,4,5

How do I take in those ints and put them into my dynamically allocated array? I read that by default cin takes in integers separated by whitespace, can I change this to commas?

Please explain in the simplest manner possible, I am a beginner to programming (sorry!)

EDIT: TY so much for all the answers. Problem is we haven't covered vectors...is there a method only using the dynamically allocated array I have?

so far my function looks like this. I made a default array in main. I plan to pass it to this function, make the new array, fill it, and update the pointer to point to the new array.

int *fill (int *&array, int *limit) {

cout << "What is the desired array size?: ";                                  
while ( !(cin >> *limit) || *limit < 0 ) {
    cout << "  Invalid entry. Please enter a positive integer: ";
    cin.clear();
    cin.ignore (1000, 10);
}

int *newarr;                                                                            
newarr = new int[*limit]
    //I'm stuck here
}
Ian004
  • 195
  • 2
  • 3
  • 11

9 Answers9

5

All of the existing answers are excellent, but all are specific to your particular task. Ergo, I wrote a general touch of code that allows input of comma separated values in a standard way:

template<class T, char sep=','>
struct comma_sep { //type used for temporary input
    T t; //where data is temporarily read to
    operator const T&() const {return t;} //acts like an int in most cases
};
template<class T, char sep>
std::istream& operator>>(std::istream& in, comma_sep<T,sep>& t) 
{
    if (!(in >> t.t)) //if we failed to read the int
        return in; //return failure state
    if (in.peek()==sep) //if next character is a comma
        in.ignore(); //extract it from the stream and we're done
    else //if the next character is anything else
        in.clear(); //clear the EOF state, read was successful
    return in; //return 
}

Sample usage http://coliru.stacked-crooked.com/a/a345232cd5381bd2:

typedef std::istream_iterator<comma_sep<int>> istrit; //iterators from the stream
std::vector<int> vec{istrit(in), istrit()}; //construct the vector from two iterators

Since you're a beginner, this code might be too much for you now, but I figured I'd post this for completeness.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • Hmm, there is an odd quirk that this will _also_ parse space separated input. I don't know if I want to disallow that or not. – Mooing Duck Feb 17 '14 at 20:01
  • This looks wrong - it is extracting the value plus a comma (or white space as @Mooing Duck mentions), leaving the the last value (which has no separator) terminated by something. –  Feb 17 '14 at 20:09
  • @DieterLücking: the `else in.clear()` makes it so that the last value is indeed extracted properly, and the terminating character is left in the buffer. Check the link which shows the results of the test. If you can think of an error case I'll see what I can do – Mooing Duck Feb 17 '14 at 20:26
  • It would be good to add a case for the cin also apart from stringstream. – Atul Kumar Mar 04 '15 at 18:52
  • @user2876962: not sure what you mean, nothing in my answer does anything with stringstream specifically. It works with _any_ stream. – Mooing Duck Mar 04 '15 at 18:54
  • @MooingDuck Your code read from a comma separated string. User wants to read from console perhaps. For a beginner, it would be better to be on point. – Atul Kumar Mar 04 '15 at 19:02
  • 1
    @user2876962 no, my code reads in from anything derived from `std::istream&` named `in`... Oh! My sample creates a `stringstream` yes. You want this you mean? http://coliru.stacked-crooked.com/a/ff7c6acbde576e48 – Mooing Duck Mar 04 '15 at 19:14
  • @MooingDuck Great. Updating that link in your answer will make it exact answer for a beginner. – Atul Kumar Mar 04 '15 at 19:35
4

A priori, you should want to check that the comma is there, and declare an error if it's not. For this reason, I'd handle the first number separately:

std::vector<int> dest;
int value;
std::cin >> value;
if ( std::cin ) {
    dest.push_back( value );
    char separator;
    while ( std::cin >> separator >> value && separator == ',' ) {
        dest.push_back( value );
    }
}
if ( !std::cin.eof() ) {
    std::cerr << "format error in input" << std::endl;
}

Note that you don't have to ask for the size first. The array (std::vector) will automatically extend itself as much as needed, provided the memory is available.

Finally: in a real life example, you'd probably want to read line by line, in order to output a line number in case of a format error, and to recover from such an error and continue. This is a bit more complicated, especially if you want to be able to accept the separator before or after the newline character.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • +1 That `std::cin.eof()` might be no good it cin is used interactively - on the other hand, the input format (of the OP) is not well defined. –  Feb 17 '14 at 19:50
  • @DieterLücking Maybe. Logically, you want the size of the vector to be determined by the number of entries; having to enter it up front is unnecessary, and very Mickey Mouse. The simplest way of doing so is to read until end of file: if the input is a keyboard, ^D will do the trick under Unix, ^Z under Windows (at the start of the line, of course). Alternatively: you require all of the input to be in a single line, use `std::getline`, then `std::istringstream`, or you use some sort of keyword to signal the end. The last is probably too complex for a beginner. – James Kanze Feb 17 '14 at 21:27
2

You can use getline() method as below:

#include <vector>
#include <string>
#include <sstream>

int main() 
{
  std::string input_str;
  std::vector<int> vect;

  std::getline( std::cin, input_str );

  std::stringstream ss(str);

  int i;

  while (ss >> i)
  {
    vect.push_back(i);

    if (ss.peek() == ',')
    ss.ignore();
  }
}

The code is taken and processed from this answer.

Community
  • 1
  • 1
Victor
  • 13,914
  • 19
  • 78
  • 147
  • 4
    You don't need the getline() or the stringstream, just use ignore() directly on cin. – mattnewport Feb 17 '14 at 19:27
  • On the other hand, you usually don't want to use `peek` here, since it doesn't skip whitespace (which would be preferable). – James Kanze Feb 17 '14 at 19:37
  • And of course, the code in question fails to detect an error if a comma is missing. – James Kanze Feb 17 '14 at 19:38
  • @JamesKanze: On the other hand, input of any other type leaves the next character in the buffer, which requires the usage of `peek`. – Mooing Duck Feb 17 '14 at 19:56
  • @MooingDuck Using `>>` extracts the character, which can then be checked for `','`, which is what is wanted. (But handling separators, as opposed to terminators, can be a bit tricky. That's why I handled the first value separately, and then considered the `','` a required prefix. Not the only solution, but not too complicated, either.) – James Kanze Feb 17 '14 at 21:22
1

Victor's answer works but does more than is necessary. You can just directly call ignore() on cin to skip the commas in the input stream.

What this code does is read in an integer for the size of the input array, reserve space in a vector of ints for that number of elements, then loop up to the number of elements specified alternately reading an integer from standard input and skipping separating commas (the call to cin.ignore()). Once it has read the requested number of elements, it prints them out and exits.

#include <iostream>
#include <iterator>
#include <limits>
#include <vector>

using namespace std;

int main() {
    vector<int> vals;
    int i;
    cin >> i;
    vals.reserve(i);
    for (size_t j = 0; j != vals.capacity(); ++j) {
        cin >> i;
        vals.push_back(i);
        cin.ignore(numeric_limits<streamsize>::max(), ',');
    }
    copy(begin(vals), end(vals), ostream_iterator<int>(cout, ", "));
    cout << endl;
}
mattnewport
  • 13,728
  • 2
  • 35
  • 39
  • An interesting idea: use an `istream_iterator` for reading. (You'd need to define a special type, a `CommaSeparatedInt` for it, but it should be doable.) – James Kanze Feb 17 '14 at 19:46
  • I thought about that, but since the OP said he was a beginner and would like a simple answer it would probably be an overly complicated answer to his question. – mattnewport Feb 17 '14 at 19:47
  • Yes. I said an interesting idea, not something for a beginner. – James Kanze Feb 17 '14 at 21:09
1
#include <iostream>
using namespace std;

int main() {
    int x,i=0;
    char y;               //to store commas
    int arr[50];
    while(!cin.eof()){
        cin>>x>>y;
        arr[i]=x;
        i++;
    }

    for(int j=0;j<i;j++)
        cout<<arr[j];     //array contains only the integer part
    return 0;
}
vaibhav
  • 11
  • 1
0

The code can be simplified a bit with new std::stoi function in C+11. It takes care of spaces in the input when converting and throws an exception only when a particular token has started with non-numeric character. This code will thus accept input

" 12de, 32, 34 45, 45 , 23xp,"

easily but reject

" de12, 32, 34 45, 45 , 23xp,"

One problem is still there as you can see that in first case it will display " 12, 32, 34, 45, 23, " at the end where it has truncated "34 45" to 34. A special case may be added to handle this as error or ignore white space in the middle of token.

wchar_t in;
std::wstring seq;
std::vector<int> input;
std::wcout << L"Enter values : ";

while (std::wcin >> std::noskipws >> in)
{
    if (L'\n' == in || (L',' == in))
    {
        if (!seq.empty()){
            try{
                input.push_back(std::stoi(seq));
            }catch (std::exception e){ 
                std::wcout << L"Bad input" << std::endl;
            }
            seq.clear();
        }
        if (L'\n' == in) break;
        else continue;
    }
    seq.push_back(in);
}

std::wcout << L"Values entered : ";
std::copy(begin(input), end(input), std::ostream_iterator<int, wchar_t>(std::wcout, L", "));
std::cout << std::endl;
Atul Kumar
  • 366
  • 4
  • 15
0
#include<bits/stdc++.h>
using namespace std;
int a[1000];
int main(){
    string s;
    cin>>s;
    int i=0;
    istringstream d(s);
    string b;
    while(getline(d,b,',')){
        a[i]= stoi(b);
        i++;
    }
    for(int j=0;j<i;j++){
        cout<<a[j]<<" ";
    }
}

This code works nicely for C++ 11 onwards, its simple and i have used stringstreams and the getline and stoi functions

0

You can use scanf instead of cin and put comma beside data type symbol

#include<bits/stdc++.h>
using namespace std;
int main()
 {
    int a[10],sum=0;
    cout<<"enter five numbers";
    for(int i=0;i<3;i++){
    scanf("%d,",&a[i]);
    sum=sum+a[i];
    }
    cout<<sum;
}
RAM KUMAR
  • 1
  • 1
0

First, take the input as a string, then parse the string and store it in a vector, you will get your integers.

vector<int> v;
string str;
cin >> str;
stringstream ss(str);
for(int i;ss>>i;){
    v.push_back(i);
    if(ss.peek() == ','){
        ss.ignore();
    }
}
for(auto &i:v){
    cout << i << " ";
}