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


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

Re: What are the odds? (a continuation of One works ...)

Started byBarry Schwarz <schwarzb@delq.com>
First post2019-11-06 14:23 -0800
Last post2019-11-07 11:57 +0000
Articles 10 — 8 participants

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

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: What are the odds? (a continuation of One works ...) Barry Schwarz <schwarzb@delq.com> - 2019-11-06 14:23 -0800
    Re: What are the odds? (a continuation of One works ...) Bart <bc@freeuk.com> - 2019-11-06 22:35 +0000
      Re: What are the odds? (a continuation of One works ...) luser droog <luser.droog@gmail.com> - 2019-11-06 17:09 -0800
      Re: What are the odds? (a continuation of One works ...) Keith Thompson <kst-u@mib.org> - 2019-11-06 19:19 -0800
        Re: What are the odds? (a continuation of One works ...) Ian Collins <ian-news@hotmail.com> - 2019-11-07 16:30 +1300
          Re: What are the odds? (a continuation of One works ...) Bart <bc@freeuk.com> - 2019-11-07 10:59 +0000
          Re: What are the odds? (a continuation of One works ...) David Brown <david.brown@hesbynett.no> - 2019-11-07 14:27 +0100
    Re: What are the odds? (a continuation of One works ...) DFS <nospam@dfs.com> - 2019-11-06 18:09 -0500
      Re: What are the odds? (a continuation of One works ...) Keith Thompson <kst-u@mib.org> - 2019-11-06 19:26 -0800
        Re: What are the odds? (a continuation of One works ...) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-07 11:57 +0000

#147683 — Re: What are the odds? (a continuation of One works ...)

FromBarry Schwarz <schwarzb@delq.com>
Date2019-11-06 14:23 -0800
SubjectRe: What are the odds? (a continuation of One works ...)
Message-ID<g4g6se5u1ggsmecioggck2k7ve59pfdbbp@4ax.com>
On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:

>On 11/6/2019 1:08 PM, Barry Schwarz wrote:

<snip>

>> One of the simplest things you can do that make programming
>> exponentially easier is use a consistent indenting scheme.  This will
>> help you avoid nesting level errors.
>
>
>The indenting is fine in my editor, but a mix of tabs and spaces comes 
>out bad when the code is pasted to Thunderbird.

When asking for help, it behooves one to make things as easy as
possible for the reader.  Experienced people in this newsgroup have
recommended spaces instead of tabs so that the resulting display is
not dependent on how the reader's tabs are set.

>>> Maybe you can show me how to fix the //letter distribution part of the
>>> code.  I can't get it to compile.
>> 
>> The error message for the statement that calls strcmp should have been
>> crystal clear.  What part of it did you not understand?
>
>
>I got it:

You got that part of it but then decided to break another part.

<snip>

>=========================================================================
>final code
>=========================================================================
>#include <stdlib.h>
>#include <stdio.h>
>#include <time.h>
>#include <math.h>
>#include <string.h>
>
>int randNbr(int low, int high) {
>   return (low + rand() / (RAND_MAX / (high - low + 1) + 1));
>}
>	
>int main(void) {

<snip>

>	 //letter distribution
>    char charset[62] = 
>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>    int charsetLen = strlen(charset);

After numerous examples in your comp.lang.c posts (where I have
redirected this response since we are not discussing the odds any
more) of calculating charsetLen correctly, you have chosen to use a
different method.  You have tried to pass charset to strlen in
complete violation of the requirements that function imposes. 

It is not sufficient to simply pass a pointer to char to strlen.
strlen requires that the pointer actually point to a string.  In order
for an array of char to contain a string, the array must contain at
least one '\0' to properly terminate the string.  charset does not. As
a result, this code exhibits undefined behavior.

When you tested the code, did you not notice extraneous lines of
output after the line for "9"?

>    cnt=0;
>    printf("n = 1000000\n");
>    for(i=0;i<charsetLen;i++) {
>		 for(j=0;j<1000000;j++) {
>			 k = randNbr(0,charsetLen-1);
>        if(charset[i] == charset[k]) {cnt++;}
>      }
>      printf("%c = %d\n",charset[i],cnt);
>      cnt=0;
>    }
>
>exit(0);
>}
>=========================================================================

-- 
Remove del for email

[toc] | [next] | [standalone]


#147684

FromBart <bc@freeuk.com>
Date2019-11-06 22:35 +0000
Message-ID<2VHwF.97943$_i.39059@fx25.am4>
In reply to#147683
On 06/11/2019 22:23, Barry Schwarz wrote:
> On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:

>>     char charset[62] =
>> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

> After numerous examples in your comp.lang.c posts (where I have
> redirected this response since we are not discussing the odds any
> more) of calculating charsetLen correctly, you have chosen to use a
> different method.  You have tried to pass charset to strlen in
> complete violation of the requirements that function imposes.
> 
> It is not sufficient to simply pass a pointer to char to strlen.
> strlen requires that the pointer actually point to a string.  In order
> for an array of char to contain a string, the array must contain at
> least one '\0' to properly terminate the string.  charset does not.

A simple fix is to get rid of the '62':

  char charset[] =
   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

Then the trailing 0 that is part of every string constant is included 
(otherwise the 63 chars including \0 are truncated to 62).

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


#147693

Fromluser droog <luser.droog@gmail.com>
Date2019-11-06 17:09 -0800
Message-ID<33b3c4ce-2f41-4bb1-bbc1-76a768125681@googlegroups.com>
In reply to#147684
On Wednesday, November 6, 2019 at 4:35:51 PM UTC-6, Bart wrote:
> On 06/11/2019 22:23, Barry Schwarz wrote:
> > On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:
> 
> >>     char charset[62] =
> >> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
> 
> > After numerous examples in your comp.lang.c posts (where I have
> > redirected this response since we are not discussing the odds any
> > more) of calculating charsetLen correctly, you have chosen to use a
> > different method.  You have tried to pass charset to strlen in
> > complete violation of the requirements that function imposes.
> > 
> > It is not sufficient to simply pass a pointer to char to strlen.
> > strlen requires that the pointer actually point to a string.  In order
> > for an array of char to contain a string, the array must contain at
> > least one '\0' to properly terminate the string.  charset does not.
> 
> A simple fix is to get rid of the '62':
> 
>   char charset[] =
>    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
> 
> Then the trailing 0 that is part of every string constant is included 
> (otherwise the 63 chars including \0 are truncated to 62).

Another small improvement would be to use the compiler's ability to 
concatenate string literals. I'd make the three sequences separate
string literals so they can be lined up.

  char charset[] =
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789";

If you happen to miss a letter while typing one of the two alphabets,
the error would immediately be apparent to the eye.

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


#147696

FromKeith Thompson <kst-u@mib.org>
Date2019-11-06 19:19 -0800
Message-ID<ln36f05q6t.fsf@kst-u.example.com>
In reply to#147684
Bart <bc@freeuk.com> writes:
> On 06/11/2019 22:23, Barry Schwarz wrote:
>> On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:
>>>     char charset[62] =
>>> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>> After numerous examples in your comp.lang.c posts (where I have
>> redirected this response since we are not discussing the odds any
>> more) of calculating charsetLen correctly, you have chosen to use a
>> different method.  You have tried to pass charset to strlen in
>> complete violation of the requirements that function imposes.
>> 
>> It is not sufficient to simply pass a pointer to char to strlen.
>> strlen requires that the pointer actually point to a string.  In order
>> for an array of char to contain a string, the array must contain at
>> least one '\0' to properly terminate the string.  charset does not.
>
> A simple fix is to get rid of the '62':
>
>   char charset[] =
>    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

The only thing the code does that depends on charset containing a
valid string is the single (incorrect) call to strlen().  If you
replace `strlen(charset)` by `sizeof charset` then there's no need
to nul-terminate it.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

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


#147698

FromIan Collins <ian-news@hotmail.com>
Date2019-11-07 16:30 +1300
Message-ID<h2hhf7Fq967U11@mid.individual.net>
In reply to#147696
On 07/11/2019 16:19, Keith Thompson wrote:
> Bart <bc@freeuk.com> writes:
>> On 06/11/2019 22:23, Barry Schwarz wrote:
>>> On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:
>>>>      char charset[62] =
>>>> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>>> After numerous examples in your comp.lang.c posts (where I have
>>> redirected this response since we are not discussing the odds any
>>> more) of calculating charsetLen correctly, you have chosen to use a
>>> different method.  You have tried to pass charset to strlen in
>>> complete violation of the requirements that function imposes.
>>>
>>> It is not sufficient to simply pass a pointer to char to strlen.
>>> strlen requires that the pointer actually point to a string.  In order
>>> for an array of char to contain a string, the array must contain at
>>> least one '\0' to properly terminate the string.  charset does not.
>>
>> A simple fix is to get rid of the '62':
>>
>>    char charset[] =
>>     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
> 
> The only thing the code does that depends on charset containing a
> valid string is the single (incorrect) call to strlen().  If you
> replace `strlen(charset)` by `sizeof charset` then there's no need
> to nul-terminate it.
Or do what I did in my C++ version and use a compile time constant for 
the size.  That way the compile will break if you miss out a character.

-- 
Ian.

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


#147705

FromBart <bc@freeuk.com>
Date2019-11-07 10:59 +0000
Message-ID<0OSwF.55314$_d3.10705@fx38.am4>
In reply to#147698
On 07/11/2019 03:30, Ian Collins wrote:
> On 07/11/2019 16:19, Keith Thompson wrote:

>> The only thing the code does that depends on charset containing a
>> valid string is the single (incorrect) call to strlen().  If you
>> replace `strlen(charset)` by `sizeof charset` then there's no need
>> to nul-terminate it.

> Or do what I did in my C++ version and use a compile time constant for 
> the size.  That way the compile will break if you miss out a character.

What does that look like?

With a specified bound, C is only interested if you have too many 
characters, not too few.

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


#147710

FromDavid Brown <david.brown@hesbynett.no>
Date2019-11-07 14:27 +0100
Message-ID<qq1649$vvi$1@dont-email.me>
In reply to#147698
On 07/11/2019 04:30, Ian Collins wrote:
> On 07/11/2019 16:19, Keith Thompson wrote:
>> Bart <bc@freeuk.com> writes:
>>> On 06/11/2019 22:23, Barry Schwarz wrote:
>>>> On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:
>>>>>      char charset[62] =
>>>>> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>>>> After numerous examples in your comp.lang.c posts (where I have
>>>> redirected this response since we are not discussing the odds any
>>>> more) of calculating charsetLen correctly, you have chosen to use a
>>>> different method.  You have tried to pass charset to strlen in
>>>> complete violation of the requirements that function imposes.
>>>>
>>>> It is not sufficient to simply pass a pointer to char to strlen.
>>>> strlen requires that the pointer actually point to a string.  In order
>>>> for an array of char to contain a string, the array must contain at
>>>> least one '\0' to properly terminate the string.  charset does not.
>>>
>>> A simple fix is to get rid of the '62':
>>>
>>>    char charset[] =
>>>     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>>
>> The only thing the code does that depends on charset containing a
>> valid string is the single (incorrect) call to strlen().  If you
>> replace `strlen(charset)` by `sizeof charset` then there's no need
>> to nul-terminate it.
> Or do what I did in my C++ version and use a compile time constant for
> the size.  That way the compile will break if you miss out a character.
> 

C++ will complain if the initialiser is too long (as it is in this case,
but not if it is too short.  (A compiler may provide a warning, of course.)

I think the best way to ensure such arrays are the size you expect are
to omit the size in the definition, then use a static assertion to check it:

const char charset[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

_Static_assert(sizeof(charset) == 63,
	"Charset should be 62 chars plus terminating zero");

If you have got your alphabet wrong, you'll get a compile-time error.

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


#147686

FromDFS <nospam@dfs.com>
Date2019-11-06 18:09 -0500
Message-ID<joIwF.86203$FF4.79851@fx40.iad>
In reply to#147683
On 11/6/2019 5:23 PM, Barry Schwarz wrote:
> On Wed, 6 Nov 2019 15:52:28 -0500, DFS <nospam@dfs.com> wrote:
> 
>> On 11/6/2019 1:08 PM, Barry Schwarz wrote:
> 
> <snip>
> 
>>> One of the simplest things you can do that make programming 
>>> exponentially easier is use a consistent indenting scheme.  This
>>> will help you avoid nesting level errors.
>> 
>> 
>> The indenting is fine in my editor, but a mix of tabs and spaces
>> comes out bad when the code is pasted to Thunderbird.
> 
> When asking for help, it behooves one to make things as easy as 
> possible for the reader.  Experienced people in this newsgroup have 
> recommended spaces instead of tabs so that the resulting display is 
> not dependent on how the reader's tabs are set.

I'll do that.



>>>> Maybe you can show me how to fix the //letter distribution part
>>>> of the code.  I can't get it to compile.
>>> 
>>> The error message for the statement that calls strcmp should have
>>> been crystal clear.  What part of it did you not understand?
>> 
>> 
>> I got it:
> 
> You got that part of it but then decided to break another part.

> <snip>
> 
>> //letter distribution char charset[62] = 
>> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 
>> int charsetLen = strlen(charset);
> 
> After numerous examples in your comp.lang.c posts (where I have 
> redirected this response since we are not discussing the odds any 
> more) of calculating charsetLen correctly, 

Actually, I never calculated it before.  I hard-coded it.

short charsetLen = 62;


> you have chosen to use a 
> different method.  You have tried to pass charset to strlen in 
> complete violation of the requirements that function imposes.
> 
> It is not sufficient to simply pass a pointer to char to strlen. 
> strlen requires that the pointer actually point to a string.  In
> order for an array of char to contain a string, the array must
> contain at least one '\0' to properly terminate the string.  charset
> does not. As a result, this code exhibits undefined behavior.


char charset[62]
="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int charsetLen = strlen(charset);
printf("%d \n",charsetLen);
62


char charset[63] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int charsetLen = strlen(charset);
printf("%d \n",charsetLen);
62





> When you tested the code, did you not notice extraneous lines of 
> output after the line for "9"?


Not seeing that.  Compiled and ran on tcc/Windows and gcc (MSYS2) and 
there are no extraneous lines of output after the output for 9.

I do notice on tcc/Windows the count for 9 is always significantly lower 
than the count of any other character in the set.  Low 15Ks vs high 
15Ks/low 16Ks for all the other characters.

That doesn't happen on gcc/MSYS2.


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


#147697

FromKeith Thompson <kst-u@mib.org>
Date2019-11-06 19:26 -0800
Message-ID<lny2ws4ba3.fsf@kst-u.example.com>
In reply to#147686
DFS <nospam@dfs.com> writes:
[...]
> char charset[62]
> ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
> int charsetLen = strlen(charset);
> printf("%d \n",charsetLen);
> 62

That still has undefined behavior.  It appears to "work" only because,
most likely, there just happens to be a null byte in memory immediately
after charset.

I just compiled and ran your on my system.  I got 62 with gcc and clang,
and 65 with tcc.  There is not necessarily any particular reason for
this, and it could just as easily produce different results tomorrow.

> char charset[63] =
> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
> int charsetLen = strlen(charset);
> printf("%d \n",charsetLen);
> 62

That's well defined, but as I mentioned elsethread your (incorrect)
strlen call is the only thing that relies on charset containing a valid
string.

If you define charset using [] you can get its size using sizeof.

>> When you tested the code, did you not notice extraneous lines of 
>> output after the line for "9"?
>
> Not seeing that.  Compiled and ran on tcc/Windows and gcc (MSYS2) and 
> there are no extraneous lines of output after the output for 9.

That's one of thep problems with undefined behavior: it can evade
testing.

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

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


#147707

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-11-07 11:57 +0000
Message-ID<87o8xnj3vs.fsf@bsb.me.uk>
In reply to#147697
Keith Thompson <kst-u@mib.org> writes:

> DFS <nospam@dfs.com> writes:
> [...]
>> char charset[62]
>> ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>> int charsetLen = strlen(charset);
>> printf("%d \n",charsetLen);
>> 62
>
> That still has undefined behavior.  It appears to "work" only because,
> most likely, there just happens to be a null byte in memory immediately
> after charset.
>
> I just compiled and ran your on my system.  I got 62 with gcc and clang,
> and 65 with tcc.  There is not necessarily any particular reason for
> this, and it could just as easily produce different results tomorrow.
>
>> char charset[63] =
>> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
>> int charsetLen = strlen(charset);
>> printf("%d \n",charsetLen);
>> 62
>
> That's well defined, but as I mentioned elsethread your (incorrect)
> strlen call is the only thing that relies on charset containing a valid
> string.
>
> If you define charset using [] you can get its size using sizeof.

(This is to the OP...)  You will get 63 using sizeof because the size
includes the null that will be put there if you [] in the array
declaration.  You have to write sizeof charset - 1.  Keith's previous
remark about using sizeof refereed to the case what you gave an explicit
size in the array declaration.

Just in case things have got confused, here are your options:

  char s[] = "abc";

s will be a null terminated string and you can get the number of
non-null characters using either strlen(s) or sizeof s - 1.

  char s[3] = "abc";

s will not be a string.  There is no guarantee that there will be a null
at the end (though there might be one by accident).  You can't use
strlen but sizeof s will give you 3.

  char *s = "abc";

s points to the start of a null-terminated string.  You can get the
number of non-null characters in it using strlen(s) but you can't size
sizeof s because that will report only the size of the pointer s.

(And you can put const in front of all of these to tell the reader the
that this is read-only data.  Indeed, in the last case you can write

  const char *const s = "abc";

to show that the pointer s itself is read-only as well as the string it
points to.)

-- 
Ben.

[toc] | [prev] | [standalone]


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


csiph-web