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


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_type이 size있습니다. 메소드가 리턴 한 유형 입니다.

// 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.