벡터의 내용을 인쇄하는 방법?


282

C ++에서 벡터의 내용을 인쇄하고 싶습니다. 다음은 내가 가진 것입니다.

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <vector>
#include <sstream>
#include <cstdio>
using namespace std;

int main()
{
    ifstream file("maze.txt");
    if (file) {
        vector<char> vec(istreambuf_iterator<char>(file), (istreambuf_iterator<char>()));
        vector<char> path;
        int x = 17;
        char entrance = vec.at(16);
        char firstsquare = vec.at(x);
        if (entrance == 'S') { 
            path.push_back(entrance); 
        }
        for (x = 17; isalpha(firstsquare); x++) {
            path.push_back(firstsquare);
        }
        for (int i = 0; i < path.size(); i++) {
            cout << path[i] << " ";
        }
        cout << endl;
        return 0;
    }
}

벡터의 내용을 화면에 어떻게 인쇄합니까?


1
왜 "작동하지 않습니다"?
기본값

답변:


394

순수하게 질문에 대답하기 위해 반복자를 사용할 수 있습니다.

std::vector<char> path;
// ...
for (std::vector<char>::const_iterator i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

for 루프에서 벡터의 내용을 수정하려면 iterator대신const_iterator .

그러나 이것에 대해 말할 수있는 것이 더 많이 있습니다. 당신이 사용할 수있는 대답을 원한다면 여기서 멈출 수 있습니다. 그렇지 않으면 계속 읽으십시오.

자동 (C ++ 11) / typedef

이것은 다른 해결책이 아니라 위의 iterator해결책에 대한 보충 입니다. C ++ 11 표준 (이상)을 사용하는 경우 auto키워드를 사용 하여 가독성을 높일 수 있습니다 .

for (auto i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

그러나의 유형은 i상수가 아닙니다 (즉, 컴파일러는 std::vector<char>::iterator의 유형으로 사용합니다 i).

이 경우 typedefC ++ 11에 국한되지 않고 어쨌든 사용하는 것이 매우 유용합니다.

typedef std::vector<char> Path;
Path path;
// ...
for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

카운터

물론 정수 유형을 사용하여 for루프 에서 위치를 기록 할 수 있습니다 .

for(int i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';

이 작업을 수행하려는 경우 컨테이너의 멤버 유형이 사용 가능하고 적절하다면 사용하는 것이 좋습니다. 이 작업에 대한 std::vector멤버 유형 size_typesize있습니다. 메소드가 리턴 한 유형 입니다.

// Path typedef'd to std::vector<char>
for( Path::size_type i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';

iterator솔루션 보다 이것을 사용하지 않습니까? 간단한 경우도 가능하지만 요점은 iterator클래스 가이 솔루션이 이상적이지 않은보다 복잡한 객체를 위해이 작업을 수행하도록 설계된 객체라는 것입니다.

범위 기반 for 루프 (C ++ 11)

Jefffrey의 솔루션을 참조하십시오 . C ++ 11 이상에서는 for다음과 같은 새로운 범위 기반 루프를 사용할 수 있습니다 .

for (auto i: path)
  std::cout << i << ' ';

이후 path항목 (명시 적으로의 벡터이다 std::vector<char>), 객체가 i벡터의 항목의 유형입니다 (즉, 명시 적으로,이 유형이다 char). 개체 i는 개체 의 실제 항목의 복사 본인 값을 갖습니다 path. 따라서 i루프의 모든 변경 사항 path자체 는 유지되지 않습니다 . 또한 i루프에서 복사 된 값을 변경하고 싶지 않다는 사실을 적용 하려면 유형 i을 다음 const char과 같이 강제 설정할 수 있습니다 .

for (const auto i: path)
  std::cout << i << ' ';

의 항목을 수정하려면 path참조를 사용할 수 있습니다.

for (auto& i: path)
  std::cout << i << ' ';

그리고 수정하고 싶지 않더라도 path객체 복사가 비싼 경우 값으로 복사하는 대신 const 참조를 사용해야합니다.

for (const auto& i: path)
  std::cout << i << ' ';

표준 :: 복사

참조 여호수아의 대답을 . STL 알고리즘 std::copy을 사용하여 벡터 내용을 출력 스트림에 복사 할 수 있습니다 . 이것은 편안하다면 우아한 솔루션입니다 (그리고 벡터의 내용을 인쇄하는 경우뿐만 아니라 매우 유용합니다).

std :: for_each

Max의 솔루션을 참조하십시오 . 사용 std::for_each이 간단한 시나리오에 대한 잔인한 사람이지만, 그냥 화면으로 인쇄하는 것보다 더 많은 일을하기를 원한다면 매우 유용한 솔루션입니다 : 사용 std::for_each당신이 할 수 있는 벡터 내용에 (분별) 작업을.

과부하 ostream :: operator <<

Chris의 답변을 참조하십시오 . 오버로드에서 위의 솔루션 중 하나를 여전히 구현해야하기 때문에 이것은 다른 답변에 대한 보완입니다. 그의 예제에서 그는 for루프 에서 카운터를 사용했습니다 . 예를 들어 다음과 같이 Joshua의 솔루션을 빠르게 사용할 수 있습니다 .

template <typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v) {
  if ( !v.empty() ) {
    out << '[';
    std::copy (v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
    out << "\b\b]";
  }
  return out;
}

다른 솔루션의 사용법은 간단해야합니다.

결론

여기에 제시된 모든 솔루션이 작동합니다. "최고"의 코드는 사용자에게 달려 있습니다. 이것보다 더 자세한 것은 아마도 찬반 양론이 적절하게 평가 될 수있는 또 다른 질문에 가장 적합한 것입니다. 그러나 항상 사용자 환경 설정이 항상 역할을합니다. 제시된 솔루션 중 어느 것도 잘못되지 않지만 일부는 각 개별 코더에 더 좋아 보일 것입니다.

추가

이것은 내가 게시 한 이전 솔루션의 확장 솔루션입니다. 그 게시물이 계속 주목을 받고 있기 때문에 나는 그것을 확장하기로 결정하고 여기에 게시 된 다른 우수한 솔루션을 참조하기로 결정했습니다. 내 원래의 게시물은 경우 그 언급 한 발언했다 있었다 , 안쪽 당신의 벡터 수정에 대한 의도 for다음이에서 제공하는 두 가지 방법이 있습니다 루프 std::vector: 액세스 요소에 std::vector::operator[]범위 검사를하지 않으며 std::vector::at않는 범위 검사를 수행. 즉, at벡터 외부의 요소에 액세스하려고 시도하면 operator[]그렇지 않습니다. 나는 누군가가 이미 모르는 경우에 유용 할 수있는 것을 언급하기 위해 원래이 의견을 추가했다. 그리고 나는 지금 아무런 차이가 없습니다. 따라서이 부록은 다음과 같습니다.


0스루를 반복 vector::size()하면서 루프 내에서 벡터를 수정하지 않으면 at()여분의 경계 검사 오버 헤드 를 사용할 필요가 없습니다 . 즉, 제안한대로 반복자와 함께 갈 것입니다.
Ed S.

1
@ Ed : 예, at루프에서 아무것도 벡터를 수정하지 않으면 사용에 아무런 의미가 없지만 루프에서 벡터 수정 된 경우 (권장되지 않음) 그리고 결코 얻지 못하기 때문에 언급 할 것이라고 생각 했습니다. 언급하고 적어도 그것을 아는 것이 유용 할 수 있습니다.
Zorawar

범위 기반 for 루프는 다음과 같이 큰 하위 오브젝트의 경우 중요 할 수있는 참조를 사용하도록 다시 작성할 수 있습니다.for (auto const &i: path) std::cout << i << ' ';
underscore_d

@underscore_d : 감사합니다. 나는 그 부분을 정리했으며 지금은 더 완전하고 명확 해지기를 바랍니다.
Zorawar

"과부하 연산자 <<"는 좋은 해결책이 아닙니다. 인수 의존적 조회로 인해 오버로드 된 연산자의 피연산자가 하나 이상 정의 된 클래스 여야합니다.
MM

218

가장 쉬운 방법은 표준 복사 알고리즘을 사용하는 것입니다 .

#include <iostream>
#include <algorithm> // for copy
#include <iterator> // for ostream_iterator
#include <vector>

int main() {
    /* Set up vector to hold chars a-z */
    std::vector<char> path;
    for (int ch = 'a'; ch <= 'z'; ++ch)
        path.push_back(ch);

    /* Print path vector to console */
    std::copy(path.begin(), path.end(), std::ostream_iterator<char>(std::cout, " "));

    return 0;
}

ostream_iterator는 반복자 어댑터 입니다. 스트림 (이 경우에는 char) 으로 인쇄하기 위해 유형 위에 템플릿 화 됩니다. cout(일명 콘솔 출력)은 우리가 쓰려는 스트림과 공백 문자 (" " )는 벡터에 저장된 각 요소 사이에 인쇄하려는 것입니다.

이 표준 알고리즘은 강력하며 다른 알고리즘도 강력합니다. 표준 라이브러리가 제공하는 강력 함과 유연성이 그토록 큰 장점입니다. 단지 줄의 코드로 콘솔에 벡터를 인쇄 할 수 있습니다 . 구분 문자를 사용하여 특별한 경우를 처리 할 필요는 없습니다. for 루프에 대해 걱정할 필요가 없습니다. 표준 라이브러리는 모든 것을 지원합니다.


3
무엇을 내 벡터 유형 인 경우 vector<pair<int, struct node>>. 이 방법을 사용하여이 벡터를 인쇄하려면 어떻게합니까?
mtk

6
구분자 문자열은 모든 요소 뒤에 , 즉 마지막 요소 사이에 있지 않고 쓰여집니다 . 그것은 당신이 분리기 (separator) 사이에서만 그것을 원한다면 특별한 경우를 다루어야 할 수도 있습니다.
Quigi

2
@mtk 당신은 operator<<당신의 특정 쌍에 대한 함수를 선언 할 수 있습니다 .
ShoeLace 2016 년

비슷한 접근 방식을 보여 주지만 추가 후행 구분 기호에 대해 위의 @Quigi : s 주석을 사용 하여 답변을 추가 했습니다 .
dfri

@ShoeLace 다른 방법이 없습니까?
thegreatcoder

69

C ++ 11에서는 이제 범위 기반 for 루프를 사용할 수 있습니다 .

for (auto const& c : path)
    std::cout << c << ' ';

이것은 for 루프 범위의 본문에서 벡터의 크기가 변경되지 않은 경우에만 효과적입니다.
Brian

8
@BrianP. 예. 컨테이너의 요소를 인쇄해도 컨테이너의 범위는 수정되지 않습니다.
구두

여기서 선호되는 것 – 요소를 복사하지 않도록 값 복사 또는 const 참조로 c?
kleinfreund

@kleinfreund 그것은 벡터의 내용에 달려 있습니다. 예를 들어 char, s 벡터의 경우 상수 참조를 통과하는 것이 실제로 값보다 비용이 많이 듭니다. 그러나 여기서는 마이크로 최적화에 대해 이야기하고 있습니다.
구두

43

이 작업을 수행하는 가장 좋은 방법은 operator<<이 기능을 프로그램에 추가하여 오버로드 하는 것입니다.

#include <vector>
using std::vector;
#include <iostream>
using std::ostream;

template<typename T>
ostream& operator<< (ostream& out, const vector<T>& v) {
    out << "{";
    size_t last = v.size() - 1;
    for(size_t i = 0; i < v.size(); ++i) {
        out << v[i];
        if (i != last) 
            out << ", ";
    }
    out << "}";
    return out;
}

그런 다음 <<요소도 ostream& operator<<정의 했다고 가정하면 가능한 벡터 에서 연산자를 사용할 수 있습니다 .

vector<string>  s = {"first", "second", "third"};
vector<bool>    b = {true, false, true, false, false};
vector<int>     i = {1, 2, 3, 4};
cout << s << endl;
cout << b << endl;
cout << i << endl;

출력 :

{first, second, third}
{1, 0, 1, 0, 0}
{1, 2, 3, 4}

3
v.size ()-1을 정수로 저장하면 가능한 정밀도 손실이 발생합니다. 승인 된 동료 검토 편집 ( stackoverflow.com/revisions/23397700/5 ) 에서이 문제를 해결 했지만 그 후 가능한 정밀도 손실을 복원하여 다시 편집했습니다. 벡터는 일반적으로 그렇게 크지 않기 때문에 실제로는별로 중요하지 않습니다.
JDiMatteo

변수로 저장하지 않으면 코드의 가독성이 떨어집니다. 이는 편집에 동의하지 않은 부분입니다. 유형을 last로 변경 했습니다 size_t.
Chris Redford

size_t last = v.size() - 1;중복 if (i) out << ", ";되기 때문에 out << v[i]; 링크
Vladimir Gamalyan

3
이 연산자는 인수의 네임 스페이스에 없으므로 ADL에서 찾을 수 없습니다. 따라서 다른 네임 스페이스에 의해 숨겨집니다 operator<<.
MM

이 작업을 수행 하려면 루프 에서if (i != last) 매번 테스트해야하는 이유 는 무엇입니까? 대신 컨테이너가 비어 있지 않으면 (a) 첫 번째 요소를 보낸 다음 (b) 나머지 요소를 루프 전송 하여 구분 기호를 먼저 인쇄합니다 (접두사). 루프 조건 자체를 제외하고 내부 루프 테스트가 필요하지 않습니다. 루프 외부 테스트는 하나만 필요합니다.
WhozCraig

22

방법에 대한 for_each+의 람다 식 :

#include <vector>
#include <algorithm>
...
std::vector<char> vec;
...
std::for_each(
              vec.cbegin(),
              vec.cend(),
              [] (const char c) {std::cout << c << " ";} 
              );
...

물론 범위 기반 은이 구체적인 작업을위한 가장 우아한 솔루션이지만이 방법은 다른 많은 가능성을 제공합니다.

설명

for_each알고리즘은 얻어 입력 범위호출 객체 의 범위의 모든 요소에서이 오브젝트를 호출. 입력 범위가 2로 정의 반복자 . 호출 객체 함수 함수 포인터, 과부하 클래스의 객체 일 수 () operator또는 이러한 경우에서와 같이, 람다 식 . 이 표현식의 매개 변수는 벡터의 요소 유형과 일치합니다.

이 구현의 장점은 람다 식에서 얻을 수있는 힘입니다. 벡터를 인쇄하는 것보다 훨씬 더 많은 방법으로이 방법을 사용할 수 있습니다.


11

컨테이너를 콘솔에 복사하십시오.

std::vector<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));

출력해야합니다 :

1 2 3 4

8

문제는 아마도 이전 루프에있을 것입니다 : (x = 17; isalpha(firstsquare); x++). 이 루프는 전혀 실행되지 않거나 ( firstsquare알파가 아닌 경우 ) 영원히 실행됩니다 (알파인 경우). 그 이유는 증가 firstsquare함에 따라 변경되지 않기 때문입니다 x.


7

C ++ 11에서는 범위 기반 for 루프가 좋은 솔루션 일 수 있습니다.

vector<char> items = {'a','b','c'};
for (char n : items)
    cout << n << ' ';

산출:

a b c 

6

std::copy추가 후행 구분 기호를 사용 하지 않고 사용

@JoshuaKravtiz answerstd::copy 에서 원래 사용 되었지만 마지막 요소 다음에 추가 후행 구분 기호를 포함하지 않는 대체 / 수정 된 접근법 :

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

template <typename T>
void print_contents(const std::vector<T>& v, const char * const separator = " ")
{
    if(!v.empty())
    {
        std::copy(v.begin(),
                  --v.end(),
                  std::ostream_iterator<T>(std::cout, separator));
        std::cout << v.back() << "\n";
    }
}

// example usage
int main() {
    std::vector<int> v{1, 2, 3, 4};
    print_contents(v);      // '1 2 3 4'
    print_contents(v, ":"); // '1:2:3:4'
    v = {};
    print_contents(v);      // ... no std::cout
    v = {1};
    print_contents(v);      // '1'
    return 0;
}

사용자 지정 POD 유형의 컨테이너에 적용되는 사용 예 :

// includes and 'print_contents(...)' as above ...

class Foo
{
    int i;
    friend std::ostream& operator<<(std::ostream& out, const Foo& obj);
public:
    Foo(const int i) : i(i) {}
};

std::ostream& operator<<(std::ostream& out, const Foo& obj)
{
    return out << "foo_" << obj.i; 
}

int main() {
    std::vector<Foo> v{1, 2, 3, 4};
    print_contents(v);      // 'foo_1 foo_2 foo_3 foo_4'
    print_contents(v, ":"); // 'foo_1:foo_2:foo_3:foo_4'
    v = {};
    print_contents(v);      // ... no std::cout
    v = {1};
    print_contents(v);      // 'foo_1'
    return 0;
}

5

과부하 연산자 << :

template<typename OutStream, typename T>
OutStream& operator<< (OutStream& out, const vector<T>& v)
{
    for (auto const& tmp : v)
        out << tmp << " ";
    out << endl;
    return out;
}

용법:

vector <int> test {1,2,3};
wcout << test; // or any output stream

3

두 가지 문제가 있습니다. 에서 지적했듯이 for (x = 17; isalpha(firstsquare); x++)무한 루프가 있거나 전혀 실행되지 않으며 if (entrance == 'S')입구 문자가 'S'와 다른 경우 경로 벡터에 아무것도 입력되지 않아 비워져 화면에 아무것도 인쇄되지 않습니다. 후자의 검사 path.empty()또는 인쇄 를 테스트 할 수 있습니다path.size() .

어느 쪽이든, 벡터 대신 문자열을 사용하는 것이 좋지 않을까요? 배열과 같은 문자열 내용에 액세스하고, 문자를 찾고, 부분 문자열을 추출하고, 루프없이 쉽게 문자열을 인쇄 할 수 있습니다.

문자열을 모두 사용하여 덜 복잡한 방식으로 작성하고 문제를 쉽게 발견 할 수 있습니다.


3

이 답변은 Zorawar의 답변을 기반으로하지만 거기에 의견을 남기지 못했습니다.

대신 cbegin 및 cend를 사용하여 자동 (C ++ 11) / typedef 버전을 const로 만들 수 있습니다.

for (auto i = path.cbegin(); i != path.cend(); ++i)
    std::cout << *i << ' ';

1

C ++ 11에서

for (auto i = path.begin(); i != path.end(); ++i)
std::cout << *i << ' ';

for(int i=0; i<path.size(); ++i)
std::cout << path[i] << ' ';

이 답변은 기존 답변과 비교하여 추가 정보를 제공하지 않습니다.
Yashas

0
#include<bits/stdc++.h>
using namespace std;

int main()
{
    vector <pair<string,int> > v;
    int n;
    cin>>n;
int i;
    for( i=0;i<n;i++)
    {
        int  end;
        string str;
        cin>>str;
        cin>>end;
        v.push_back(make_pair(str,end));
    }



for (int j=0;j<n;j++)
{
    cout<<v[j].first<< " "<<v[j].second<<endl;
}``
}

2
안녕하세요! stackoverflow에 오신 것을 환영합니다. 코드 스 니펫에 수행중인 작업 및 질문에 대한 답변에 대한 설명을 코드 스 니펫에 포함 시키면 좋을 것입니다.
Slabgorb 2016 년


0

이것은 나를 위해 일했다 :

    for (auto& i : name)
    {
    int r = 0;
    for (int j = 0; j < name[r].size();j++) 
    {
    std::cout << i[j];
    }
    r++;
    std::cout << std::endl;
    }

0

관심있는 사람들을 위해 : 나는 두 세계를 모두 활용하는 일반화 된 솔루션을 작성했으며 모든 유형의 범위로 더 일반화되었으며 비 산술 유형 (문자열과 같은 유형에 적합)을 인용합니다. 또한이 방법에는 ADL 문제가 없어야하며 '서프라이즈'를 피해야합니다 (사례별로 명시 적으로 추가되었으므로).

template <typename T>
inline constexpr bool is_string_type_v = std::is_convertible_v<const T&, std::string_view>;

template<class T>
struct range_out {
  range_out(T& range) : r_(range) {
  }
  T& r_;
  static_assert(!::is_string_type_v<T>, "strings and string-like types should use operator << directly");
};

template <typename T>
std::ostream& operator<< (std::ostream& out, range_out<T>& range) {
  constexpr bool is_string_like = is_string_type_v<T::value_type>;
  constexpr std::string_view sep{ is_string_like ? "', '" : ", " };

  if (!range.r_.empty()) {
    out << (is_string_like ? "['" : "[");
    out << *range.r_.begin();
    for (auto it = range.r_.begin() + 1; it != range.r_.end(); ++it) {
      out << sep << *it;
    }
    out << (is_string_like ? "']" : "]");
  }
  else {
    out << "[]";
  }

  return out;
}

이제 모든 범위에서 사용하기가 매우 쉽습니다.

std::cout << range_out{ my_vector };

끈 모양의 수표는 개선의 여지를 남겨둔다. 또한 static_assert피하기 위해 솔루션을 체크인 std::basic_string<>했지만 간단하게 여기에 남겨 두었습니다.


-1

당신은 당신의 자신의 함수를 작성할 수 있습니다 :

void printVec(vector<char> vec){
    for(int i = 0; i < vec.size(); i++){
        cout << vec[i] << " ";
    }
    cout << endl;
}

-1

루프가없는 단일 라이너를 원하는 사람들에게 :

나는 아무도 이것을 가지고 있지 않다는 것을 믿을 수는 없지만 아마도 C와 같은 접근 방식 때문일 수 있습니다. 어쨌든, 한 라이너, 루프없이이 일을 완벽하게 안전한 가정 (가) 있음을 std::vector<char>null로 끝나는 것입니다 :

std::vector<char> test { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\0' };
std::cout << test.data() << std::endl;

그러나 ostream@Zorawar이 제안한 것처럼 운영자에게 이것을 감싸서 안전합니다.

template <typename T>std::ostream& operator<< (std::ostream& out, std::vector<T>& v)
{
    v.push_back('\0'); // safety-check!
    out << v.data();
    return out;
}

std::cout << test << std::endl; // will print 'Hello, world!'

printf대신 다음 을 사용하여 비슷한 동작을 수행 할 수 있습니다 .

fprintf(stdout, "%s\n", &test[0]); // will also print 'Hello, world!'

노트:

과부하 된 ostream연산자는 벡터를 상수가 아닌 것으로 받아 들여야합니다. 이로 인해 프로그램이 안전하지 않거나 잘못 사용할 수있는 코드가 생길 수 있습니다. 또한 널 문자가 추가되므로 재 할당 std::vector이 발생할 수 있습니다. 따라서 반복자와 함께 for 루프를 사용하는 것이 더 빠를 것입니다.


1
1. fprintf(stdout, "%s\n", &test[0]);와 다르지 않으며 std::cout << test.data()둘 다 null로 끝나는 벡터가 필요합니다. 2. 그러나 << 올바른 피연산자를 수정하는 연산자는 "ostream 연산자로 래핑합니다" 라는 것은 매우 나쁜 생각입니다.
HolyBlackCat

나는 fprintf(stdout, "%s\n", &test[0]);아무런 문제없이 코드에서 오랫동안 사용 했습니다. 흥미 롭습니다! 그리고 ostream연산자 에서 벡터를 수정하는 것은 좋지 않지만 수동 반복 반복자를 사용하는 것을 싫어 합니다. 어떻게 든 std::vector<char>표준 라이브러리를 인쇄하는 것과 같은 간단한 작업에서 이러한 것들을 숨겨야한다고 생각합니다. 그러나 C ++은 지속적으로 개발되고 있으며 곧 나올 수 있습니다.
ワ イ き ん ぐ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.