Como declarar um array de strings em C ++?

89

Estou tentando iterar todos os elementos de uma matriz estática de strings da melhor maneira possível. Quero ser capaz de declará-lo em uma linha e adicionar / remover elementos facilmente sem ter que controlar o número. Parece muito simples, não é?

Possíveis não soluções:

vector<string> v;
v.push_back("abc");
b.push_back("xyz");

for(int i = 0; i < v.size(); i++)
    cout << v[i] << endl;

Problemas - nenhuma maneira de criar o vetor em uma linha com uma lista de strings

Possível não solução 2:

string list[] = {"abc", "xyz"};

Problemas - nenhuma maneira de obter o número de strings automaticamente (que eu saiba).

Deve haver uma maneira fácil de fazer isso.

naumcho
fonte
A biblioteca de atribuição de impulso parece ser exatamente o que você está procurando. Isso torna a atribuição de constantes a contêineres mais fácil do que nunca.
Craig H

Respostas:

108

C ++ 11 adicionou listas de inicialização para permitir a seguinte sintaxe:

std::vector<std::string> v = {"Hello", "World"};

O suporte para este recurso C ++ 11 foi adicionado pelo menos no GCC 4.4 e apenas no Visual Studio 2013 .

Anthony Cramp
fonte
2018. Acabei de iniciar o C ++ e fiz algumas pesquisas sobre matrizes flexíveis. Acabou usando apenas vetores ...
Robert Molina
37

Você pode inicializar concisamente a vector<string>partir de uma char*matriz criada estaticamente :

char* strarray[] = {"hey", "sup", "dogg"};
vector<string> strvector(strarray, strarray + 3);

Isso copia todas as strings, aliás, então você usa o dobro da memória. Você pode usar a sugestão de Will Dean para substituir o número mágico 3 aqui por arraysize (str_array) - embora eu me lembre de haver algum caso especial em que essa versão específica de arraysize pode fazer algo ruim (desculpe, não consigo me lembrar dos detalhes imediatamente) . Mas muitas vezes funciona corretamente.

Além disso, se você estiver realmente entusiasmado com a coisa de uma linha, pode definir uma macro variável para que uma única linha DEFINE_STR_VEC(strvector, "hi", "there", "everyone");funcione.

Tyler
fonte
Como strarrayestá em um cabeçalho, não violará a regra de definição única?
jww
22

Problemas - nenhuma maneira de obter o número de strings automaticamente (que eu conheço).

Existe uma maneira padrão bog de fazer isso, que muitas pessoas (incluindo MS) definem macros como arraysizepara:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))
Will Dean
fonte
1
Alternativamente, pode-se usar algo como isto: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (Palavra-chave inline não é necessária, mas usada para documentar a intenção da função. Um compilador moderno deveria teoricamente ser capaz de retornar a função inteira, eu acredito.
Justin Time - Reintegrar Monica
1
Isso falha para ponteiros. A contagem de elementos da matriz deve ser feita de maneira diferente em C ++.
jww
8

Declare uma matriz de strings em C ++ como esta: char array_of_strings[][]

Por exemplo : char array_of_strings[200][8192];

irá conter 200 strings, cada string tendo o tamanho de 8kb ou 8192 bytes.

use strcpy(line[i],tempBuffer); para colocar dados no array de strings.


fonte
Para sua informação, char array_of_strings [] [] não pode aceitar strings C ++, certifique-se de converter para char * primeiro. cplusplus.com/reference/string/string/c_str
Luqmaan
Como array_of_stringsestá em um cabeçalho, não violará a regra de definição única?
jww
7

Uma possibilidade é usar um ponteiro NULL como um valor de sinalizador:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}
Eclipse
fonte
O que char ** realmente significa? Em java, seria uma lista de strings?
IAmGroot
1
@Doomsknight: Nesse caso, sim. Na primeira linha, defino um array de char*. Na memória, isso é apresentado como 3 ponteiros - um aponta para "cachorro", outro aponta para "gato" e o outro é NULL. Posso pegar um ponteiro para aquele primeiro ponteiro e obter um char**- um ponteiro para um ponteiro para char. Quando eu incremento isso, eu movo o char ** para apontar para o próximo item na lista - um ponteiro para o ponteiro que aponta para "gato", então eu incremento novamente e obtenho um ponteiro que aponta para o ponteiro NULL, e Eu sei que estou feito. (
Eclipse de
4

Você pode usar as funções begine endda biblioteca de intervalo Boost para encontrar facilmente as extremidades de um array primitivo e, ao contrário da solução de macro, isso dará um erro de compilação em vez de um comportamento interrompido se você acidentalmente aplicá-lo a um ponteiro.

const char* array[] = { "cat", "dog", "horse" };
vector<string> vec(begin(array), end(array));
Ross Smith
fonte
3

Você pode usar a sugestão de Will Dean [ #define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))] para substituir o número mágico 3 por arraysize (str_array) - embora eu me lembre de haver algum caso especial em que essa versão particular de arraysize pode fazer algo ruim (desculpe, não consigo me lembrar dos detalhes imediatamente). Mas muitas vezes funciona corretamente.

O caso em que não funciona é quando o "array" é realmente apenas um ponteiro, não um array real. Além disso, devido à maneira como os arrays são passados ​​para funções (convertidos em um ponteiro para o primeiro elemento), ele não funciona em chamadas de função, mesmo que a assinatura se pareça com um array - some_function(string parameter[])realmente é some_function(string *parameter).

Matthew Crumley
fonte
3

Aqui está um exemplo:

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

int main() {
    const char* const list[] = {"zip", "zam", "bam"};
    const size_t len = sizeof(list) / sizeof(list[0]);

    for (size_t i = 0; i < len; ++i)
        std::cout << list[i] << "\n";

    const std::vector<string> v(list, list + len);
    std::copy(v.begin(), v.end(), std::ostream_iterator<string>(std::cout, "\n"));
}
Shadow2531
fonte
2

Em vez dessa macro, posso sugerir este:

template<typename T, int N>
inline size_t array_size(T(&)[N])
{
    return N;
}

#define ARRAY_SIZE(X)   (sizeof(array_size(X)) ? (sizeof(X) / sizeof((X)[0])) : -1)

1) Queremos usar uma macro para torná-la uma constante de tempo de compilação; o resultado da chamada de função não é uma constante de tempo de compilação.

2) No entanto, não queremos usar uma macro porque a macro pode ser usada acidentalmente em um ponteiro. A função só pode ser usada em matrizes de tempo de compilação.

Portanto, usamos a definição da função para tornar a macro "segura"; se a função existe (ou seja, tem tamanho diferente de zero), então usamos a macro como acima. Se a função não existir, retornamos um valor incorreto.

DrPizza
fonte
2
#include <boost/foreach.hpp>

const char* list[] = {"abc", "xyz"};
BOOST_FOREACH(const char* str, list)
{
    cout << str << endl;
}

fonte
1
#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>

int main()
{
    const std::vector< std::string > v = boost::assign::list_of( "abc" )( "xyz" );
    std::copy(
        v.begin(),
        v.end(),
        std::ostream_iterator< std::string >( std::cout, "\n" ) );
}
Dominic.wig
fonte
1

Você pode declarar diretamente um array de strings como string s[100];. Então, se você deseja acessar elementos específicos, pode obtê-lo diretamente como s[2][90]. Para fins de iteração, pegue o tamanho da string usando a s[i].size()função.

Kajol Jain
fonte