0

In a given loop eg:

for(int i=0 ; i < strlen(s) ; i++){
    //do something
}

Is the strlen(s) calculated for every iteration of the loop? How do the C and C++ languages handle this? If this function call is going to be made for every iteration and we know beforehand that the result from the function will be constant, is it more efficient to store this value in a variable? eg.:

int length = strlen(s);
for(int i=0 ; i< length ; i++){
    //do something
}
Nitin Labhishetty
  • 1,290
  • 2
  • 21
  • 41
  • 1
    Yes. It does. Yes. It is more efficient. – Spikatrix Sep 14 '14 at 13:02
  • 2
    Also, be aware that many compilers (including gcc) can optimize the code by caching the result of `strlen`. But, it's not a good practice to rely on that. – Arjun Sreedharan Sep 14 '14 at 13:28
  • If "the result from the function will be constant" is because you run this loop on a constant string, you could omit the entire `strlen` and replace it with a constant value. (Just to point out that "it depends"...) – Jongware Sep 14 '14 at 13:42
  • @Jongware Some compilers optimize `strlen` on literals. – fredoverflow Sep 14 '14 at 14:58

3 Answers3

3

Yes, strlen(s) will be evaluated on each iteration.

If you won't be changing the string in the loop, it is better (faster) to store the value in and then include it in the for loop.

Fastest way to do this is:

for(int i=0, length = strlen(s) ; i< length ; i++){
    //do something
}
Igor Pejic
  • 3,658
  • 1
  • 14
  • 32
  • 1
    "Fastest" ... if you check for the terminating 0 you don't need a `strlen` at all. How big is the difference? `strlen` checks each character once, and so it would be the same if you did it yourself - apart from the function call. – Jongware Sep 14 '14 at 13:36
  • @Jongware Faster to calculate strlen only once than to calculate it on each iteration, is what I meant. – Igor Pejic Sep 14 '14 at 13:38
2

Is the strlen(s) calculated for every iteration of the loop?

Yes.

is it more efficient to store this value in a variable?

Yes. Calling a function on each iteration and its stack maintenance results in some extra overhead.

haccks
  • 104,019
  • 25
  • 176
  • 264
0

In C++ 11:

template<class T>
struct array_view {
  T*b=nullptr;
  T*e=nullptr;
  T*begin()const{return b;}
  T*end()const{return e;}
  std::size_t size()const{return e-b;}
  bool empty()const{return size()==0;}
  T&operator[](std::size_t i)const{return b[i];}
};

which is a simple little class. Some helpers to make it:

template<class T>
array_view<T> view(T* b,T* e){return {b,e};}
template<class T>
array_view<T> view(T* b,std::size_t l){return {b,b+l};}
template<class T, unsigned N>
array_view<T> view(T(&a)[N]){return view(&a[0],N};}
template<class T, unsigned N>
array_view<T> view(std::array<T,N>& a){return view(&a[0],N};}
template<class T, unsigned N>
array_view<const T> view(std::array<T,N>const& a){return view(&a[0],N};}
template<class T, class...Xs>
array_view<T> view(std::vector<T,Xs...>& v){return view(v.data(),v.size()};}
template<class T, class...Xs>
array_view<const T> view(std::basic_string<T,Xs...>const & v){return view(v.data(),v.size()};}
template<class T, class...Xs>
array_view<T> view(std::vector<T,Xs...>& v){return view(v.data(),v.size()};}
template<class T, class...Xs>
array_view<const T> view(std::basic_string<T,Xs...>const & v){return view(v.data(),v.size()};}

and finally:

array_view<char> view(char*str){return view(str, strlen(str));}
array_view<char const> view(char const*str){return view(str, strlen(str));}

now we can do this:

for(char& c:view(str)){
  // code
}

and get the index via &c-str if we need it.

There is one more more efficient approach: use sentinals and pointer-to-index to avoid calculating the length prior to hitting the end.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524