Ir ao conteúdo
  • Cadastre-se

C++ Como usar <vector> para armazenar um texto


Trindade12
Ir à solução Resolvido por vangodp,

Posts recomendados

Boa tarde,

Como eu posso usar <vector> para ler um texto do usuario e armazenar cada palavra em uma posição do vector?

Criei este codigo, mas não sei como fazer para parar de ler o texto e nem separar cada palavra em uma posição diferente.

#include <iostream>
#include <string>
#include <vector>

int main() {

    std::vector<std::string> texto = {};
    
    while (std::cin >> texto[0]) {
        std::cin >> texto[0];
    }
    
    std::cout << texto[0];

    return 0;
}

 

  • Amei 1
Link para o comentário
Compartilhar em outros sites

  • Solução
#include<iostream>
#include<vector>
using namespace std;

int main(){
    std::vector<std::string> v;
    string s;
    
    s = "Ola";
    v.push_back( s.c_str() );
    
    s = "Mundo";
    v.push_back( s.c_str() );
    
    v.push_back( "curel" );

    for(auto a : v){
        cout << a << " ";
    }

    return 0;
}

igual que com outros tipos de dados você precisa fazer o tal pushback para inserir. Logo você terá v[0], v[1], v[2]... como de um vetor normal se tratara só que é um container da stl.

Não é o caso mas deixo a sugestão de investigar sobre emplaceback em vez de usar pushback. ;)

  • Curtir 3
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Em 16/12/2020 às 07:38, Trindade12 disse:

@vangodp Obrigado, funcionou direitinho. E vou pesquisar sobre o emplaceback

Só complementando o nosso amigo ali de cima.

 

A Rotina push_back, insere no final do vector. Se você precisa inserir no meio ou em outra posição, recomendo você usar o insert.

 

Por exemplo, para inserir no inicio:

 

strvec.insert(strvec.begin(), "Nova string");

 

O emplace_back, normalmente, realoca todas as posições de memória para inserir o seu elemento no vector. Isto é, essa rotina de insert que coloquei acima, se caso você tivesse armazenado o strvec.begin(), em uma variável, seria necessário atualizar a mesma, pois não seria mais um ponteiro válido.

 

// Ponteiro em posição inicial do vector
vector<string>::iterator ptr = strvec.begin();

// Insere realocando o vector inteiro.
strvec.emplace_back("Outra nova string");

// Tenta inserir na antiga posição inicial < é esperado uma exception
// Ao usar emplace_back, ocorre realocação de memória, então o ponteiro inicial também é alterado, por isso não vai conseguir inserir no começo
strvec.insert(ptr, "Teste de ponteiro");

 

Evite usar o emplace_back quando se está fazendo um laço for para inserir novos elementos usando os iteratores.

 

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

1 hora atrás, Carlos Zanon disse:

O emplace_back, normalmente, realoca todas as posições de memória para inserir o seu elemento no vector.

A mesma coisa faz o push_back(Com certa diferença), pois vetores são um conjunto contíguos. Se fizer push_back e não conter espaço contiguo na memória que você acha que vai acontecer??

Primeiro devemos entender como funciona o vector internamente. Para que um vetor seja funcional precisamos somente de duas coisas, um ponteiro ao primeiro elemento e o numero de elementos, com isso saberemos o tamanho, e onde começa obviamente. porém vector(da STL) n é só isso... ele contem alguns elementos a mais, que entre ditos elementos estão o capacity e size.
Quando criamos um vector ele começa tendo capacity 0 y size 0, cada vez que fazemos push_back( Ou emplaceback ou insert etc) passamos de capacity 0 a capacity 1, e o tamanho(size) passará a ser 1. Ao fazer uma nova chamada a new, que é o que faz e todas essas funções por nós de forma explicita, passaremos de capacity 1 a 2 e size 2, onde o dado seja inserido(inicio/meio/fim) não é o importante. O problema vem agora ao fazer um 3º puch_back, porque capacity não vai ser 3 si não 4, porque ele irá duplicando( 0, 1, 2, 4, 8, 16 ), é dizer... a partir da terceira chamada a new(chamar a puch_back, emplace_back, etc) teremos uma capacidade de 4 elementos no vetor, e só teremos um size 3, ou seja teremos uma capacidade de 4 elementos mas teremos somente 3 elementos no vector, e teremos um espaço a mais no vetor para uma futura chamada a new.


Ao fazer novas chamadas a essas funções o programa terá cada vez maior custe, pois a reserva de elementos será cada vez maior mesmo você n usando esse espaço. Que pode sair mal? Como falei a reserva vai se duplicando cada vez que o size supere o capacity, n importa qual dessas funções você chamar. O que pode sair ruim é que em um determinado momento o vetor fique estrangulado por n ter mais para onde se expandir, coisa que ele solucionaria reservando o dobro do espaço em outro lugar e copiando todos os dados a essa nova posição, coisa que aumentaria o custe, pois sabemos que copiar dados n é gratis, leva um tempo, e dependendo do tamanho do vetor pode ficar chato, para isso existe funções como reserve, que você pode indicar um tamanho inicial caso souber quantos elementos vai usar desde o inicio.

Então como falei o problema n era esse... o que faz o emplace_back é que você n precisa criar um objeto na pilha e depois fazer a inserção de dito objeto, o objeto será construido diretamente no heap, ja o push_back precisa de um objeto no qual você vai copiar ele no heap, por isso fai que:

Em 16/12/2020 às 02:08, vangodp disse:

Não é o caso mas deixo a sugestão de investigar sobre emplaceback em vez de usar pushback. ;)

.
Não sei se me expressei bem ou deu para entender, sou muito ruim escrevendo shuehsueh.

Se n quiser ter problemas com o tal capacity talvez o que necessite é o list, porém o list dispersa os dados pela memória, coisa que aumenta o tempo ao percorrer toda a lista.

Se alguém achar que estou errado ou quiser comentar e aportar algo que ignoro, que deixe seu ponto de vista aqui abaixo. Sorte!

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

#include <iostream>
#include <string>
#include <vector>
int main() {
    std::vector<std::string> texto = {};   
    while (std::cin >> texto[0]) {
        std::cin >> texto[0];
    }    
    std::cout << texto[0];
    return 0;
}

 

Em 15/12/2020 às 17:11, Trindade12 disse:

Criei este codigo, mas não sei como fazer para parar de ler o texto e nem separar cada palavra em uma posição diferente

 

Já sabe como seria copiar todas as palavras na mesma posição: a primeira. Se estivesse certo, copiaria todos os valores, um sobre o outro, até o fim.

 

Você tem um livro sobre isso? Já leu algum? Recomendo muito ter um livro ou ao menos ler um pouco sobre o que está tentando fazer. Onde arrumou essa linha. por exemplo:
 

    std::vector<std::string> texto = {};

 

vector é uma classe em C++. Um tipo particular de classe: um container. Um vetor pode ter qualquer coisa dentro, por exemplo valores que sejam outras classes, como string no seu caso.

 

Quando você declara algo como vector<> isso vai chamar um construtor, como qualquer e toda classe em C++, e aí que tal ver no manual quais são as possibilidades? Em CPlusPlus.com por exemplo diz sobre vector:
 

default (1)	
vector();
explicit vector (const allocator_type& alloc);

fill (2)	
explicit vector (size_type n, const allocator_type& alloc = allocator_type());
         vector (size_type n, const value_type& val,
                 const allocator_type& alloc = allocator_type());

range (3)	
template <class InputIterator>
  vector (InputIterator first, InputIterator last,
          const allocator_type& alloc = allocator_type());

  copy (4)	
vector (const vector& x);
vector (const vector& x, const allocator_type& alloc);

  move (5)	
vector (vector&& x);
vector (vector&& x, const allocator_type& alloc);

  initializer list (6)	
vector (initializer_list<value_type> il,
       const allocator_type& alloc = allocator_type());

 

E você optou pelo primeiro, começou com um vetor vazio. OK, mas nesse caso não é a melhor opção.

 

E para colocar algo lá dentro? O que você pode fazer com a classe é um repertório de funções, e em C++ são chamadas métodos. Eis o começo da lista, no mesmo lugar:

referencia para vector

 

Lá tem esse método
 

image.png.f2d4b965aa801c2cd18b4fd5955a1061.png

 

mesmo sem um livro em português: isso adiciona um elemento ao final do vetor. E é uma função pública. Isso quer dizer que você pode escrever sempre, no seu caso, 
 

    string um{};
    while (std::cin >> um) texto.push_back(um); 

 

porque texto é do tipo vector<string>: foi você que declarou assim. E  um é string. Então texto aceita um e como é um vetor pode usar todas as funções membro públicas de vector, os tais métodos.

 

E assim esse loop iria consumir toda a entrada uma string por vez: uma linha

 

E para mostrar isso na tela pra conferir:
 

    for ( auto  x : texto ) cout << x << "\n";

 

Outra linha. Isso funciona porque todo elemento de texto é uma string, como declarado. E então esse for vai ver que x vai assumir todo possível valor que tem no vetor, no popular o conteúdo, uma string por vez. 

 

Juntando isso teria um programa minimalista que faria o que você parece querer:

 

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(void)
 {
    string um;
    std::vector<std::string> texto = {}; 

    // lendo
    while (std::cin >> um) texto.push_back(um);

    //mostrando
    for ( auto  x : texto ) cout << x << "\n";
    return 0;
}

 

Há maneiras mais simples de fazer isso.

 

E claro há maneiras mais complicadas.

 

Mas o que importa sempre é escrever em torno dos dados e aqui tem um problema:

 

  • Que d1@b0 é uma palavra? 
  • O que vai  fazer com as duplicadas?
  • "a+b" é uma palavra? Ou 3?
  • E "dois,tres" é uma palavra? serão duas? três?

Antes de tudo precisa de uma definição precisa do que é uma palavra. E o que fazer com as eventuais duplicatas.

 

Procure ler os dados de uma arquivo. É muito mais fácil e seguro. E muito menos chato que ficar digitando no terminal.

 

3 horas atrás, vangodp disse:

Quando criamos um vector ele começa tendo capacity 0 y size 0, cada vez que fazemos push_back( Ou emplaceback ou insert etc) passamos de capacity 0 a capacity 1, e o tamanho(size) passará a ser 1. Ao fazer uma nova chamada a new, que é o que faz e todas essas funções por nós de forma explicita, passaremos de capacity 1 a 2 e size 2, onde o dado seja inserido(inicio/meio/fim) não é o importante. O problema vem agora ao fazer um 3º puch_back, porque capacity não vai ser 3 si não 4, porque ele irá duplicando( 0, 1, 2, 4, 8, 16 ), é dizer... a partir da terceira chamada a new(chamar a puch_back, emplace_back, etc) teremos uma capacidade de 4 elementos no vetor, e só teremos um size 3, ou seja teremos uma capacidade de 4 elementos mas teremos somente 3 elementos no vector, e teremos um espaço a mais no vetor para uma futura chamada a new

 

Não entendi nadinha disso que escreveu. Mas vou deixar minha opinião também:

  • metadados como size, capacity, allocator e essas questões de realocação e performance e new devem ser basicamente esquecidos até você ter um motivo sólido para se preocupar com isso. A implementação geralmente faz isso muito melhor que qualquer um de nós, provavelmente. Melhor do eu certamente.
  • vector é muito, muito rápido em geral.
  • insira SEMPRE no fim, o tal push_back(). Se não serve para seu caso provavelmente não deveria estar usando vector. Tem uma família grande de containers, que é o nome dessas coisas em C++. E cada um tem suas qualidades. vector é muito rápido para ler, iterar e para inserir, mas no fim.
  • vector pode sempre ser retornado por valor --- "move semantics" -- então é algo pra nem pensar quando se está aprendendo. Declare e use.
  • para esse caso das palavras, set é o container mais óbvio, já que os elementos já ficam em ordem e sem duplicidade... E não precisa mudar muito no programa :):
     
    #include <iostream>
    #include <string>
    #include <set>
    using namespace std;
    int main(void)
     {
        string um;
        std::set<std::string> texto = {}; 
    
        // lendo
        while (std::cin >> um) texto.insert(um);
    
        //mostrando
        for ( auto  x : texto ) cout << x << "\n";
        return 0;
    }

    Já que são todos iguais.

 

  • Curtir 1
  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

3 horas atrás, vangodp disse:

Só você n entendeu, mas como você ja sabe tudo n lhe vou explicar

 

@vangodp
 

:) Você teve uma visão? Duas? Só sei dizer que EU não entendi. Você por outro lado diz que

  • eu fui o único que não entendeu
  • eu sei tudo

Não sei "tudo". Sei bem pouco. E eu li de novo o que escreveu. Não entendi nada. De novo. E acho que está errado, no fundo. Vou tentar te mostrar como eu penso.


Escrevi um programa para ajudar:
 

// prg.c
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char** argv)
{
    vector<string> teste;
    unsigned prev = 0;
    unsigned long N = 1000; // limite padrão
    if (argc > 1) N = strtoul( argv[1], nullptr, 10 );
    cout << N << " elementos no vetor neste teste\n\n";
    for (unsigned i = 0; i < N; i += 1)
    {
        teste.push_back("teste");
        if ( prev != teste.capacity() )
        {
            cout << "\tsize = " << 
                std::setw(11) << teste.size() <<
                " capacity mudou: " << std::setw(11) << prev <<
                " => " << 
                std::setw(11) << teste.capacity() << "\n";
            prev = teste.capacity();
        };  // if()
    };  // for()
};  // main()

 

Ele mostra a variação de capacity à medida em que size aumenta em um vetor.

 

Como vê, tem pouco mais de 20 linhas, e ele aceita um único (esperado) argumento: o tamanho do vetor. Sem argumentos assume 1000 só para ter um valor

 

Rodando sem argumentos e depois para um milhão de elementos:
 

C:\Users\toninho\source\repos\ConsoleApplication3\Debug>pgm
1000 elementos no vetor neste teste

        size =           1 capacity mudou:           0 =>           1
        size =           2 capacity mudou:           1 =>           2
        size =           3 capacity mudou:           2 =>           3
        size =           4 capacity mudou:           3 =>           4
        size =           5 capacity mudou:           4 =>           6
        size =           7 capacity mudou:           6 =>           9
        size =          10 capacity mudou:           9 =>          13
        size =          14 capacity mudou:          13 =>          19
        size =          20 capacity mudou:          19 =>          28
        size =          29 capacity mudou:          28 =>          42
        size =          43 capacity mudou:          42 =>          63
        size =          64 capacity mudou:          63 =>          94
        size =          95 capacity mudou:          94 =>         141
        size =         142 capacity mudou:         141 =>         211
        size =         212 capacity mudou:         211 =>         316
        size =         317 capacity mudou:         316 =>         474
        size =         475 capacity mudou:         474 =>         711
        size =         712 capacity mudou:         711 =>        1066

C:\Users\toninho\source\repos\ConsoleApplication3\Debug>pgm 1000000
1000000 elementos no vetor neste teste

        size =           1 capacity mudou:           0 =>           1
        size =           2 capacity mudou:           1 =>           2
        size =           3 capacity mudou:           2 =>           3
        size =           4 capacity mudou:           3 =>           4
        size =           5 capacity mudou:           4 =>           6
        size =           7 capacity mudou:           6 =>           9
        size =          10 capacity mudou:           9 =>          13
        size =          14 capacity mudou:          13 =>          19
        size =          20 capacity mudou:          19 =>          28
        size =          29 capacity mudou:          28 =>          42
        size =          43 capacity mudou:          42 =>          63
        size =          64 capacity mudou:          63 =>          94
        size =          95 capacity mudou:          94 =>         141
        size =         142 capacity mudou:         141 =>         211
        size =         212 capacity mudou:         211 =>         316
        size =         317 capacity mudou:         316 =>         474
        size =         475 capacity mudou:         474 =>         711
        size =         712 capacity mudou:         711 =>        1066
        size =        1067 capacity mudou:        1066 =>        1599
        size =        1600 capacity mudou:        1599 =>        2398
        size =        2399 capacity mudou:        2398 =>        3597
        size =        3598 capacity mudou:        3597 =>        5395
        size =        5396 capacity mudou:        5395 =>        8092
        size =        8093 capacity mudou:        8092 =>       12138
        size =       12139 capacity mudou:       12138 =>       18207
        size =       18208 capacity mudou:       18207 =>       27310
        size =       27311 capacity mudou:       27310 =>       40965
        size =       40966 capacity mudou:       40965 =>       61447
        size =       61448 capacity mudou:       61447 =>       92170
        size =       92171 capacity mudou:       92170 =>      138255
        size =      138256 capacity mudou:      138255 =>      207382
        size =      207383 capacity mudou:      207382 =>      311073
        size =      311074 capacity mudou:      311073 =>      466609
        size =      466610 capacity mudou:      466609 =>      699913
        size =      699914 capacity mudou:      699913 =>     1049869

C:\Users\toninho\source\repos\ConsoleApplication3\Debug>

 

Isso no caso do compilador da Microsoft. Entenda que a ideia desses containers é que você não se preocupe com essas coisas. Mais ainda, a estratégia de alocação é definida por cada  implementação de std::vector.

Se você já programou algo assim como um array dinâmico de estruturas em alguma linguagem sabe que é preciso ter alguma disciplina de alocação para não ficar muito lento. Só que os caras que programam essas coisas são muito melhores do que desenvolvedores comuns. Alguns são conhecidos e estão entre os melhores caras de nossa época, e assim em geral se deve deixar por conta deles mesmo. 

 

Quando seu problema for tal que exija algo mais existem muitas possibilidades de interferir no vetor, alocando um tamanho inicial, passando seu próprio alocador de memória e coisas assim. E você sempre pode derivar a classe ou escrever outra. E se o seu problema exige algo assim você provavelmente saberá escrever algo assim também ;) 

 

De volta ao seu texto

 

Se rodar o programa acima em sua máquina, ou apenas aceitar os números acima, talvez concorde que as coisas não são como tentou escrever

 

Em 17/12/2020 às 23:53, arfneto disse:

Quando criamos um vector ele começa tendo capacity 0 y size 0, cada vez que fazemos push_back( Ou emplaceback ou insert etc) passamos de capacity 0 a capacity 1, e o tamanho(size) passará a ser 1

 

Não é o caso. Veja o que diz o programa acima. E sobre isso veja o que diz uma referência comum:
 

Citação

"vetores podem alocar memória extra para acomodar um possível crescimento, e assim um o container pode ter uma capacidade real maior que a estritamente necessária para conter seus elementos --- o valor de size(). Diferentes bibliotecas podem implementar diferentes estratégias de crescimento para obter um equilíbrio entre uso de memória e realocações mas, em qualquer caso, realocações devem ocorrer apenas em intervalos crescentes logaritmicamente em tamanho de modo que a inserção de elementos ao final do vetor --- push_back() --- possa ser oferecida com complexidade constante em relação ao tempo" 

 

Sobre isso
 

Em 17/12/2020 às 19:50, vangodp disse:

Ao fazer uma nova chamada a new, que é o que faz e todas essas funções por nós de forma explicita, passaremos de capacity 1 a 2 e size 2, onde o dado seja inserido(inicio/meio/fim) não é o importante


Imagino que pretendia escrever "de forma implícita" e não "explícita". E de todo modo fato de ser inserido no início/meio/fim, ao contrário do que disse, é muito importante. A performance é excelente ao inserir no final. E inserir em outros pontos não é sequer recomendado. Da mesma fonte, leia por exemplo
 

Citação

Compared to the other dynamic sequence containers (deques, lists and forward_lists), vectors are very efficient accessing its elements (just like arrays) and relatively efficient adding or removing elements from its end. For operations that involve inserting or removing elements at positions other than the end, they perform worse than the others, and have less consistent iterators and references than lists and forward_lists - https://www.cplusplus.com/reference/vector/vector/ 

 

Não vou traduzir como fiz antes porque estou com preguiça.

 

Mas vou dizer o que sempre digo sobre vetores em C++: Use como arrays em C e são ultra-rápidos e simples. Insira só no final. Se não serve assim estude seus dados e use outra estrutura.

 

Em 17/12/2020 às 23:53, arfneto disse:

O problema vem agora ao fazer um 3º puch_back, porque capacity não vai ser 3 si não 4, porque ele irá duplicando( 0, 1, 2, 4, 8, 16 ), é dizer... a partir da terceira chamada a new(chamar a puch_back, emplace_back, etc) teremos uma capacidade de 4 elementos no vetor, e só teremos um size 3, ou seja teremos uma capacidade de 4 elementos mas teremos somente 3 elementos no vector, e teremos um espaço a mais no vetor para uma futura chamada a new

 

Bem, já sabe que não é assim. Mas entenda que por exemplo para  size = 138.256 a capacidade muda para  207.382 e esse é o desperdício em troca da performance no caso desse compilador. 
       

Abraço.

Bom final de semana

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...