Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #69828 > unrolled thread

Issues with array, strlen, etc

Started byAlla _ <modelling.data@gmail.com>
First post2015-09-07 10:47 -0700
Last post2015-09-08 02:39 -0700
Articles 20 — 12 participants

Back to article view | Back to comp.lang.c


Contents

  Issues with array, strlen, etc Alla _ <modelling.data@gmail.com> - 2015-09-07 10:47 -0700
    Re: Issues with array, strlen, etc James Kuyper <jameskuyper@verizon.net> - 2015-09-07 14:47 -0400
    Re: Issues with array, strlen, etc bartekltg <bartekltg@gmail.com> - 2015-09-07 22:03 +0200
    Re: Issues with array, strlen, etc Paul N <gw7rib@aol.com> - 2015-09-07 13:08 -0700
    Re: Issues with array, strlen, etc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-09-07 22:55 +0100
      Re: Issues with array, strlen, etc Rosario19 <Ros@invalid.invalid> - 2015-09-08 07:59 +0200
        Re: Issues with array, strlen, etc Rosario19 <Ros@invalid.invalid> - 2015-09-08 08:05 +0200
    Re: Issues with array, strlen, etc Barry Schwarz <schwarzb@dqel.com> - 2015-09-07 20:35 -0700
    Re: Issues with array, strlen, etc Alla _ <modelling.data@gmail.com> - 2015-09-08 01:08 -0700
      Re: Issues with array, strlen, etc Keith Thompson <kst-u@mib.org> - 2015-09-08 09:04 -0700
        Re: Issues with array, strlen, etc Alla _ <modelling.data@gmail.com> - 2015-09-10 01:22 -0700
          Re: Issues with array, strlen, etc Richard Heathfield <rjh@cpax.org.uk> - 2015-09-10 09:38 +0100
            Re: Issues with array, strlen, etc Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-09-10 07:34 -0400
              Re: Issues with array, strlen, etc David Brown <david.brown@hesbynett.no> - 2015-09-10 13:47 +0200
                Re: Issues with array, strlen, etc Richard Heathfield <rjh@cpax.org.uk> - 2015-09-10 13:11 +0100
            Re: Issues with array, strlen, etc Keith Thompson <kst-u@mib.org> - 2015-09-10 10:21 -0700
          Re: Issues with array, strlen, etc Geoff <geoff@invalid.invalid> - 2015-09-10 10:42 -0700
    Re: Issues with array, strlen, etc Alla _ <modelling.data@gmail.com> - 2015-09-08 01:11 -0700
      Re: Issues with array, strlen, etc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-09-08 09:51 +0100
        Re: Issues with array, strlen, etc Alla _ <modelling.data@gmail.com> - 2015-09-08 02:39 -0700

#69828 — Issues with array, strlen, etc

FromAlla _ <modelling.data@gmail.com>
Date2015-09-07 10:47 -0700
SubjectIssues with array, strlen, etc
Message-ID<1866812f-e415-44b4-8127-8e21c4a13653@googlegroups.com>
Hello!

I have started working on a new task.
I decided to break the program into
parts and then combine them.

First part should prompt the user for 
a card number; then multiply every other
digit by 2, starting from the number's 
second-to-last digit. (please, bear with
me until I will be able to get rid of 
scanf; for now, please, allow me to 
use it).

I plan to try a few approaches. I think
I am facing not only C programming issues
here, but also issues connected with math.

First approach involves arrays. The program
doesn't do what I thought it should. I post
my thoughts within comments.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char card_number[16];

/** limiting the number of possible inputs by
    16, because it represents the longest card
    number
**/
    int i, digit;
    
    printf ("Please, enter your card number:  \n");
    
    if (scanf ("%16s", card_number) == 1)
    {
        for (i = (strlen(card_number)-1); i >= 0; i -= 1)
        {
            digit = card_number[i] * 2;
            printf ("%i", digit);
        }
    }
/** I have tried to achieve the following: 
    take the last i-th character of the array 
    and subtract 1 character; this will be
    a starting point, i.e. i = (strlen(card_number)-1);

    multiply that character by 2 and store the number
    in variable 'digit'; print that number; start the next
    loop with the array that has 2 digits less comparing to 
    the initial array; do until i = 0. 
    for example:
    4 5 6 7 
    strlen = 4, card_number[4] = 7

    i = (strlen(card_number)-1) will be 6, i.e.
    card_number[3] = 6
    6 * 2 = 12
    print 12

    next iteration of the loop starts from 
    digit 5 (because the first loop ended by
    i = i - 1, hence at 5, which is on the 3d
    position of the array); subtracts 1, and 
    multiplies 4 by 2.
   
    This intention isn't realized. I don't see why.
**/
     
    printf ("\n");
    return 0;
}
Thank you!

[toc] | [next] | [standalone]


#69831

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-09-07 14:47 -0400
Message-ID<55EDDBBF.9020804@verizon.net>
In reply to#69828
On 09/07/2015 01:47 PM, Alla _ wrote:
> Hello!
> 
> I have started working on a new task.
> I decided to break the program into
> parts and then combine them.
> 
> First part should prompt the user for 
> a card number; then multiply every other
> digit by 2, starting from the number's 
> second-to-last digit. (please, bear with
> me until I will be able to get rid of 
> scanf; for now, please, allow me to 
> use it).
> 
> I plan to try a few approaches. I think
> I am facing not only C programming issues
> here, but also issues connected with math.
> 
> First approach involves arrays. The program
> doesn't do what I thought it should. I post
> my thoughts within comments.
> 
> #include <stdio.h>
> #include <string.h>
> 
> int main(void)
> {
>     char card_number[16];
> 
> /** limiting the number of possible inputs by
>     16, because it represents the longest card
>     number
> **/
>     int i, digit;
>     
>     printf ("Please, enter your card number:  \n");
>     
>     if (scanf ("%16s", card_number) == 1)
>     {
>         for (i = (strlen(card_number)-1); i >= 0; i -= 1)
>         {
>             digit = card_number[i] * 2;

Note: if the card number is "9876543210", then filling in the array by
calling scanf() this way is roughly is equivalent to

char card_number[16] = {'9', '8', '7', '6', '5', '4', '3', '2', '1',
'0', '\0'};

The main difference is that, with your code, card_number[11],
card_number[12], card_number[13], card_number[14], card_number[15] all
remain uninitialized. With my replacement code, they would all have
values of 0.

On a typical system that uses ASCII encoding, this will also be
equivalent to

char card_number[16] = {57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 0};

If that's not what you expected, that's probably where your problem is.

The reason is that '9' == 57; ASCII uses a value of 57 to encode the
character '9'. So do most of the other encodings currently in
wide-spread use, but there are exceptions, the most prominent being EBCDIC.

If you read in one digit at a time using scanf("%1.1d",
&card_number[i]), then scanf() will perform the conversion from the
character '5' to integer value 5 for you, so you don't have to worry
about it. It will use the appropriate encoding for your platform,
regardless of whether that is ASCII, UTF-8, EBCDIC, UCS2, Shift-JIS,
UTF-16, or anything else.

[toc] | [prev] | [next] | [standalone]


#69841

Frombartekltg <bartekltg@gmail.com>
Date2015-09-07 22:03 +0200
Message-ID<mskqii$4d1$1@node1.news.atman.pl>
In reply to#69828
On 07.09.2015 19:47, Alla _ wrote:
> Hello!
>
> I have started working on a new task.
> I decided to break the program into
> parts and then combine them.
>
> First part should prompt the user for
> a card number; then multiply every other
> digit by 2, starting from the number's
> second-to-last digit. (please, bear with
> me until I will be able to get rid of
> scanf; for now, please, allow me to
> use it).
>

>
> #include <stdio.h>
> #include <string.h>
>
> int main(void)
> {
>      char card_number[16];
>
> /** limiting the number of possible inputs by
>      16, because it represents the longest card
>      number
> **/
>      int i, digit;
>
>      printf ("Please, enter your card number:  \n");
>
>      if (scanf ("%16s", card_number) == 1)
>      {
>          for (i = (strlen(card_number)-1); i >= 0; i -= 1)
>          {
>              digit = card_number[i] * 2;

card_number[i] is an ASCII code for a character.
https://en.wikipedia.org/wiki/ASCII#ASCII_printable_code_chart
character '0' is represented as _48_.

You have to decode ascii first.
One way is to subtract a code for zero

digit = (card_number[i]-'0') * 2;

Do you know why this works?

>              printf ("%i", digit);

6 times 2 is 12, this is not a digit;-)
The output still looks like gibberish, add space

         printf ("%i ", digit);

bartekltg

[toc] | [prev] | [next] | [standalone]


#69842

FromPaul N <gw7rib@aol.com>
Date2015-09-07 13:08 -0700
Message-ID<2c7e0d58-1527-47be-9c40-c2817a0a455f@googlegroups.com>
In reply to#69828
On Monday, 7 September 2015 18:47:30 UTC+1, Alla _  wrote:
> Hello!
> 
> I have started working on a new task.
> I decided to break the program into
> parts and then combine them.
> 
> First part should prompt the user for 
> a card number; then multiply every other
> digit by 2, starting from the number's 
> second-to-last digit. (please, bear with
> me until I will be able to get rid of 
> scanf; for now, please, allow me to 
> use it).
> 
> I plan to try a few approaches. I think
> I am facing not only C programming issues
> here, but also issues connected with math.
> 
> First approach involves arrays. The program
> doesn't do what I thought it should. I post
> my thoughts within comments.
> 
> #include <stdio.h>
> #include <string.h>
> 
> int main(void)
> {
>     char card_number[16];
> 
> /** limiting the number of possible inputs by
>     16, because it represents the longest card
>     number
> **/
>     int i, digit;
>     
>     printf ("Please, enter your card number:  \n");
>     
>     if (scanf ("%16s", card_number) == 1)
>     {
>         for (i = (strlen(card_number)-1); i >= 0; i -= 1)

Two problems with this line. Firstly, you said you wanted to start with the last but one digit, so your "-1" should be "-2" - see below. And secondly, you said you only wanted to do each alternate digit, so " i -= 1" should be "i -= 2".

>         {
>             digit = card_number[i] * 2;

As James has said, card_number[i] is a char so it contains a value representing a character. You can change it to the actual number by subtracting the value for the character 0, ie (card_number[i] - '0').

>             printf ("%i", digit);
>         }
>     }
> /** I have tried to achieve the following: 
>     take the last i-th character of the array 
>     and subtract 1 character; this will be
>     a starting point, i.e. i = (strlen(card_number)-1);
> 
>     multiply that character by 2 and store the number
>     in variable 'digit'; print that number; start the next
>     loop with the array that has 2 digits less comparing to 
>     the initial array; do until i = 0. 
>     for example:
>     4 5 6 7 
>     strlen = 4, card_number[4] = 7

No, arrays in C are zero-based. card_number[0] is '4'. card_number[3] is '7'. card_number[4] is zero, marking the end of the string.

>     i = (strlen(card_number)-1) will be 6, i.e.
>     card_number[3] = 6
>     6 * 2 = 12
>     print 12
> 
>     next iteration of the loop starts from 
>     digit 5 (because the first loop ended by
>     i = i - 1, hence at 5, which is on the 3d
>     position of the array); subtracts 1, and 
>     multiplies 4 by 2.
>    
>     This intention isn't realized. I don't see why.
> **/
>      
>     printf ("\n");
>     return 0;
> }
> Thank you!

[toc] | [prev] | [next] | [standalone]


#69853

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-09-07 22:55 +0100
Message-ID<87lhchq4h8.fsf@bsb.me.uk>
In reply to#69828
Alla _ <modelling.data@gmail.com> writes:

> Hello!
>
> I have started working on a new task.
> I decided to break the program into
> parts and then combine them.
>
> First part should prompt the user for 
> a card number; then multiply every other
> digit by 2, starting from the number's 
> second-to-last digit. (please, bear with
> me until I will be able to get rid of 
> scanf; for now, please, allow me to 
> use it).
>
> I plan to try a few approaches. I think
> I am facing not only C programming issues
> here, but also issues connected with math.
>
> First approach involves arrays. The program
> doesn't do what I thought it should. I post
> my thoughts within comments.
>
> #include <stdio.h>
> #include <string.h>
>
> int main(void)
> {
>     char card_number[16];
>
> /** limiting the number of possible inputs by
>     16, because it represents the longest card
>     number
> **/
>     int i, digit;
>     
>     printf ("Please, enter your card number:  \n");
>     
>     if (scanf ("%16s", card_number) == 1)

You need 15 there.  scanf must put a null (zero) byte at the end of the
input, and that means reading no more than 15 characters.  You can, of
course, choose to change the array size to 17 instead.

>     {
>         for (i = (strlen(card_number)-1); i >= 0; i -= 1)

You said "every other digit".  Setting i to i-1 will print the next one.

>         {
>             digit = card_number[i] * 2;
>             printf ("%i", digit);
>         }

You are likely to get confused by this output because it will be run
together.  If is see 710 as the output is that one number, or the result
of printing 7 then 1 then 0, or 7 and then 10?  You can't tell.

For now, do something like printf("[%i]", digit); so you can see where
one starts and another ends.  You can remove the []s later.

Also, first, just print the digits without any multiplication and in the
normal order and see if you understand the output.  Post again if you
don't!

   for (i = 0; i < strlen(card_number); ++i) {
       digit = card_number[1];
       printf("[%i]", digit);
   }

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#69864

FromRosario19 <Ros@invalid.invalid>
Date2015-09-08 07:59 +0200
Message-ID<k4usuaptmnii8v9bs9v4mvlnfgn5dria5k@4ax.com>
In reply to#69853
On Mon, 07 Sep 2015 22:55:31 +0100, Ben Bacarisse wrote:

>   for (i = 0; i < strlen(card_number); ++i) {
>       digit = card_number[1];
>       printf("[%i]", digit);
>   }

yes the compiler can optimize etc but i'm more confident on my own
   for(i=0, cardLen=strlen(card_number); i<cardLen; ++i) 
      {digit =card_number[1];
       printf("[%i]", digit);
      }
or something as above

[toc] | [prev] | [next] | [standalone]


#69866

FromRosario19 <Ros@invalid.invalid>
Date2015-09-08 08:05 +0200
Message-ID<5lusuah399e795pndnlptm2omrovqo9jvo@4ax.com>
In reply to#69864
On Tue, 08 Sep 2015 07:59:37 +0200, Rosario19 <Ros@invalid.invalid>
wrote:

>On Mon, 07 Sep 2015 22:55:31 +0100, Ben Bacarisse wrote:
>
>>   for (i = 0; i < strlen(card_number); ++i) {
>>       digit = card_number[1];
>>       printf("[%i]", digit);
>>   }
>
>yes the compiler can optimize etc but i'm more confident on my own
>   for(i=0, cardLen=strlen(card_number); i<cardLen; ++i) 
>      {digit =card_number[1];
>       printf("[%i]", digit);
>      }
>or something as above

yes the compiler can optimize etc but i'm more confident on my own
   for(i=0, cardLen=strlen(card_number); i<cardLen; ++i) 
      {digit =card_number[i];
       printf("[%i]", digit);
      }
or something as above

[toc] | [prev] | [next] | [standalone]


#69861

FromBarry Schwarz <schwarzb@dqel.com>
Date2015-09-07 20:35 -0700
Message-ID<mfqrua9nqer025bvd2lfjcv4rpatuhkoh3@4ax.com>
In reply to#69828
On Mon, 7 Sep 2015 10:47:05 -0700 (PDT), Alla _
<modelling.data@gmail.com> wrote:

>Hello!
>
>I have started working on a new task.
>I decided to break the program into
>parts and then combine them.
>
>First part should prompt the user for 
>a card number; then multiply every other
>digit by 2, starting from the number's 
>second-to-last digit. (please, bear with
>me until I will be able to get rid of 
>scanf; for now, please, allow me to 
>use it).
>
>I plan to try a few approaches. I think
>I am facing not only C programming issues
>here, but also issues connected with math.
>
>First approach involves arrays. The program
>doesn't do what I thought it should. I post
>my thoughts within comments.
>
>#include <stdio.h>
>#include <string.h>
>
>int main(void)
>{
>    char card_number[16];
>
>/** limiting the number of possible inputs by
>    16, because it represents the longest card
>    number
>**/
>    int i, digit;
>    
>    printf ("Please, enter your card number:  \n");
>    
>    if (scanf ("%16s", card_number) == 1)

This allows too many characters.  Since scanf will always add a
terminating '\0',  width specification must be at least one less than
the size of the target.

>    {
>        for (i = (strlen(card_number)-1); i >= 0; i -= 1)
>        {
>            digit = card_number[i] * 2;

You have lost sight of the difference between a character digit and an
integer digit.  If card_number[i] is '2' (the character), then the
result of this arithmetic is not 4 (the integer) and not '4' (the
character) but 'd' which is not an integer or character digit.

>            printf ("%i", digit);
>        }
>    }
>/** I have tried to achieve the following: 
>    take the last i-th character of the array 
>    and subtract 1 character; this will be
>    a starting point, i.e. i = (strlen(card_number)-1);
>
>    multiply that character by 2 and store the number
>    in variable 'digit'; print that number; start the next
>    loop with the array that has 2 digits less comparing to 
>    the initial array; do until i = 0. 
>    for example:
>    4 5 6 7 
>    strlen = 4, card_number[4] = 7
>
>    i = (strlen(card_number)-1) will be 6, i.e.
>    card_number[3] = 6

NO!  card_number[3] = '6' which is a completely different value.

>    6 * 2 = 12
>    print 12
>
>    next iteration of the loop starts from 
>    digit 5 (because the first loop ended by
>    i = i - 1, hence at 5, which is on the 3d
>    position of the array); subtracts 1, and 
>    multiplies 4 by 2.
>   
>    This intention isn't realized. I don't see why.
>**/
>     
>    printf ("\n");
>    return 0;
>}
>Thank you!

-- 
Remove del for email

[toc] | [prev] | [next] | [standalone]


#69876

FromAlla _ <modelling.data@gmail.com>
Date2015-09-08 01:08 -0700
Message-ID<1e5f8717-847a-451c-8e50-7e87115ead51@googlegroups.com>
In reply to#69828
Thank you very much for these explanations.

I have revised the program based on your 
explanations and suggestions.

Bartekltg, yes, I understand (now) what 
happens when '0' is being subtracted :)
Given '0' equals 48, by subtracting '0' 
from any given character I get the correct
digit (integer, not an ascii character). 

#include <stdio.h>
#include <string.h>

int main(void)
{
    char card_number[17];
    int i, number;
    
    printf ("Please, enter your card number:  \n");
    
    if (scanf ("%s", card_number) == 1)
    {
        for (i = (strlen(card_number) - 2); i >= 0; i -= 2)
        {
            number = (card_number[i]-'0') * 2;
            printf (" [%i] ", number);
        }
    }
    printf ("\n");
    return 0;
}

[toc] | [prev] | [next] | [standalone]


#69922

FromKeith Thompson <kst-u@mib.org>
Date2015-09-08 09:04 -0700
Message-ID<lnlhcgsxs9.fsf@kst-u.example.com>
In reply to#69876
Alla _ <modelling.data@gmail.com> writes:
> Thank you very much for these explanations.
>
> I have revised the program based on your explanations and suggestions.
>
> Bartekltg, yes, I understand (now) what happens when '0' is being
> subtracted :) Given '0' equals 48, by subtracting '0' from any given
> character I get the correct digit (integer, not an ascii character).

'0' is equal to 48 only if you're using an ASCII-based character
set, which the standard doesn't guarantee.  For example, EBCDIC
assigns the value 240 to the character '0'.

*However* the C standard guarantees that the character codes for
the digits '0' through '9' have consecutive codes, so subtracting
'0' from a digit *is* give you the value ('9' - '0' == 9 for any
conforming implementation, even if '0' != 48).

Keep in mind that there's no such guarantee for letters; 'z' -
'a' == 25 in ASCII but not in EBCDIC.

[...]
>         for (i = (strlen(card_number) - 2); i >= 0; i -= 2)
>         {
>             number = (card_number[i]-'0') * 2;
>             printf (" [%i] ", number);
>         }
[...]

This evaluates strlen(card_number) each time through the loop, which is
inefficient.  The strlen() function has to scan the entire string to
find the terminating '\0', which can turn an O(N) loop into an O(N**2)
loop.  You probably won't notice the difference for reasonably short
strings, and micro-optimization is *usually* less important than
clarity, but for something like this, it's worth it to save the length
in a variable:

    size_t len = strlen(card_number);
    for (i = len - 2, ...)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#70133

FromAlla _ <modelling.data@gmail.com>
Date2015-09-10 01:22 -0700
Message-ID<061a430f-e33f-4661-a8c5-506bf106c590@googlegroups.com>
In reply to#69922
> This evaluates strlen(card_number) each time through the loop, which is
> inefficient.  The strlen() function has to scan the entire string to
> find the terminating '\0', which can turn an O(N) loop into an O(N**2)
> loop.  You probably won't notice the difference for reasonably short
> strings, and micro-optimization is *usually* less important than
> clarity, but for something like this, it's worth it to save the length
> in a variable:
> 
>     size_t len = strlen(card_number);
>     for (i = len - 2, ...)
> 
Keith, thank you very much. I have revised
parts with strlen. I guess I see the difference; 
please, correct me if I am wrong: if I declare
the length outside the loop, the program will only
once scan through the whole card number to find '\0'
and will compute the length of the card number only once,
then will store that length in the variable 'len'; hence
when further with each iteration of the loop the program
will have to deal only with that defined number, and will
not have to scan through the entire card_number again and 
again.
> -- 
> Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
> Working, but not speaking, for JetHead Development, Inc.
> "We must do something.  This is something.  Therefore, we must do this."
>     -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#70137

FromRichard Heathfield <rjh@cpax.org.uk>
Date2015-09-10 09:38 +0100
Message-ID<MjbIx.485700$8E7.431470@fx29.am4>
In reply to#70133
On 10/09/2015 09:22, Alla _ wrote:
>
>>  This evaluates strlen(card_number) each time through the loop,

No, it doesn't. Keith is wrong. That doesn't happen very often, but it 
happened this time.

>> which is
>>  inefficient.  The strlen() function has to scan the entire string to
>>  find the terminating '\0',

True.

>> which can turn an O(N) loop into an O(N**2)
>>  loop.

Not if the strlen is in the x part of for(x;y;z) which, on this 
occasion, it was.

> Keith, thank you very much. I have revised
> parts with strlen. I guess I see the difference;

That's interesting, because he's wrong. Here's why:

In this loop:

for(x; y; z)
{
   the_loop_body;
}

x is only executed once, at the beginning. y, z, and the_loop_body are 
executed once *per loop iteration*. If your strlen call had been in any 
of those places, Keith would have been perfectly correct. So the lesson 
is still worth learning, even if on this occasion Keith very slightly 
mis-read your code.

> please, correct me if I am wrong: if I declare
> the length outside the loop, the program will only
> once scan through the whole card number to find '\0'
> and will compute the length of the card number only once,
> then will store that length in the variable 'len'; hence
> when further with each iteration of the loop the program
> will have to deal only with that defined number, and will
> not have to scan through the entire card_number again and
> again.

That's the basic idea, yes, and that would have been true with your code 
if you'd written something like:

for(i = 0; i < strlen(s) - 2; i += 2)
     <-x->  <----y---------->  <--z-->

strlen(s) is in the 'y' part. That's the kind of thing Keith was talking 
about. Note the difference between it and your own code, which was 
roughly this:

for (i = (strlen(s) - 2); i >= 0; i -= 2)
      <----- x -------->  <--y--> <--z-->

In your code, strlen() is in the 'x' part, so moving it above the loop 
has no effect on performance.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

[toc] | [prev] | [next] | [standalone]


#70150

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-09-10 07:34 -0400
Message-ID<msrpot$1rm$1@dont-email.me>
In reply to#70137
On 9/10/2015 4:38 AM, Richard Heathfield wrote:
> [...]
> In this loop:
>
> for(x; y; z)
> {
>    the_loop_body;
> }
>
> x is only executed once, at the beginning. y, z, and the_loop_body are
> executed once *per loop iteration*. [...]

     Richard isn't wrong very often, but he's wrong this time.

     x is executed once; Richard is right.

     y is executed either (1) the same number of times as
the_loop_body or (2) one more time than the_loop_body.

     z is executed either (2) the same number of times as
the_loop_body or (1) one fewer time than the_loop_body.

     Case (2) might be considered the "normal" case, when
the loop terminates by the action of the `for' part alone.
In this case, y precedes and z follows each the_loop_body
execution, and y executes one additional time (when it
evaluates to false and stops the loop).

     Case (1) holds when the_loop_body itself terminates the
loop, by executing a `break' or `return' or `goto' or the
like.  In this case, y precedes each the_loop_body execution
and z follows each one except the last.

     Caveat: All the above presumes that none of x,y,z, or
the_loop_body invokes undefined behavior, in which case
there's no telling what might happen.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#70151

FromDavid Brown <david.brown@hesbynett.no>
Date2015-09-10 13:47 +0200
Message-ID<msrqha$4kq$1@dont-email.me>
In reply to#70150
On 10/09/15 13:34, Eric Sosman wrote:
> On 9/10/2015 4:38 AM, Richard Heathfield wrote:
>> [...]
>> In this loop:
>>
>> for(x; y; z)
>> {
>>    the_loop_body;
>> }
>>
>> x is only executed once, at the beginning. y, z, and the_loop_body are
>> executed once *per loop iteration*. [...]
> 
>     Richard isn't wrong very often, but he's wrong this time.
> 
>     x is executed once; Richard is right.
> 
>     y is executed either (1) the same number of times as
> the_loop_body or (2) one more time than the_loop_body.
> 
>     z is executed either (2) the same number of times as
> the_loop_body or (1) one fewer time than the_loop_body.
> 
>     Case (2) might be considered the "normal" case, when
> the loop terminates by the action of the `for' part alone.
> In this case, y precedes and z follows each the_loop_body
> execution, and y executes one additional time (when it
> evaluates to false and stops the loop).
> 
>     Case (1) holds when the_loop_body itself terminates the
> loop, by executing a `break' or `return' or `goto' or the
> like.  In this case, y precedes each the_loop_body execution
> and z follows each one except the last.
> 
>     Caveat: All the above presumes that none of x,y,z, or
> the_loop_body invokes undefined behavior, in which case
> there's no telling what might happen.
> 

You're all wrong!  For a compiler with reasonable optimisation, the
compiler will see that the strlen() call is invariant in the loop, and
lift it outside - it will be executed only once no matter where in the
x, y, z it is given.

/Logically/ you are correct - but if you are trying to measure the
generated behaviour, write fast code, or examine the assembly code, it's
worth remembering the compiler's ability to shuffle things around and
give you fast, efficient object code even though you wrote slow,
inefficient source code.

Richard's approximation (x is done once, while y and z are done once per
iteration) is probably good enough for most purposes.  And moving the
strlen() call outside the loop makes sense even if the compiler is smart
enough to do so automatically - compilers don't always manage such
optimisations.

[toc] | [prev] | [next] | [standalone]


#70153

FromRichard Heathfield <rjh@cpax.org.uk>
Date2015-09-10 13:11 +0100
Message-ID<OreIx.33502$xw.15873@fx22.am4>
In reply to#70151
On 10/09/2015 12:47, David Brown wrote:
> On 10/09/15 13:34, Eric Sosman wrote:
>>  On 9/10/2015 4:38 AM, Richard Heathfield wrote:
>>>  [...]
>>>  In this loop:
>>>
>>>  for(x; y; z)
>>>  {
>>>     the_loop_body;
>>>  }
>>>
>>>  x is only executed once, at the beginning. y, z, and the_loop_body are
>>>  executed once *per loop iteration*. [...]
>>
>>      Richard isn't wrong very often,

You'd be surprised.

>>  but he's wrong this time.
>>
<snip>
>
> You're all wrong!  For a compiler with reasonable optimisation, the
> compiler will see that the strlen() call is invariant in the loop, and
> lift it outside - it will be executed only once no matter where in the
> x, y, z it is given.

You are, of course, wrong. If the loop body contains f(s), this could 
stop the strlen call from being invariant. And the compiler may not even 
be able to see the code of f() to determine whether or not that is the 
case. And in any case, from the OP's point of view, the whole shooting 
match is irrelevant because the strlen is in x, not y, z, or loop_body.

(Eric is also wrong because nobody in their right mind would put a goto, 
a break (except as part of an inner switch), or a return into a loop body.)

> /Logically/ you are correct - but if you are trying to measure the
> generated behaviour, write fast code, or examine the assembly code, it's
> worth remembering the compiler's ability to shuffle things around and
> give you fast, efficient object code even though you wrote slow,
> inefficient source code.
>
> Richard's approximation (x is done once, while y and z are done once per
> iteration) is probably good enough for most purposes.  And moving the
> strlen() call outside the loop makes sense even if the compiler is smart
> enough to do so automatically - compilers don't always manage such
> optimisations.

All good stuff, but you're not going to win any friends telling people 
they're right. :-)

Anyway, I think Keith should have the last word on this little fracas - 
if there is any justice, he'll find a way of telling us we're *all* wrong.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

[toc] | [prev] | [next] | [standalone]


#70183

FromKeith Thompson <kst-u@mib.org>
Date2015-09-10 10:21 -0700
Message-ID<lnmvwunqah.fsf@kst-u.example.com>
In reply to#70137
Richard Heathfield <rjh@cpax.org.uk> writes:
> On 10/09/2015 09:22, Alla _ wrote:
>>
>>>  This evaluates strlen(card_number) each time through the loop,
>
> No, it doesn't. Keith is wrong. That doesn't happen very often, but it 
> happened this time.
[...]
>> Keith, thank you very much. I have revised
>> parts with strlen. I guess I see the difference;
>
> That's interesting, because he's wrong. Here's why:
>
> In this loop:
>
> for(x; y; z)
> {
>    the_loop_body;
> }
>
> x is only executed once, at the beginning. y, z, and the_loop_body are 
> executed once *per loop iteration*. If your strlen call had been in any 
> of those places, Keith would have been perfectly correct. So the lesson 
> is still worth learning, even if on this occasion Keith very slightly 
> mis-read your code.

Oh, crud.  Richard, you are of course absolutely correct.  Alla, sorry
about the confusion.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#70184

FromGeoff <geoff@invalid.invalid>
Date2015-09-10 10:42 -0700
Message-ID<1qd3vat1tdajkber6imo67ilb2q7e0u8h2@4ax.com>
In reply to#70133
On Thu, 10 Sep 2015 01:22:29 -0700 (PDT), Alla _
<modelling.data@gmail.com> wrote:

>Keith, thank you very much. I have revised
>parts with strlen. I guess I see the difference; 
>please, correct me if I am wrong: if I declare
>the length outside the loop, the program will only
>once scan through the whole card number to find '\0'
>and will compute the length of the card number only once,
>then will store that length in the variable 'len'; hence
>when further with each iteration of the loop the program
>will have to deal only with that defined number, and will
>not have to scan through the entire card_number again and 
>again.

Alla _,

There is absolutely no difference in the performance of this loop
whether it's written

         for (i = (strlen(card_number) - 2); i >= 0; i -= 2)
         {
             number = (card_number[i]-'0') * 2;
             printf (" [%i] ", number);
         }

or as

    size_t len = strlen(card_number);
    for (i = len - 2, ; i >= 0; i -= 2)
         {
             number = (card_number[i]-'0') * 2;
             printf (" [%i] ", number);
         }

The only variables that will be modified as the loop executes will be
i and number.

In both cases, strlen(card_number) - 2 is evaluated EXACTLY ONCE at
the beginning of the loop to initialize i, then i, and only i, is
modified to index through the card_number array.

Your original version is preferable. It's shorter, clearer, cleaner
and is written in the fashion of 99% of for() loops of this nature
because it saves the declaration of another variable that is only used
once and ignored thereafter.

[toc] | [prev] | [next] | [standalone]


#69877

FromAlla _ <modelling.data@gmail.com>
Date2015-09-08 01:11 -0700
Message-ID<326d1e2b-aeca-4e1b-8843-76bbb46d7466@googlegroups.com>
In reply to#69828
May I continue asking questions about 
other parts of this program as I include
them? Or shall I start a new thread? I do 
not know if there are any restrictions 
and rules regarding such issues. 
Thank you!

[toc] | [prev] | [next] | [standalone]


#69879

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-09-08 09:51 +0100
Message-ID<8737yppa3s.fsf@bsb.me.uk>
In reply to#69877
Alla _ <modelling.data@gmail.com> writes:

> May I continue asking questions about 
> other parts of this program as I include
> them? Or shall I start a new thread? I do 
> not know if there are any restrictions 
> and rules regarding such issues. 
> Thank you!

I don't think it makes very much difference.  Posting in the same thread
makes it easier to find other versions of the program but that probably
won't matter in this case as the program is short and you can post is
all when asking new questions.

Basically, take your pick.  No one will mind.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#69882

FromAlla _ <modelling.data@gmail.com>
Date2015-09-08 02:39 -0700
Message-ID<1c74da61-5dfb-4342-ac6a-eb9675e61c33@googlegroups.com>
In reply to#69879
On Tuesday, September 8, 2015 at 12:51:43 PM UTC+4, Ben Bacarisse wrote:
> Alla _ <modelling.data@gmail.com> writes:
> 
> > May I continue asking questions about 
> > other parts of this program as I include
> > them? Or shall I start a new thread? I do 
> > not know if there are any restrictions 
> > and rules regarding such issues. 
> > Thank you!
> 
> I don't think it makes very much difference.  Posting in the same thread
> makes it easier to find other versions of the program but that probably
> won't matter in this case as the program is short and you can post is
> all when asking new questions.
> 
> Basically, take your pick.  No one will mind.
> 
> -- 
> Ben.

Thank you!

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web