如何读取用户输入的逗号分隔整数?

6
我正在编写一个程序,提示用户输入以下信息:
  1. 数组的大小
  2. 要放入数组中的值
第一部分很简单,我创建了一个动态分配的数组(必须这样做),并将其设置为用户想要的大小。
我卡在下一步。用户应该输入一系列用逗号隔开的整数,例如:1,2,3,4,5
我该如何获取这些整数并将它们放入我的动态分配的数组中?我读到cin默认接受以空格分隔的整数,我能把它改成以逗号分隔吗?
请尽可能简单地解释,我是编程的初学者(抱歉!)
编辑:非常感谢所有回答。问题是我们还没有涵盖向量...只使用我已有的动态分配的数组是否有办法?
到目前为止,我的函数看起来像这样。我在主函数中创建了一个默认数组。我计划将其传递到此函数中,创建新数组,填充它,并更新指针以指向新数组。
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
}

C++ 中有 split() 函数吗? - Ranveer
相关:https://dev59.com/lnI-5IYBdhLWcg3wW3Cp - Robert Harvey
最简单的方法需要一些编码,恐怕我必须这么说。你的开头句子表明你已经在这方面有所进展,看到你目前为止做了什么会很有帮助。 - WhozCraig
9个回答

5

所有现有的答案都非常好,但都是针对您特定任务的。因此,我编写了一段通用代码,以标准方式允许输入逗号分隔的值:

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 
}

示例用法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

由于您是初学者,这段代码可能对您来说有些困难,但我认为我应该发布这个完整的代码。


嗯,有一个奇怪的问题,它也会解析空格分隔的输入。我不知道是否要禁止这种情况。 - Mooing Duck
这看起来不对 - 它提取了值加上逗号(或者像@Mooing Duck提到的空格),留下了最后一个值(它没有分隔符)被某些东西终止。 - user2249683
@DieterLücking:else in.clear() 使得最后一个值确实被正确提取,并且终止字符留在缓冲区中。请查看链接以查看测试结果。如果您能想到错误情况,我会尽力解决。 - Mooing Duck
除了stringstream之外,为cin添加一个case会很好。 - Atul Kumar
1
@user2876962 不好意思,我的代码从任何名为 instd::istream& 的派生类中读取... 哦!我的样例创建了一个 stringstream 对吧。你是想要这个吗?http://coliru.stacked-crooked.com/a/ff7c6acbde576e48 - Mooing Duck
显示剩余3条评论

4

首先,您应该检查是否有逗号存在,如果没有,则声明错误。因此,我会单独处理第一个数字:

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;
}

请注意,您不必首先请求大小。如果有足够的内存,数组(std::vector)将自动扩展自己。
最后,在实际示例中,您可能希望逐行阅读,以便在格式错误时输出行号,并从此类错误中恢复并继续执行。这有点更复杂,特别是如果您想要能够在换行符之前或之后接受分隔符。

+1 那个 std::cin.eof() 可能不太好,如果 cin 是交互式使用的话 - 另一方面,OP 的输入格式并没有很好地定义。 - user2249683
@DieterLücking 可能吧。从逻辑上讲,向量的大小应该由条目数确定;预先输入它是不必要的,而且非常幼稚。最简单的方法是读取直到文件结尾:如果输入来自键盘,在Unix下使用^D,在Windows下使用^Z(当然是在行首)。或者:您需要将所有输入放在一行中,使用std::getline,然后使用std::istringstream,或者使用某种关键字来表示结束。最后一个对于初学者来说可能太复杂了。 - James Kanze

2
您可以按如下方式使用getline()方法:
#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();
  }
}

这段代码是从这篇回答中提取和处理的。


4
不需要使用getline()或stringstream,直接在cin上使用ignore()即可。 - mattnewport
另一方面,您通常不希望在此处使用 peek,因为它不会跳过空格(这是更可取的)。 - James Kanze
当然,如果逗号丢失,相关代码将无法检测到错误。 - James Kanze
@JamesKanze:另一方面,任何其他类型的输入都会将下一个字符留在缓冲区中,这需要使用peek - Mooing Duck
@MooingDuck 使用 >> 提取字符,然后可以检查是否为 ',',这就是所需的内容。(但处理分隔符与终止符不同,可能有点棘手。这就是为什么我单独处理了第一个值,然后将 ',' 视为必需前缀的原因。这不是唯一的解决方案,但也不太复杂。) - James Kanze

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;
}

1
Victor的回答是可行的,但做得过多了。您可以直接在cin上调用ignore()以跳过输入流中的逗号。
这段代码的作用是读取输入数组的大小的整数,在int的向量中为该数量的元素保留空间,然后循环到指定的元素数,交替从标准输入读取整数并跳过分隔逗号(调用cin.ignore())。一旦它读取了所请求的元素数,它就会将它们打印出来并退出。
#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;
}

一个有趣的想法:使用istream_iterator进行读取。(你需要定义一个特殊类型,即CommaSeparatedInt,但应该是可行的。) - James Kanze
我考虑过这个问题,但鉴于楼主说自己是初学者,想要一个简单的答案,给他提供一个过于复杂的答案可能并不合适。 - mattnewport
是的。我说的是一个有趣的想法,而不是初学者能理解的东西。 - James Kanze

0

使用C+11中的新std::stoi函数可以简化代码。它在转换时处理输入中的空格,并仅在特定标记以非数字字符开头时抛出异常。因此,此代码将轻松接受输入

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

但会拒绝

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

仍然存在一个问题,就是在第一种情况下,它将在末尾显示“12, 32, 34, 45, 23”,其中将“34 45”截断为34。可以添加一个特殊情况来处理此错误或忽略标记中间的空格。

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;

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]<<" ";
    }
}

这段代码适用于C++ 11及以上版本,它很简单,我使用了stringstreams、getline和stoi函数。


0
首先,将输入作为字符串进行处理,然后解析该字符串并将其存储在向量中,这样您就可以得到您的整数。
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 << " ";
}

0
你可以使用scanf代替cin,并在数据类型符号旁边放置逗号。
#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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接