90

Recently I have found a lot of examples, most of them regards the C++ 98, anyways I have created my simple-array and a loop (codepad):

#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;
}

Output:

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

Segmentation fault

It's working fine, except the segmentation fault at the end.

My question is, does this array/loop through is done a good way? I am using C++ 11 so would like to be sure it fits the standards and couldnt be done a better way?

UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
Lucas
  • 3,517
  • 13
  • 46
  • 75

11 Answers11

130

In C/C++ sizeof. always gives the number of bytes in the entire object, and arrays are treated as one object. Note: sizeof a pointer--to the first element of an array or to a single object--gives the size of the pointer, not the object(s) pointed to. Either way, sizeof does not give the number of elements in the array (its length). To get the length, you need to divide by the size of each element. eg.,

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

As for doing it the C++11 way, the best way to do it is probably

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

This lets the compiler figure out how many iterations you need.

as others have pointed out, std::array is preferred in C++11 over raw arrays; however, none of the other answers addressed why sizeof is failing the way it is, so I still think this is the better answer.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Nicu Stiurca
  • 8,747
  • 8
  • 40
  • 48
  • 14
    For added simplicity try `for(auto & text : texts)` – edA-qa mort-ora-y Nov 27 '13 at 07:51
  • @edA-qamort-ora-y or even better: `for(auto &&text: texts)` – RamblingMad Dec 09 '15 at 05:04
  • For the first way, won't this only work if all the strings are of the same length? – tmath Dec 03 '18 at 20:09
  • 1
    @tmath My math should work fine with OP's example because each `string` object is actually a constant size regardless of the length of the encapsulated string. In particular a `string` object is essentially just a struct with a _pointer_ to the data, and a bit of other constant-size metadata. – Nicu Stiurca Feb 26 '19 at 07:38
  • Note, this may work for C++, but this is dangerous to use in C. It works in C for statically-declared arrays that are on the stack, but will not work in a function. In a function, the sizeof operator does not know about the whole array, and instead will return the size of the pointer. – jvriesem Apr 16 '20 at 20:12
  • @RamblingMad Can you explain why this is better? – tjhorner Jun 15 '22 at 21:58
31
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
    cout << "value of a: " << texts[a] << endl;
}

Nope. Totally a wrong way of iterating through an array. sizeof(texts) is not equal to the number of elements in the array!

The modern, C++11 ways would be to:

  • use std::array if you want an array whose size is known at compile-time; or
  • use std::vector if its size depends on runtime

Then use range-for when iterating.

#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;
    }
}

Live example


You may ask, how is std::array better than the ol' C array? The answer is that it has the additional safety and features of other standard library containers, mostly closely resembling std::vector. Further, The answer is that it doesn't have the quirks of decaying to pointers and thus losing type information, which, once you lose the original array type, you can't use range-for or std::begin/end on it.

Mark Garcia
  • 17,424
  • 4
  • 58
  • 94
14

sizeof tells you the size of a thing, not the number of elements in it. A more C++11 way to do what you are doing would be:

#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;
}

ideone demo: http://ideone.com/6xmSrn

kfsone
  • 23,617
  • 2
  • 42
  • 74
  • 4
    hey, this is awesome! but should probably explain what it means and how it works. – cnst Apr 26 '16 at 23:18
3

you need to understand difference between std::array::size and sizeof() operator. if you want loop to array elements in conventional way then you could use std::array::size. this will return number of elements in array but if you keen to use C++11 then prefer below code

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

If you have a very short list of elements you would like to handle, you could use the std::initializer_list introduced in C++11 together with 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;
}
Phidelux
  • 2,043
  • 1
  • 32
  • 50
2

How about:

#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;
}

Compiles and works with C++ 11 and has no 'raw' looping :)

Harmen
  • 51
  • 5
1

sizeof(texts) on my system evaluated to 96: the number of bytes required for the array and its string instances.

As mentioned elsewhere, the sizeof(texts)/sizeof(texts[0]) would give the value of 3 you were expecting.

stites
  • 4,903
  • 5
  • 32
  • 43
bvj
  • 3,294
  • 31
  • 30
1

Add a stopping value to the array:

#include <iostream>
using namespace std;

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

   return 0;
}
0
In my point of view:
It is because the sizeof() operator returns the size 
of a type in bytes.
So, Simply we can use size() instead of sizeof(). If 
we need or must use sizeof() we have to divide it 
with sizeof(dataType):


First way:
#include <iostream>
using namespace std;

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

   return 0;
  }

Second way:
#include <iostream>
using namespace std;

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

 return 0;
}
-1

Feels like illegal but this works:

So basically it is dynamic multidimensional array iteration termination case and it differs a bit from one dimensional solution, last element is -1 and it is stop value for cycle (I am new to C++ but this method me likes)

int arr[][3] = {{164, 0, 0}, {124, 0, 0}, {92, 4, 0}, {68, 4, 0}, -1};

for(int i = 0; arr[i][0]!=-1; i++)
{
    cout << i << "\n";
}
BIOHAZARD
  • 1,937
  • 20
  • 23
  • except what if -1 is actually a value used? This is a horrible practice and extremely brittle, also this wont even compile as -1 is not an aaray of size 3. – UpAndAdam Sep 05 '22 at 21:31
  • @UpAndAdam it compiles, it is dirty solution but works and will never collide with -1 so basically -1 is artificial breakpoint in the array while looping – BIOHAZARD Feb 14 '23 at 21:20
  • so what is at arr[5][0] arr[5][1] and arr[5][2] ? you are just inserting a {-1,-1,-1} element in to the data and deciding that is a sentinal when you have no knowledge that is a safe sentinel value. It's not modern C++11 and doesn't apply generally (if using other data or other types of elements, what if type was unsigned or a massive dataset?) this is nothing more than a brittle hack you admit is dirty and only fits into your contrived variant example. What if negative numbers were in the dataset? It's not a dynamic multidimensional array either the length is set at compile time. – UpAndAdam May 05 '23 at 16:05
-2

You can do it as follow:

#include < iostream >

using namespace std;

int main () {

   string texts[] = {"Apple", "Banana", "Orange"};

   for( unsigned int a = 0; a < sizeof(texts) / 32; a++ ) { // 32 is the size of string data type

       cout << "value of a: " << texts[a] << endl;

   }


   return 0;

}
Cody Piersall
  • 8,312
  • 2
  • 43
  • 57