¿Cómo declarar una matriz de cadenas en C ++?

89

Estoy tratando de iterar sobre todos los elementos de una matriz estática de cadenas de la mejor manera posible. Quiero poder declararlo en una línea y agregar / eliminar elementos fácilmente sin tener que realizar un seguimiento del número. Suena muy simple, ¿no?

Posibles no soluciones:

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

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

Problemas: no hay forma de crear el vector en una línea con una lista de cadenas

Posible no solución 2:

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

Problemas: no hay forma de obtener la cantidad de cadenas automáticamente (que yo sepa).

Debe haber una manera fácil de hacer esto.

naumcho
fuente
La biblioteca de asignación de impulso parece ser exactamente lo que está buscando. Hace que la asignación de constantes a contenedores sea más fácil que nunca.
Craig H

Respuestas:

108

C ++ 11 agregó listas de inicialización para permitir la siguiente sintaxis:

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

Se agregó soporte para esta característica de C ++ 11 en al menos GCC 4.4 y solo en Visual Studio 2013 .

Anthony Calambre
fuente
2018. Acabo de comenzar con C ++ e investigué bastante sobre arreglos flexibles. Terminé usando vectores ...
Robert Molina
37

Puede inicializar de forma concisa a vector<string>desde una char*matriz creada estáticamente :

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

Esto copia todas las cadenas, por cierto, por lo que usa el doble de memoria. Puede usar la sugerencia de Will Dean para reemplazar el número mágico 3 aquí con arraysize (str_array), aunque recuerdo que hubo un caso especial en el que esa versión particular de arraysize podría hacer algo malo (lo siento, no puedo recordar los detalles de inmediato) . Pero muy a menudo funciona correctamente.

Además, si está realmente entusiasmado con la cosa de una línea, puede definir una macro variadic para que una sola línea como DEFINE_STR_VEC(strvector, "hi", "there", "everyone");funcione.

Tyler
fuente
Dado que strarrayestá en un encabezado, ¿no violará la regla de una definición?
jww
22

Problemas: no hay forma de obtener la cantidad de cadenas automáticamente (que yo sepa).

Hay una forma estándar de pantano de hacer esto, que muchas personas (incluida MS) definen macros como arraysizepara:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))
Will Dean
fuente
1
Alternativamente, se podría usar algo como esto: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (La palabra clave en línea no es necesaria, pero se usa para documentar la intención de la función. En teoría, un compilador moderno debería poder devolver la función completa, creo.
Justin Time - Reinstate Monica
1
Esto falla para los punteros. El recuento de los elementos de la matriz debe realizarse de forma diferente en C ++.
jww
8

Declare una matriz de cadenas en C ++ como esta: char array_of_strings[][]

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

contendrá 200 cadenas, cada una de las cuales tendrá un tamaño de 8 kb u 8192 bytes.

se usa strcpy(line[i],tempBuffer); para poner datos en la matriz de cadenas.


fuente
Para su información, char array_of_strings [] [] no puede aceptar cadenas de C ++, asegúrese de convertir a char * primero. cplusplus.com/reference/string/string/c_str
Luqmaan
Dado que array_of_stringsestá en un encabezado, ¿no violará la regla de una definición?
jww
7

Una posibilidad es utilizar un puntero NULL como valor de marca:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}
Eclipse
fuente
¿Qué significa char ** en realidad? En java, ¿sería una lista de cadenas?
IAmGroot
1
@Doomsknight: En este caso, sí. En la primera línea defino una matriz de char*. En la memoria, esto se presenta como 3 punteros: uno apunta a "perro", uno apunta a "gato" y el otro se deja NULL. Puedo tomar un puntero a ese primer puntero y obtener char**un puntero a un puntero a char. Cuando incremento eso, muevo el carácter ** para que apunte al siguiente elemento de la lista: un puntero al puntero que apunta a "gato", luego lo vuelvo a incrementar y obtengo un puntero que apunta al puntero NULL, y Sé que he terminado. (
Eclipse
4

Puede usar las funciones beginy endde la biblioteca de rango de Boost para encontrar fácilmente los extremos de una matriz primitiva y, a diferencia de la solución macro, esto dará un error de compilación en lugar de un comportamiento roto si lo aplica accidentalmente a un puntero.

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

Puede usar la sugerencia de Will Dean [ #define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))] para reemplazar el número mágico 3 aquí con arraysize (str_array), aunque recuerdo que hubo un caso especial en el que esa versión particular de arraysize podría hacer algo malo (lo siento, no puedo recordar los detalles inmediatamente). Pero muy a menudo funciona correctamente.

El caso en el que no funciona es cuando la "matriz" es en realidad solo un puntero, no una matriz real. También, debido a la forma en que las matrices son pasados a las funciones (convertido a un puntero al primer elemento), que no funciona a través de llamadas a funciones, incluso si las miradas de la firma como una matriz - some_function(string parameter[])es realmente some_function(string *parameter).

Matthew Crumley
fuente
3

He aquí un ejemplo:

#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"));
}
Sombra2531
fuente
2

En lugar de esa macro, podría sugerir esta:

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 una macro para convertirla en una constante en tiempo de compilación; El resultado de la llamada a la función no es una constante en tiempo de compilación.

2) Sin embargo, no queremos usar una macro porque la macro podría usarse accidentalmente en un puntero. La función solo se puede utilizar en matrices en tiempo de compilación.

Entonces, usamos la definición de la función para hacer que la macro sea "segura"; si la función existe (es decir, tiene un tamaño distinto de cero), usamos la macro como se indicó anteriormente. Si la función no existe devolvemos un valor incorrecto.

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

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

fuente
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 peluca
fuente
1

Puede declarar directamente una matriz de cadenas como string s[100];. Luego, si desea acceder a elementos específicos, puede obtenerlo directamente como s[2][90]. Para propósitos de iteración, tome el tamaño de la cadena usando la s[i].size()función.

kajol jain
fuente