For loop and strlen

K

karthikbalaguru

Hi,
I came across a strange behaviour of 'For Loop'.
Here, to make it clear, I have listed the
strange behaviour in 'Strange_1' and the modified one
that gives the desired output as 'Strange_2'.

In 'Strange_1', the strlen(p1) gives the correct value of
10, but the for loop does not execute for 10 times.
It comes out of 'for loop' after 5th time . But, it was
supposed to come after 10 times.

Strange_1 :
----------------
#include<stdio.h>
int main(void)
{
int i,count=0;
char *p1="abcdefghij";
char *p2="alcmenfoip";
printf("len %d \n",strlen(p1));
for(i=0;i<strlen(p1);i++)
{
if(*p1++ == *p2++)
{
count+=5;
}
else
{
count-=3;
}
}
printf("i = %d count = %d\n",i,count);
}

output -
----------
len 10
i = 5 count = 9

I made a small modification and got the desired output.
But, i am not sure how this 'strlen' is affecting the 'for loop'.
Is the method of calling 'strlen' in 'for statement' an
'Undefined Behaviour' ?

I have listed the changes made under the name 'Strange_2'.
Here, i added a new temporary variable 't' and assigned
the strlen(p1) to it. I replaced the strlen(p1) with 't' and it
worked fine.

Strange_2 :
----------------
#include<stdio.h>
int main(void)
{
int i,count=0;
char *p1="abcdefghij";
char *p2="alcmenfoip";
int t;
t = strlen(p1);
printf("len %d \n",strlen(p1));
for(i=0;i<t;i++)
{
if(*p1++ == *p2++)
{
count+=5;
}
else
{
count-=3;
}
}
printf("i = %d count = %d\n",i,count);
}

output -
------------
len 10
i = 10 count = 2

Any ideas ?

Thx in advans,
Karthik Balaguru
 
J

James Kuyper

karthikbalaguru said:
Hi,
I came across a strange behaviour of 'For Loop'.
Here, to make it clear, I have listed the
strange behaviour in 'Strange_1' and the modified one
that gives the desired output as 'Strange_2'.

In 'Strange_1', the strlen(p1) gives the correct value of
10, but the for loop does not execute for 10 times.
It comes out of 'for loop' after 5th time . But, it was
supposed to come after 10 times.

Strange_1 :
----------------
#include<stdio.h>
int main(void)
{
int i,count=0;
char *p1="abcdefghij";
char *p2="alcmenfoip";
printf("len %d \n",strlen(p1));
for(i=0;i<strlen(p1);i++)
{
if(*p1++ == *p2++)

Each time through the loop you advance p1 forward by one position. As a
result, each time through the loop, strlen(p1) gets smaller by 1. By the
time i==5, strlen(p1) is also 5, so it exits.
I made a small modification and got the desired output.
But, i am not sure how this 'strlen' is affecting the 'for loop'.
Is the method of calling 'strlen' in 'for statement' an
'Undefined Behaviour' ?

No, it's perfectly well defined. At each pass through the loop,
strlen(p1) gives you the length of the string that starts at the
location pointed at by p1, and ends with the next null character.
 
M

Morris Keesan

In 'Strange_1', the strlen(p1) gives the correct value of
10, but the for loop does not execute for 10 times.
It comes out of 'for loop' after 5th time . But, it was
supposed to come after 10 times.

Strange_1 : ....
char *p1="abcdefghij"; ....
for(i=0;i<strlen(p1);i++)
{
if(*p1++ == *p2++)

I've removed everything except the relevant pieces.
In "for(expr1; expr2; expr3)", expr1 gets evaluated once,
before the first time through the loop, and expr2
(ALL of expr2) gets evaluated EACH TIME before executing
the loop body. So the first time, p1 is pointing at the
beginning of the string, and strlen(p1) returns what
you're expecting. Then, the first thing that happens in
the loop body is that p1 and p2 get incremented. This
means that the second time you execute the test, you're
calling (in effect) strlen("bcdefghij"). Then the next
time, after p1 is incremented again, the test is
i < strlen("cdefghij"). It shouldn't be surprising that
the loop body doesn't get executed 10 times.

Even (especially?) if you weren't modifying p1 in the loop,
it would be a bad idea to be calling strlen in the test
expression, because this is rather inefficient. A good
optimizing compiler might generate code which calls strlen
only once, but I wouldn't count on it, and you're confusing
any programmer reading your code, who would wonder why
the code is written as if the return value of strlen might
change.
 
W

William Hughes

Hi,
I came across a strange behaviour of 'For Loop'.
Here, to make it clear, I have listed the
strange behaviour in 'Strange_1' and the modified one
that gives the desired output as 'Strange_2'.

In 'Strange_1', the strlen(p1) gives the correct value of
10, but the for loop does not execute for 10 times.
It comes out of 'for loop' after 5th time . But, it was
supposed to come after 10 times.

As noted by others, your problem is that
you change p1 and hence strlen(p1)

The question is why?

Misplaced optimization?

Did you perhaps start with

for (i=0;i<=strlen(p1);i++) {

if( p1 == p2 )
...

and decide to change the indexing to pointer
arithmetic, thereby introducing a bug?

As noted if you want to optimize anything
remove the strlen
call from the loop condition. Note this also
solves your bug, and allows the use of pointer arithmetic
if it is actually faster.

Also why the "increment count by 5 on a match, decrement by
3 on a mismatch"? Why not keep separate counts of
matched and not_matched and calculate
5*matched - 3*not_matched when you need it.
The method you have chosen is never meaningfully faster[1]
(if at all, plausibly it may be slower if the machine
has special instructions for increment by 1 [2]),
and is much less clear.

- William Hughes

[1] Well, hardly ever

[2] On the DS2K model pi^2 your method is faster.
The model pi^2 has special instructions for increment
by 5 and decrement by 3. To increment by 1 it increments
by 5 twice then decrements by 3 three times.
 
K

karthikbalaguru

Each time through the loop you advance p1 forward by one position. As a
result, each time through the loop, strlen(p1) gets smaller by 1. By the
time i==5, strlen(p1) is also 5, so it exits.


No, it's perfectly well defined. At each pass through the loop,
strlen(p1) gives you the length of the string that starts at the
location pointed at by p1, and ends with the next null character.- Hide quoted text -
Oops. Yes. Got it.
It is funny that it got overlooked.
Thx for that .

Karthik Balaguru
 
B

Barry Schwarz

Hi,
I came across a strange behaviour of 'For Loop'.
Here, to make it clear, I have listed the
strange behaviour in 'Strange_1' and the modified one
that gives the desired output as 'Strange_2'.

In 'Strange_1', the strlen(p1) gives the correct value of
10, but the for loop does not execute for 10 times.
It comes out of 'for loop' after 5th time . But, it was
supposed to come after 10 times.

Strange_1 :
----------------
#include<stdio.h>
int main(void)
{
int i,count=0;
char *p1="abcdefghij";
char *p2="alcmenfoip";
printf("len %d \n",strlen(p1));

In addition to what others have mentioned, strlen returns a size_t
which is unsigned but need not be an int. If your system does not
support the %zu conversion specification, you need to cast the return
value to a type for which you do have a conversion specification.
for(i=0;i<strlen(p1);i++)
{
if(*p1++ == *p2++)
{
count+=5;
}
else
{
count-=3;
}
}
printf("i = %d count = %d\n",i,count);
}

output -
----------
len 10
i = 5 count = 9

I made a small modification and got the desired output.
But, i am not sure how this 'strlen' is affecting the 'for loop'.
Is the method of calling 'strlen' in 'for statement' an
'Undefined Behaviour' ?

I have listed the changes made under the name 'Strange_2'.
Here, i added a new temporary variable 't' and assigned
the strlen(p1) to it. I replaced the strlen(p1) with 't' and it
worked fine.

Strange_2 :
----------------
#include<stdio.h>
int main(void)
{
int i,count=0;
char *p1="abcdefghij";
char *p2="alcmenfoip";
int t;
t = strlen(p1);
printf("len %d \n",strlen(p1));

Why are you calling strlen again. If you had used t, this would not
have the same problem noted above.
 
K

Keith Thompson

Barry Schwarz said:
In addition to what others have mentioned, strlen returns a size_t
which is unsigned but need not be an int.
[...]

I'm sure what you meant to say is that strlen returns a size_t which
is unsigned *and cannot* be an int. Either that, or that it need
not be an unsigned int.
 
K

Keith Thompson

pete said:
Keith said:
In addition to what others have mentioned, strlen returns a size_t
which is unsigned but need not be an int.

[...]

I'm sure what you meant to say is that strlen returns a size_t which
is unsigned *and cannot* be an int. Either that, or that it need
not be an unsigned int.

I think he's saying that size_t may be sufficiently different from int,
such that "%d" might not work for size_t values.

Of course. My point is that the phrase "but need not be an int"
implies that it *could* be an int.
 
H

Herbert Rosenau

Even (especially?) if you weren't modifying p1 in the loop,
it would be a bad idea to be calling strlen in the test
expression, because this is rather inefficient. A good
optimizing compiler might generate code which calls strlen
only once, but I wouldn't count on it, and you're confusing
any programmer reading your code, who would wonder why
the code is written as if the return value of strlen might
change.

Oh, uh! the value of strlen IS changed in each iteration of the loop.
Oh, yea, optimation may occure by unrolling the whole loop.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2R Deutsch ist da!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top