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


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

while loop condition doesn't work

Started byAlla _ <modelling.data@gmail.com>
First post2017-01-20 01:24 -0800
Last post2017-01-21 05:36 -0800
Articles 20 on this page of 42 — 10 participants

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


Contents

  while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 01:24 -0800
    Re: while loop condition doesn't work mark.bluemel@gmail.com - 2017-01-20 03:29 -0800
    Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-20 12:19 +0000
      Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 05:12 -0800
        Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-20 13:17 +0000
          Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 05:20 -0800
          Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-20 15:07 +0000
      Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 05:31 -0800
        Re: while loop condition doesn't work Manfred <noname@invalid.add> - 2017-01-20 15:23 +0100
        Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-20 15:16 +0000
          Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 07:45 -0800
            Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-20 16:06 +0000
              Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 08:37 -0800
              Re: while loop condition doesn't work David Brown <david.brown@hesbynett.no> - 2017-01-20 17:54 +0100
                Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-20 17:04 +0000
                  Re: while loop condition doesn't work David Brown <david.brown@hesbynett.no> - 2017-01-20 19:08 +0100
                  Re: while loop condition doesn't work Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-30 12:51 -0800
                    Re: while loop condition doesn't work Keith Thompson <kst-u@mib.org> - 2017-01-30 14:09 -0800
                      Re: while loop condition doesn't work supercat@casperkitty.com - 2017-01-30 14:57 -0800
                      Re: while loop condition doesn't work Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-01 21:31 -0800
                        Re: while loop condition doesn't work Keith Thompson <kst-u@mib.org> - 2017-02-02 10:01 -0800
                          Re: while loop condition doesn't work Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-04 00:22 -0800
                Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-20 19:12 +0000
                  Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-23 10:54 +0000
              Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 23:22 -0800
                Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-23 11:02 +0000
              Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-21 01:22 -0800
                Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-21 11:00 +0000
                  Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-21 08:35 -0800
                    Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-21 17:17 +0000
                      Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-21 09:32 -0800
            Re: while loop condition doesn't work Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-20 19:16 +0000
              Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-23 11:03 +0000
      Re: while loop condition doesn't work David Brown <david.brown@hesbynett.no> - 2017-01-20 14:34 +0100
        Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 07:40 -0800
          Re: while loop condition doesn't work Richard Heathfield <rjh@cpax.org.uk> - 2017-01-20 15:47 +0000
            Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 08:26 -0800
              Re: while loop condition doesn't work David Brown <david.brown@hesbynett.no> - 2017-01-20 18:01 +0100
                Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 09:26 -0800
                  Re: while loop condition doesn't work David Brown <david.brown@hesbynett.no> - 2017-01-20 19:02 +0100
                    Re: while loop condition doesn't work Alla _ <modelling.data@gmail.com> - 2017-01-20 10:13 -0800
                      Re: while loop condition doesn't work Malcolm McLean <malcolm.mclean5@btinternet.com> - 2017-01-21 05:36 -0800

Page 1 of 3  [1] 2 3  Next page →


#102211 — while loop condition doesn't work

FromAlla _ <modelling.data@gmail.com>
Date2017-01-20 01:24 -0800
Subjectwhile loop condition doesn't work
Message-ID<750784a4-22dc-44ef-8972-34d4fb048b00@googlegroups.com>
Hello!

Please, help me to understand why a very simple while loop 
condition doesn't work - it doesn't stop the loop when I 
expect it to stop. 
Please, take a look at the piece of code, and my explanation
of how I intended it to perform:

Input:
1062,1252,1587,1934,2519

Count starts at 5.

double number_1 = strtod(ptr, &not_converted);
    if (not_converted > ptr)
    {
        double number_2 = 0;
    
        while(not_converted > ptr && (!isspace(*not_converted)
                                 || *not_converted != '\0'))
        {
            ptr = not_converted + 1;
            number_2 = strtod(ptr, &not_converted);
            count--;
        }
        if(count != 1)
            return false;
    }
Explanation:
(1) before the loop number_1 = 1062, and 
not_converted is ",1252,1587,1934,2519"
(2) not_converted is bigger than ptr, and not_converted
doesn't point to any space character or '\0';
so the loop starts;
(3) ptr at the beginning of the loop is set to "1252,1587,1934,2519";
number_2 = 1252
not_converted points to ",1587,1934,2519"
count = 4
(4)  ptr at the beginning of the loop is set to "1587,1934,2519";
number_2 = 1587
not_converted points to ",1934,2519"
count = 3
(5) ptr at the beginning of the loop is set to "1934,2519";
number_2 = 1934
not_converted points to ",2519"
count = 2
(6) ptr at the beginning of the loop is set to "2519";
number_2 = 2519
not_converted points to "space character"
count = 1
As not_converted points to space, the loop should terminate,
hence the number_2 should be 2519 and count should also 
stay 1. But the loop doesn't terminate, and makes one more 
iteration. 
The hex dump of the full line (it also contains the name 
before numbers; but the name is left behind when the program
starts executing the code above) reveals two newline characters,
which should be detected by isspace():
53 61 6C 65 73 2C 31 30 36 32 2C 31 32 35 32 2C
31 35 38 37 2C 31 39 33 34 2C 32 35 31 39 0D 0A

Thank you!






[toc] | [next] | [standalone]


#102216

Frommark.bluemel@gmail.com
Date2017-01-20 03:29 -0800
Message-ID<b63925af-2cec-465f-b3b9-701c9bf1e28b@googlegroups.com>
In reply to#102211
On Friday, 20 January 2017 09:24:10 UTC, Alla _  wrote:
> Hello!
> 
> Please, help me to understand why a very simple while loop 
> condition doesn't work - it doesn't stop the loop when I 
> expect it to stop. 
> Please, take a look at the piece of code, and my explanation
> of how I intended it to perform:
> 
> Input:
> 1062,1252,1587,1934,2519
> 
> Count starts at 5.
> 
> double number_1 = strtod(ptr, &not_converted);
>     if (not_converted > ptr)
>     {
>         double number_2 = 0;
>     
>         while(not_converted > ptr && (!isspace(*not_converted)
>                                  || *not_converted != '\0'))
>         {
>             ptr = not_converted + 1;
>             number_2 = strtod(ptr, &not_converted);
>             count--;
>         }
>         if(count != 1)
>             return false;
>     }

Consider this part of your test (which is, IMHO, pretty loathesome) :-

(!isspace(*not_converted) || *not_converted != '\0')

If not_converted points to (say) newline, then
  "isspace(*not_coverted)" is true
so
  "!isspace(*not_coverted)" is false

So the second part of the test is evaluated :-
  "*not_converted != '\0'" is true
so the whole of the bracketed expression is true, so we continue.

You probably want && in place of ||, but I'd be looking for a clearer way to express my intent.

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


#102217

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-01-20 12:19 +0000
Message-ID<871svxdiu9.fsf@bsb.me.uk>
In reply to#102211
Alla _ <modelling.data@gmail.com> writes:

> Please, help me to understand why a very simple while loop 
> condition doesn't work - it doesn't stop the loop when I 
> expect it to stop. 
> Please, take a look at the piece of code, and my explanation
> of how I intended it to perform:
>
> Input:
> 1062,1252,1587,1934,2519
>
> Count starts at 5.
>
> double number_1 = strtod(ptr, &not_converted);
>     if (not_converted > ptr)
>     {
>         double number_2 = 0;
>     
>         while(not_converted > ptr && (!isspace(*not_converted)
>                                  || *not_converted != '\0'))
>         {
>             ptr = not_converted + 1;
>             number_2 = strtod(ptr, &not_converted);
>             count--;
>         }
>         if(count != 1)
>             return false;
>     }
> Explanation:
> (1) before the loop number_1 = 1062, and 
> not_converted is ",1252,1587,1934,2519"
> (2) not_converted is bigger than ptr, and not_converted
> doesn't point to any space character or '\0';

That's not what your test does.  Please, please, please, if you take
nothing else from my coaching, always negate a while condition to see
what it is you are trying to establish:

 while(nc > ptr && (!isspace(*nc) || *nc != '\0')) ...

is trying to make the condition false.  It stops when

     !(nc > ptr  &&  (!isspace(*nc) ||   *nc != '\0'))
  == !(nc > ptr) || !(!isspace(*nc) ||   *nc != '\0')
  ==   nc <= ptr || (!!isspace(*nc) && !(*nc != '\0'))
  ==   nc <= ptr ||   (isspace(*nc) &&   *nc == '\0')
  ==   nc <= ptr || 0
  ==   nc <= ptr

I've urged you to do this on several occasions.  Do it every time you
write a loop until you can do it without thinking.  (It's complicated by
break, but you should be avoiding break.)

The main logic rules involved are called De Morgan's laws:

  !(A && B) => !A || !B
  !(A || B) => !A && !B

<snip>

On another issue, a well-structured program to read numbers and checking
how many there are will have a call to strtod in only one place.

-- 
Ben.

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


#102221

FromAlla _ <modelling.data@gmail.com>
Date2017-01-20 05:12 -0800
Message-ID<fc3ad7a9-282a-4831-85e6-fcec02b2d821@googlegroups.com>
In reply to#102217
On Friday, January 20, 2017 at 3:19:58 PM UTC+3, Ben Bacarisse wrote:
> Alla _ <modelling.data@gmail.com> writes:
> 
> > Please, help me to understand why a very simple while loop 
> > condition doesn't work - it doesn't stop the loop when I 
> > expect it to stop. 
> > Please, take a look at the piece of code, and my explanation
> > of how I intended it to perform:
> >
> > Input:
> > 1062,1252,1587,1934,2519
> >
> > Count starts at 5.
> >
> > double number_1 = strtod(ptr, &not_converted);
> >     if (not_converted > ptr)
> >     {
> >         double number_2 = 0;
> >     
> >         while(not_converted > ptr && (!isspace(*not_converted)
> >                                  || *not_converted != '\0'))
> >         {
> >             ptr = not_converted + 1;
> >             number_2 = strtod(ptr, &not_converted);
> >             count--;
> >         }
> >         if(count != 1)
> >             return false;
> >     }
> > Explanation:
> > (1) before the loop number_1 = 1062, and 
> > not_converted is ",1252,1587,1934,2519"
> > (2) not_converted is bigger than ptr, and not_converted
> > doesn't point to any space character or '\0';
> 
> That's not what your test does.  Please, please, please, if you take
> nothing else from my coaching, always negate a while condition to see
> what it is you are trying to establish:
> 
>  while(nc > ptr && (!isspace(*nc) || *nc != '\0')) ...
> 
> is trying to make the condition false.  It stops when
> 
>      !(nc > ptr  &&  (!isspace(*nc) ||   *nc != '\0'))
>   == !(nc > ptr) || !(!isspace(*nc) ||   *nc != '\0')
>   ==   nc <= ptr || (!!isspace(*nc) && !(*nc != '\0'))
>   ==   nc <= ptr ||   (isspace(*nc) &&   *nc == '\0')
>   ==   nc <= ptr || 0
>   ==   nc <= ptr
> 
> I've urged you to do this on several occasions.  Do it every time you
> write a loop until you can do it without thinking.  (It's complicated by
> break, but you should be avoiding break.)
> 
> The main logic rules involved are called De Morgan's laws:
> 
>   !(A && B) => !A || !B
>   !(A || B) => !A && !B
> 
Yes. I have experienced a mental block. 
Sad, though, to read "if you take nothing else 
from my coaching". Is everything that bad?
Well, I can answer this myself:  I know
it is, but we have only started, and it was not enough
for good habits to develop and establish themselves. 

> <snip>
> 
> On another issue, a well-structured program to read numbers and checking
> how many there are will have a call to strtod in only one place.
Ok... Going back to rethink that piece. But. I am not checking how many
there, I am finding and storing the last one - I need only the first and 
the last one in the line. 
> 
> -- 
> Ben.

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


#102223

FromRichard Heathfield <rjh@cpax.org.uk>
Date2017-01-20 13:17 +0000
Message-ID<o5t2i9$44d$4@dont-email.me>
In reply to#102221
On 20/01/17 13:12, Alla _ wrote:

> Sad, though, to read "if you take nothing else
> from my coaching". Is everything that bad?

I don't think he means that. I think he means that the advice he gave 
you about negating every condition to verify that it's doing what you 
think it's doing is the most important advice he has ever given you. 
Therefore, whatever else you might learn from him, be sure to learn THAT.

-- 
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]


#102224

FromAlla _ <modelling.data@gmail.com>
Date2017-01-20 05:20 -0800
Message-ID<78c2de2d-1438-4cac-9fe1-ef39c0d10fd1@googlegroups.com>
In reply to#102223
On Friday, January 20, 2017 at 4:17:37 PM UTC+3, Richard Heathfield wrote:
> On 20/01/17 13:12, Alla _ wrote:
> 
> > Sad, though, to read "if you take nothing else
> > from my coaching". Is everything that bad?
> 
> I don't think he means that. I think he means that the advice he gave 
> you about negating every condition to verify that it's doing what you 
> think it's doing is the most important advice he has ever given you. 
> Therefore, whatever else you might learn from him, be sure to learn THAT.
> 
Understood. Thank you!

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


#102233

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-01-20 15:07 +0000
Message-ID<87vat9bwia.fsf@bsb.me.uk>
In reply to#102223
Richard Heathfield <rjh@cpax.org.uk> writes:

> On 20/01/17 13:12, Alla _ wrote:
>
>> Sad, though, to read "if you take nothing else
>> from my coaching". Is everything that bad?
>
> I don't think he means that. I think he means that the advice he gave
> you about negating every condition to verify that it's doing what you
> think it's doing is the most important advice he has ever given
> you. Therefore, whatever else you might learn from him, be sure to
> learn THAT.

Yes, exactly.

-- 
Ben.

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


#102226

FromAlla _ <modelling.data@gmail.com>
Date2017-01-20 05:31 -0800
Message-ID<e9b02777-9542-4e5b-bbf7-885c9bbcb5da@googlegroups.com>
In reply to#102217
On Friday, January 20, 2017 at 3:19:58 PM UTC+3, Ben Bacarisse wrote:
> Alla _ <modelling.data@gmail.com> writes:
> 
<snip>
> 
> On another issue, a well-structured program to read numbers and checking
> how many there are will have a call to strtod in only one place.
> 
Here how it looks now - I have to think how to eliminate the call to strtod:

/** Function to compute CAGR **/
bool gr_rate(char *line, struct assumptions *rates)
{
    char *ptr = line;
    char *not_converted = NULL;
    int count = DATA_SIZE;
    double number_1 = strtod(ptr, &not_converted);
    double number_2 = 0;
    if (not_converted > ptr)
    {
        while(not_converted > ptr && !isspace(*not_converted))
        {
            if(*not_converted != '\0')
            {
                ptr = not_converted + 1;
                number_2 = strtod(ptr, &not_converted);
                count--;
            }
        }
        if(count != 1)
           return false;
        rates->gr_sales = pow((number_2/number_1), (1.0/DATA_SIZE));
        return true;
    }
    return false;
}

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


#102231

FromManfred <noname@invalid.add>
Date2017-01-20 15:23 +0100
Message-ID<o5t6gc$lrs$1@gioia.aioe.org>
In reply to#102226
On 1/20/2017 2:31 PM, Alla _ wrote:
> On Friday, January 20, 2017 at 3:19:58 PM UTC+3, Ben Bacarisse wrote:
> <snip>
>> On another issue, a well-structured program to read numbers and checking
>> how many there are will have a call to strtod in only one place.
Excellent advice.
>>
> Here how it looks now - I have to think how to eliminate the call to strtod:
A hint about this (hope this helps): usage of strtod requires checking 
that the scan termination (*endptr) is larger than the start of the 
string; which can be checked only after executing strtod itself.
Therefore I would think of one of the following:
- use a do-while loop
- use a comma operator (less obvious, more compact)

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


#102234

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-01-20 15:16 +0000
Message-ID<87pojhbw2h.fsf@bsb.me.uk>
In reply to#102226
Alla _ <modelling.data@gmail.com> writes:

> On Friday, January 20, 2017 at 3:19:58 PM UTC+3, Ben Bacarisse wrote:
>> Alla _ <modelling.data@gmail.com> writes:
>> 
> <snip>
>> 
>> On another issue, a well-structured program to read numbers and checking
>> how many there are will have a call to strtod in only one place.
>> 
> Here how it looks now - I have to think how to eliminate the call to strtod:
>
> /** Function to compute CAGR **/
> bool gr_rate(char *line, struct assumptions *rates)

This looks odd.  Why is it computing something so specific?  You will
want to read 5 numbers on every line so surely there will be a function
to read 5 numbers.  The various calculations will then be separate
functions that are passed the numbers in an array.

> {
>     char *ptr = line;
>     char *not_converted = NULL;
>     int count = DATA_SIZE;
>     double number_1 = strtod(ptr, &not_converted);
>     double number_2 = 0;
>     if (not_converted > ptr)
>     {
>         while(not_converted > ptr && !isspace(*not_converted))

Why are you interested in non-spaces?  Nothing in your specification
seems to need non-spaces.  Can you write out what the input should look
like in general?  I.e. what will you permit and what won't you permit?

<snip>
-- 
Ben.

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


#102236

FromAlla _ <modelling.data@gmail.com>
Date2017-01-20 07:45 -0800
Message-ID<d4616907-128c-442d-b29e-82bf47b4e83d@googlegroups.com>
In reply to#102234
On Friday, January 20, 2017 at 6:17:01 PM UTC+3, Ben Bacarisse wrote:
> Alla _ <modelling.data@gmail.com> writes:
> 
> > On Friday, January 20, 2017 at 3:19:58 PM UTC+3, Ben Bacarisse wrote:
> >> Alla _ <modelling.data@gmail.com> writes:
> >> 
> > <snip>
> >> 
> >> On another issue, a well-structured program to read numbers and checking
> >> how many there are will have a call to strtod in only one place.
> >> 
> > Here how it looks now - I have to think how to eliminate the call to strtod:
> >
> > /** Function to compute CAGR **/
> > bool gr_rate(char *line, struct assumptions *rates)
> 
> This looks odd.  Why is it computing something so specific?  You will
> want to read 5 numbers on every line so surely there will be a function
> to read 5 numbers.  The various calculations will then be separate
> functions that are passed the numbers in an array.
> 
> > {
> >     char *ptr = line;
> >     char *not_converted = NULL;
> >     int count = DATA_SIZE;
> >     double number_1 = strtod(ptr, &not_converted);
> >     double number_2 = 0;
> >     if (not_converted > ptr)
> >     {
> >         while(not_converted > ptr && !isspace(*not_converted))
> 
> Why are you interested in non-spaces?  Nothing in your specification
> seems to need non-spaces.  Can you write out what the input should look
> like in general?  I.e. what will you permit and what won't you permit?
With this function I just need two numbers out of 5 - the first and the last
one. At the moment the function is called the input 
contains numbers, separated by commas (csv format), as in
1062,1252,1587,1934,2519

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


#102238

FromRichard Heathfield <rjh@cpax.org.uk>
Date2017-01-20 16:06 +0000
Message-ID<o5tcfb$ap3$1@dont-email.me>
In reply to#102236
On 20/01/17 15:45, Alla _ wrote:
> On Friday, January 20, 2017 at 6:17:01 PM UTC+3, Ben Bacarisse wrote:
>> Alla _ <modelling.data@gmail.com> writes:
<snip>
>>>         while(not_converted > ptr && !isspace(*not_converted))
>>
>> Why are you interested in non-spaces? [...]
> With this function I just need two numbers out of 5 - the first and the last
> one. At the moment the function is called the input
> contains numbers, separated by commas (csv format), as in
> 1062,1252,1587,1934,2519

In which case you have no need to call isspace at all, and the whole 
thing can be done in less than a dozen lines of very simple code.

n = 0; /* this is how many numbers you've successfully parsed */
do
{
   /* try to convert a number */
   num[n] = strtod(ptr, &not_converted, 10);

   /* if that worked... */
   if(not_converted > ptr)
   {
     /* record the success */
     ++n;

     /* if we're just at a field boundary, we
        want to move to just past that boundary.
        If we're at the end of the string,
        then two things happen: (1) we can't be
        sure that it's legal to move past the '\0'
        AND (2) there is in any case nothing more
        to convert.

        So if we're not at '\0', we want ptr to
        point to not_converted + 1. Otherwise, we
        want ptr to point to not_converted (which will
        terminate the loop).

        In C, the result of a condition is either 0
        (false), or 1 (true), and this happens to map
        precisely onto what we want. So we can do this:
      */

     ptr = not_converted + (*not_converted != '\0');
   }
} while(not_converted > ptr && n < expected_count);

expected_count would appear to be 5 in this case. If it's always 5, use 
a constant e.g. #define NUMBERS_PER_LINE 5

if(n == expected_count) you have all the numbers you need. If it isn't, 
you don't, and presumably that's an error.

Note the complete absence of isspace.

-- 
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]


#102241

FromAlla _ <modelling.data@gmail.com>
Date2017-01-20 08:37 -0800
Message-ID<2f5efea6-4d06-42bf-a6f9-976e1faf51e4@googlegroups.com>
In reply to#102238
On Friday, January 20, 2017 at 7:06:52 PM UTC+3, Richard Heathfield wrote:
> On 20/01/17 15:45, Alla _ wrote:
> > On Friday, January 20, 2017 at 6:17:01 PM UTC+3, Ben Bacarisse wrote:
> >> Alla _ <modelling.data@gmail.com> writes:
> <snip>
> >>>         while(not_converted > ptr && !isspace(*not_converted))
> >>
> >> Why are you interested in non-spaces? [...]
> > With this function I just need two numbers out of 5 - the first and the last
> > one. At the moment the function is called the input
> > contains numbers, separated by commas (csv format), as in
> > 1062,1252,1587,1934,2519
> 
> In which case you have no need to call isspace at all, and the whole 
> thing can be done in less than a dozen lines of very simple code.
> 
> n = 0; /* this is how many numbers you've successfully parsed */
> do
> {
>    /* try to convert a number */
>    num[n] = strtod(ptr, &not_converted, 10);
> 
>    /* if that worked... */
>    if(not_converted > ptr)
>    {
>      /* record the success */
>      ++n;
> 
>      /* if we're just at a field boundary, we
>         want to move to just past that boundary.
>         If we're at the end of the string,
>         then two things happen: (1) we can't be
>         sure that it's legal to move past the '\0'
>         AND (2) there is in any case nothing more
>         to convert.
> 
>         So if we're not at '\0', we want ptr to
>         point to not_converted + 1. Otherwise, we
>         want ptr to point to not_converted (which will
>         terminate the loop).
> 
>         In C, the result of a condition is either 0
>         (false), or 1 (true), and this happens to map
>         precisely onto what we want. So we can do this:
>       */
> 
>      ptr = not_converted + (*not_converted != '\0');
Yet another amazing trick! ) Thank you. I didn't know
about it. Not surprising though )
>    }
> } while(not_converted > ptr && n < expected_count);
> 
> expected_count would appear to be 5 in this case. If it's always 5, use 
> a constant e.g. #define NUMBERS_PER_LINE 5
Yes, I have this in the program. This was a tiny piece I have created
out of few pieces to ask for help. 

Your approach is great for storing all numbers in the array, which 
was not my intent in this piece; but it is great for the program itself,
there I do store numbers in the array of structs. 
> 
> if(n == expected_count) you have all the numbers you need. If it isn't, 
> you don't, and presumably that's an error.
> 
> Note the complete absence of isspace.
> 
> -- 
> 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]


#102243

FromDavid Brown <david.brown@hesbynett.no>
Date2017-01-20 17:54 +0100
Message-ID<o5tf8a$lpn$1@dont-email.me>
In reply to#102238
On 20/01/17 17:06, Richard Heathfield wrote:
> 
>     /* if we're just at a field boundary, we
>        want to move to just past that boundary.
>        If we're at the end of the string,
>        then two things happen: (1) we can't be
>        sure that it's legal to move past the '\0'
>        AND (2) there is in any case nothing more
>        to convert.
> 
>        So if we're not at '\0', we want ptr to
>        point to not_converted + 1. Otherwise, we
>        want ptr to point to not_converted (which will
>        terminate the loop).
> 
>        In C, the result of a condition is either 0
>        (false), or 1 (true), and this happens to map
>        precisely onto what we want. So we can do this:
>      */
> 
>     ptr = not_converted + (*not_converted != '\0');
> 

And how is that better than:

	if (*not_converted != '\0') {
		ptr = not_converted + 1;
	} else {
		ptr = not_converted;
	}

Rather than writing a nice, clear explanation in comments followed by
code with a completely different structure, why not simply write the
code that follows the nice, clear explanation?  Then you can also skip
that part of the comment.

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


#102245

FromRichard Heathfield <rjh@cpax.org.uk>
Date2017-01-20 17:04 +0000
Message-ID<o5tfrf$o7q$1@dont-email.me>
In reply to#102243
On 20/01/17 16:54, David Brown wrote:
> On 20/01/17 17:06, Richard Heathfield wrote:
>>
>>     /* if we're just at a field boundary, we
>>        want to move to just past that boundary.
>>        If we're at the end of the string,
>>        then two things happen: (1) we can't be
>>        sure that it's legal to move past the '\0'
>>        AND (2) there is in any case nothing more
>>        to convert.
>>
>>        So if we're not at '\0', we want ptr to
>>        point to not_converted + 1. Otherwise, we
>>        want ptr to point to not_converted (which will
>>        terminate the loop).
>>
>>        In C, the result of a condition is either 0
>>        (false), or 1 (true), and this happens to map
>>        precisely onto what we want. So we can do this:
>>      */
>>
>>     ptr = not_converted + (*not_converted != '\0');
>>
>
> And how is that better than:
>
> 	if (*not_converted != '\0') {
> 		ptr = not_converted + 1;
> 	} else {
> 		ptr = not_converted;
> 	}

That was in fact my first version (apart from the cuddled 'else'). But 
the duplication of code offended my sense of elegance, so I changed it 
and added the comment to explain exactly how I'd arrived at it.

Normally, I wouldn't bother with the comment, because to me the code is 
obvious. But I (correctly) guessed that Alla wouldn't be familiar with 
that idiom, so I took the time to explain it.

-- 
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]


#102249

FromDavid Brown <david.brown@hesbynett.no>
Date2017-01-20 19:08 +0100
Message-ID<o5tjj4$6pg$1@dont-email.me>
In reply to#102245
On 20/01/17 18:04, Richard Heathfield wrote:
> On 20/01/17 16:54, David Brown wrote:
>> On 20/01/17 17:06, Richard Heathfield wrote:
>>>
>>>     /* if we're just at a field boundary, we
>>>        want to move to just past that boundary.
>>>        If we're at the end of the string,
>>>        then two things happen: (1) we can't be
>>>        sure that it's legal to move past the '\0'
>>>        AND (2) there is in any case nothing more
>>>        to convert.
>>>
>>>        So if we're not at '\0', we want ptr to
>>>        point to not_converted + 1. Otherwise, we
>>>        want ptr to point to not_converted (which will
>>>        terminate the loop).
>>>
>>>        In C, the result of a condition is either 0
>>>        (false), or 1 (true), and this happens to map
>>>        precisely onto what we want. So we can do this:
>>>      */
>>>
>>>     ptr = not_converted + (*not_converted != '\0');
>>>
>>
>> And how is that better than:
>>
>>     if (*not_converted != '\0') {
>>         ptr = not_converted + 1;
>>     } else {
>>         ptr = not_converted;
>>     }
>
> That was in fact my first version (apart from the cuddled 'else'). But
> the duplication of code offended my sense of elegance, so I changed it
> and added the comment to explain exactly how I'd arrived at it.
>

I'm okay with a bit of code duplication, as long as it is short and 
clear.  If it were more than a simple assignment that were duplicated, 
I'd probably hoist the common part to before the conditional.

> Normally, I wouldn't bother with the comment, because to me the code is
> obvious. But I (correctly) guessed that Alla wouldn't be familiar with
> that idiom, so I took the time to explain it.
>

I guess this has the benefit of teaching a new idiom.  While I would not 
use it in this piece of code, I might use it elsewhere - it's a useful 
idea to know.

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


#102798

FromTim Rentsch <txr@alumni.caltech.edu>
Date2017-01-30 12:51 -0800
Message-ID<kfnbmuoff0p.fsf@x-alumni2.alumni.caltech.edu>
In reply to#102245
Richard Heathfield <rjh@cpax.org.uk> writes:

> On 20/01/17 16:54, David Brown wrote:
>> On 20/01/17 17:06, Richard Heathfield wrote:
>>
>>>     /* if we're just at a field boundary, we
>>>        want to move to just past that boundary.
>>>        If we're at the end of the string,
>>>        then two things happen:  (1) we can't be
>>>        sure that it's legal to move past the '\0'
>>>        AND (2) there is in any case nothing more
>>>        to convert.
>>>
>>>        So if we're not at '\0', we want ptr to
>>>        point to not_converted + 1.  Otherwise, we
>>>        want ptr to point to not_converted (which will
>>>        terminate the loop).
>>>
>>>        In C, the result of a condition is either 0
>>>        (false), or 1 (true), and this happens to map
>>>        precisely onto what we want.  So we can do this:
>>>      */
>>>
>>>     ptr = not_converted + (*not_converted != '\0');
>>
>> And how is that better than:
>>
>> 	if (*not_converted != '\0') {
>> 		ptr = not_converted + 1;
>> 	} else {
>> 		ptr = not_converted;
>> 	}
>
> That was in fact my first version (apart from the cuddled 'else').  But
> the duplication of code offended my sense of elegance, so I changed it
> and added the comment to explain exactly how I'd arrived at it.

I share the opinion that the single statement form is better
here.

> Normally, I wouldn't bother with the comment, because to me the code
> is obvious.  But I (correctly) guessed that Alla wouldn't be familiar
> with that idiom, so I took the time to explain it.

This brings up what I think is a more interesting point.  In
writing programs for students, it's fairly common to use comments
not because the author thinks the program needs it, but because
it is throught the students need it.  Unfortunately this habit
frequently leads to students thinking that sort of commenting
style is how programs should normally be written.  That's bad and
even worse self-perpetuating.  To fix it we should stop writing
such "educational" comments in any example code, including
(especially) code written with an educational purpose in mind.

Please consider putting any educational commentary outside the
actual code, rather that giving it as comments inside the code.

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


#102808

FromKeith Thompson <kst-u@mib.org>
Date2017-01-30 14:09 -0800
Message-ID<ln37g09p3k.fsf@kst-u.example.com>
In reply to#102798
Tim Rentsch <txr@alumni.caltech.edu> writes:
[...]
> This brings up what I think is a more interesting point.  In
> writing programs for students, it's fairly common to use comments
> not because the author thinks the program needs it, but because
> it is throught the students need it.  Unfortunately this habit
> frequently leads to students thinking that sort of commenting
> style is how programs should normally be written.  That's bad and
> even worse self-perpetuating.  To fix it we should stop writing
> such "educational" comments in any example code, including
> (especially) code written with an educational purpose in mind.
>
> Please consider putting any educational commentary outside the
> actual code, rather that giving it as comments inside the code.

I agree that there's a problem.  I'm not sure eliminating such comments
or moving them elsewhere is the best solution.

For a student just beginning to learn the language, comments like these:

    int i;  /* Create an object named "i" of type int */
    i = 42; /* Assign the value 42 to i */
    i ++;   /* Increment i by 1 */

as annoying as they might be, can actually be useful.  For example
the meaning of "++" is not obvious to a non-programmer, and
having a reminder close to where it's used can be a good reminder.
Putting them outside the code is going to make it more difficult
for the reader to associate the comments with the relevant code.

Perhaps one could use some special marker, with a comment at the
top (and an explanation by the instructor) saying that any marked
comments are intended to explain the language features and should
not be included in real code.

    int i;  /* TUT: Create an object named "i" of type int */
    i = 42; /* TUT: Assign the value 42 to i */
    i ++;   /* TUT: Increment i by 1 */

(It's been a long time since I was a beginning programmer, so it's hard
for me to tell what would work best.)

-- 
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]


#102809

Fromsupercat@casperkitty.com
Date2017-01-30 14:57 -0800
Message-ID<8f148b3d-948e-4f48-8bd9-88ba99b345c0@googlegroups.com>
In reply to#102808
On Monday, January 30, 2017 at 4:09:28 PM UTC-6, Keith Thompson wrote:
> Perhaps one could use some special marker, with a comment at the
> top (and an explanation by the instructor) saying that any marked
> comments are intended to explain the language features and should
> not be included in real code.
> 
>     int i;  /* TUT: Create an object named "i" of type int */
>     i = 42; /* TUT: Assign the value 42 to i */
>     i ++;   /* TUT: Increment i by 1 */
> 
> (It's been a long time since I was a beginning programmer, so it's hard
> for me to tell what would work best.)

An alternative for purposes of printed, PDF, or HTML documents, would be
to say that only text which is in a particular distinctive font should be
treated as part of a program, and text which is not in that font is intended
for human explanation only and is not part of the program.

I don't think such an approach would be particularly useful here, however,
nor in situations where explanations need to "travel" with the associated
code.  Perhaps those could best be handled by observing that programs whose
purpose is to test or illustrate the behavior of a particular construct
should be designed quite differently from programs which are supposed to
do real work, and should--as part of that--be commented differently.

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


#102946

FromTim Rentsch <txr@alumni.caltech.edu>
Date2017-02-01 21:31 -0800
Message-ID<kfnwpd9b1kq.fsf@x-alumni2.alumni.caltech.edu>
In reply to#102808
Keith Thompson <kst-u@mib.org> writes:

> Tim Rentsch <txr@alumni.caltech.edu> writes:
> [...]
>> This brings up what I think is a more interesting point.  In
>> writing programs for students, it's fairly common to use comments
>> not because the author thinks the program needs it, but because
>> it is thought the students need it.  Unfortunately this habit
>> frequently leads to students thinking that sort of commenting
>> style is how programs should normally be written.  That's bad and
>> even worse self-perpetuating.  To fix it we should stop writing
>> such "educational" comments in any example code, including
>> (especially) code written with an educational purpose in mind.
>>
>> Please consider putting any educational commentary outside the
>> actual code, rather that giving it as comments inside the code.
>
> I agree that there's a problem.  I'm not sure eliminating such
> comments or moving them elsewhere is the best solution.

How you phrase the statement shows how deep the problem is.  My
suggestion is not to move /comments/ but to put /commentary/
outside the program.  Any program examples that have /comments/
should have only those comments that one would write as part
of a real (as opposed to example or tutorial) program.  The
question of what is the best solution is misplaced:  it assumes
we know exactly what problem we're trying to solve, that it is
well-defined, that there is a "best" solution (by what metric?),
and that we could tell whether a proposed solution is a best
solution.  My goal is to avoid a behavior fairly well known to
have negative effects.  It may be that in the process of doing
that there will be other unexpected effects, but the only way
to know what those might be is to try the suggestion and see
what happens.


> For a student just beginning to learn the language, comments like
> these:
>
>     int i;  /* Create an object named "i" of type int */
>     i = 42; /* Assign the value 42 to i */
>     i ++;   /* Increment i by 1 */
>
> as annoying as they might be, can actually be useful.

The problem isn't that the comments are annoying.  The problem is
that they subconsciously reinforce bad habits.  Any usefulness
is temporary;  the cost of the bad habits endures much longer.


> For example
> the meaning of "++" is not obvious to a non-programmer, and
> having a reminder close to where it's used can be a good reminder.

It's hard for me to see any useful content in this statement.  It
looks like a tautology.


> Putting them outside the code is going to make it more difficult
> for the reader to associate the comments with the relevant code.

Here is an easy way to do that:  just repeat the line of code in
question, as an inline block within the commentary.  So for
example:

    The ++ operator adds one to its operand.  The program line

        i ++;

    has the effect of incrementing the variable 'i' by one.  ...


> Perhaps one could use some special marker, with a comment at the
> top (and an explanation by the instructor) saying that any marked
> comments are intended to explain the language features and should
> not be included in real code.
>
>     int i;  /* TUT:  Create an object named "i" of type int */
>     i = 42; /* TUT:  Assign the value 42 to i */
>     i ++;   /* TUT:  Increment i by 1 */

I've seen this done in other ways (eg, using a different font
for the non-code material).  It suffers from many of the same
problems that regular comments do.  Most importantly, it too
promotes or reinforces a way of thinking that is damaging to
less experienced programmers.  In that respect it isn't really
an improvement over using regular "comments".


> (It's been a long time since I was a beginning programmer, so
> it's hard for me to tell what would work best.)

The "what would work best" phrase tacitly implies that you
know what problem is being addressed.  Can you say what problem
it is you're trying to solve here?

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


Page 1 of 3  [1] 2 3  Next page →

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


csiph-web