forma más moderna de recorrer matrices de C++

6 minutos de lectura

avatar de usuario
Lucas

Recientemente encontré muchos ejemplos, la mayoría de ellos relacionados con C ++ 98, de todos modos, he creado mi matriz simple y un bucle (teclado):

#include <iostream>
using namespace std;

int main ()
{
   string texts[] = {"Apple", "Banana", "Orange"};
   for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
   {
       cout << "value of a: " << texts[a] << endl;
   }

   return 0;
}

Producción:

value of a: Apple
value of a: Banana
value of a: Orange

Segmentation fault

Funciona bien, salvo el fallo de segmentación del final.

Mi pregunta es, ¿esta matriz/bucle se realiza de una buena manera? Estoy usando C ++ 11, así que me gustaría estar seguro de que se ajusta a los estándares y no podría hacerse de una mejor manera.

  • Solo usa std::array y es size() función.

    – chris

    27 de noviembre de 2013 a las 5:57

avatar de usuario
Nicu Stiurca

En C/C++ sizeof. siempre da el número de bytes en todo el objeto, y las matrices se tratan como un solo objeto. Nota: sizeof un puntero, al primer elemento de una matriz o a un solo objeto, da el tamaño del puntero, no los objetos señalados. De todas formas, sizeof lo hace no dar el número de elementos en la matriz (su longitud). Para obtener la longitud, debe dividir por el tamaño de cada elemento. p.ej.,

for( unsigned int a = 0; a < sizeof(texts)/sizeof(texts[0]); a = a + 1 )

En cuanto a hacerlo de la manera C ++ 11, la mejor manera de hacerlo es probablemente

for(const string &text : texts)
    cout << "value of text: " << text << endl;

Esto le permite al compilador calcular cuántas iteraciones necesita.

como otros han señalado, std::array se prefiere en C ++ 11 sobre matrices sin formato; sin embargo, ninguna de las otras respuestas abordó por qué sizeof está fallando como está, así que sigo pensando que esta es la mejor respuesta.

  • Para mayor simplicidad, intente for(auto & text : texts)

    – edA-qa mort-ora-y

    27 de noviembre de 2013 a las 7:51

  • @edA-qamort-ora-y o incluso mejor: for(auto &&text: texts)

    – RamblingMad

    9 de diciembre de 2015 a las 5:04

  • Para la primera forma, ¿no funcionará esto solo si todas las cadenas tienen la misma longitud?

    – matemáticas

    3 de diciembre de 2018 a las 20:09

  • @tmath Mis matemáticas deberían funcionar bien con el ejemplo de OP porque cada string objeto es en realidad un tamaño constante, independientemente de la longitud de la cadena encapsulada. en particular un string El objeto es esencialmente solo una estructura con un puntero a los datos y un poco de otros metadatos de tamaño constante.

    – Nicu Stiurca

    26 de febrero de 2019 a las 7:38

  • Tenga en cuenta que esto puede funcionar para C++, pero es peligroso usarlo en C. Funciona en C para matrices declaradas estáticamente que están en la pila, pero no funcionará en una función. En una función, el operador sizeof no conoce toda la matriz y, en cambio, devolverá el tamaño del puntero.

    – jvriesem

    16 abr 2020 a las 20:12

avatar de usuario
Marcos García

string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
    cout << "value of a: " << texts[a] << endl;
}

No. Totalmente una forma incorrecta de iterar a través de una matriz. sizeof(texts) no es igual al número de elementos en la matriz!

Las formas modernas de C++ 11 serían:

  • usar std::array si desea una matriz cuyo tamaño se conozca en tiempo de compilación; o
  • usar std::vector si su tamaño depende del tiempo de ejecución

Luego use range-for al iterar.

#include <iostream>
#include <array>


int main() {
    std::array<std::string, 3> texts = {"Apple", "Banana", "Orange"};
    // ^ An array of 3 elements with the type std::string

    for(const auto& text : texts) {   // Range-for!
        std::cout << text << std::endl;
    }
}

ejemplo en vivo


Usted puede preguntar, ¿cómo es std::array mejor que la vieja matriz C? La respuesta es que tiene la seguridad adicional y las características de otros contenedores de biblioteca estándar, en su mayoría muy parecidos a std::vector. Además, la respuesta es que no tiene las peculiaridades de decaer en punteros y, por lo tanto, perder información de tipo, que, una vez que pierde el tipo de matriz original, no puede usar range-for o std::begin/end en eso.

  • Nota: aún podrían usar el bucle basado en rango con su matriz original.

    – juanchopanza

    27 de noviembre de 2013 a las 6:46

  • no me gusta el std::array enfoque ya que necesito contar los elementos yo mismo. De la manera tradicional, el compilador crea la matriz del tamaño adecuado para mí.

    – edA-qa mort-ora-y

    27 de noviembre de 2013 a las 7:53

  • @ edA-qamort-ora-y Hay una solución para eso.

    – Marcos García

    27 de noviembre de 2013 a las 7:57

  • lo único MAL es su tamaño de cálculo

    – UpAndAdam

    5 sep a las 21:29

sizeof te dice el tamaño de una cosa, no el número de elementos en ella. Una forma más C ++ 11 de hacer lo que está haciendo sería:

#include <array>
#include <string>
#include <iostream>

int main()
{
    std::array<std::string, 3> texts { "Apple", "Banana", "Orange" };
    for (auto& text : texts) {
        std::cout << text << '\n';
    }
    return 0;
}

demostración de ideona: http://ideone.com/6xmSrn

  • ¡Oye, esto es genial! pero probablemente debería explicar qué significa y cómo funciona.

    – cnst

    26 de abril de 2016 a las 23:18

necesita comprender la diferencia entre el operador std::array::size y sizeof(). si desea hacer un bucle en los elementos de la matriz de manera convencional, puede usar std::array::size. esto devolverá la cantidad de elementos en la matriz, pero si desea usar C ++ 11, prefiera el código a continuación

for(const string &text : texts)
    cout << "value of text: " << text << endl;

Si tiene una lista muy corta de elementos que le gustaría manejar, puede usar el std::initializer_list introducido en C++ 11 junto con auto:

#include <iostream>

int main(int, char*[])
{
    for(const auto& ext : { ".slice", ".socket", ".service", ".target" })
        std::cout << "Handling *" << ext << " systemd files" << std::endl;

    return 0;
}

avatar de usuario
Harmen

Qué tal si:

#include <iostream>
#include <array>
#include <algorithm>

int main ()
{
    std::array<std::string, 3> text = {"Apple", "Banana", "Orange"};
    std::for_each(text.begin(), text.end(), [](std::string &string){ std::cout << string << "\n"; });

    return 0;
}

Compila y funciona con C++ 11 y no tiene bucles ‘en bruto’ 🙂

avatar de usuario
stites

sizeof(texts) en mi sistema evaluado a 96: la cantidad de bytes necesarios para la matriz y sus instancias de cadena.

Como se mencionó en otra parte, el sizeof(texts)/sizeof(texts[0]) daría el valor de 3 que esperabas.

¿Ha sido útil esta solución?