BESIDES having to do a bunch of unnecessary iterations in a for loop with strlen doesn't it also produce weird behaviors?

http://www.cprogramming.com/tips/tip/dont-use-strlen-in-a-loop-condition

The documentation uses size_t instead of int. I believe I got weird behaviors when it happened. I didn't write it down when it happened so I can't remember where to look.

http://www.cplusplus.com/reference/cstring/strlen/

rproffitt commented: Hey, I like the question. +6

Dani AI

Generated

Short answer: avoid calling strlen() in the loop condition — cache the length (with the right type) or iterate by pointer/iterator. strlen() returns a size_t and computes the length by scanning until the terminating NUL, so each call is linear in the string length; calling it once per iteration makes the overall work quadratic for long strings. Compilers can sometimes inline or hoist a strlen() call when they can prove the buffer won’t change, but that optimization is not something to rely on in general. (en.cppreference.com)

Agree with and : cache the length in a size_t, not an int, to avoid signed/unsigned surprises and truncation when the length doesn’t fit in int. Use -Wall -Wextra so the compiler warns about risky signed/unsigned comparisons. If the loop body can change the string (or other functions you call might), do not cache the length — recompute or redesign the loop. (en.cppreference.com)

Practical examples (safe, small, and different from the snippets already posted):

/* C: cache in the correct type and cast chars for tolower */
size_t len = strlen(s);
for (size_t i = 0; i < len; ++i)
    s[i] = (char)tolower((unsigned char)s[i]);
/* C: pointer-style loop avoids any repeated strlen calls */
for (char *p = s; *p; ++p)
    *p = (char)tolower((unsigned char)*p);
/* C++: prefer std::string + algorithms */
std::transform(s.begin(), s.end(), s.begin(),
               [](unsigned char c){ return static_cast<char>(std::tolower(c)); });

Always cast char to unsigned char before calling tolower() to avoid undefined behavior for negative char values, and prefer std::string::size() / std::transform() in C++ when appropriate. These recommendations address the common causes of the “weird” behavior people report (signed/unsigned comparisons, UB from tolower, or modifying the buffer while measuring its length). (en.cppreference.com)

Recommended Answers

All 3 Replies

One of my rules is that you NEVER use a function as the terminating condition in a loop. This is only necessary if the output of that function may change during the loop. In this case, it does not, so do this instead (taken from the cplusplus.com article:

for ( int ix = 0, jx = strlen(a_str); ix < jx; ix++)
{
     a_str[ix] = tolower( (unsigned char) a_str[ix] );
}

I agree with rubberman. A function in a loop just wastes time if you evrey time through the loop, want the same value from it. I would call it before the loop

int length = strlen(a_str);
for ( int ix = 0, ix < length;  ix++)
{
     a_str[ix] = tolower( (unsigned char) a_str[ix] );
}

And if you want to avoid it alltogether use

int i=0;  
while (a_str[i])
{  
    a_str[i] = tolower((unsigned char)a_str[i]);
    i++;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.