By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,797 Members | 1,848 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,797 IT Pros & Developers. It's quick & easy.

coin toss problem

P: n/a
I've written this coin toss program, and can't figure out why it isn't
giving accurate results...
cheers,
Ben

#include <stdlib.h>
#include <stdio.h>
#define H 1
#define T 0
#define SENTINEL -1

int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;

void one_run(int seed_passed)
{
int i, x, row_h;
row_h = 0;

seed=(1+seed_passed);
srand(seed);

char A[limit+1];

for(i=0;i<limit;i++)
{
x=(int)(2.0*rand()/(1.0+RAND_MAX));

if(x==H)
A[i]=H;

else
A[i]=T;
}

A[i]=SENTINEL;

i=0;

while(A[i]!=SENTINEL)
{
while(A[i]==H)
{
i++;
row_h++;
}

if(row_h==in_a_row)
count++;

row_h=0;

if(A[i]!=SENTINEL)
i++;
}
}

int main(int argc, char **argv)
{
int i;
double av_occur;

if (argc==2)
seed=atoi(argv[1]);

printf("\nEnter number of coin tosses: ");
scanf("%d", &limit);

printf("\nEnter number of heads to be found in a row: ");
scanf("%d", &in_a_row);

if(limit<=1000)
iterations=100000;

for(i=1;i<=iterations;i++)
{
one_run(seed);
}

(av_occur=1.0*count/iterations);

printf("\nIf a coin is flipped %d times:\n", limit);
printf("Average no. of occurances of %d heads in a row is %.5f"
, in_a_row, av_occur);
printf("\n(with %d tests)", iterations);

/* printf("\ncount is %d", count);
*/
return 0;
}

Jun 17 '06 #1
Share this Question
Share on Google+
52 Replies


P: n/a
ce**********@hotmail.com wrote:

I've written this coin toss program, and can't figure out why it isn't
giving accurate results...
cheers,
Ben

#include <stdlib.h>
#include <stdio.h>
#define H 1
#define T 0
#define SENTINEL -1

int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;

void one_run(int seed_passed)
{
int i, x, row_h;
row_h = 0;

seed=(1+seed_passed);
srand(seed);

char A[limit+1];


This code should not compile unless you have a C99 system, which I
doubt. limit+1 is not a constant, so the compiler has no idea what
to do. In addition, you are defining storage after executable
code. Turn up your warning levels. Also you are allowed to use
blanks in expressions, the blank embargo was lifted some years ago.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews

Jun 17 '06 #2

P: n/a
CBFalconer wrote:
ce**********@hotmail.com wrote:
I've written this coin toss program, and can't figure out why it isn't
giving accurate results...
cheers,
Ben

#include <stdlib.h>
#include <stdio.h>
#define H 1
#define T 0
#define SENTINEL -1

int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;

void one_run(int seed_passed)
{
int i, x, row_h;
row_h = 0;

seed=(1+seed_passed);
srand(seed);

char A[limit+1];

This code should not compile unless you have a C99 system, which I
doubt.


Why? Compiles fine with either compiler on mine.

--
Ian Collins.
Jun 17 '06 #3

P: n/a
<ce**********@hotmail.com> wrote:
I've written this coin toss program, and can't figure out why it isn't
giving accurate results...
I don't know what your problem is but I will make some observations anyway.
First of all, get rid of the global variables. There is no need to resort
to global variables in a program this small and simple.

Is there any reason not to use enum instead of the #defines? They are more
appropriate and would probably do what you want.

Don't use the sentinel. Sentinels are something you resort to when there is
a good reason. There is no good reason here.

Reduce the program to its essence. You seem to be able to handle command
line, a default set of data, or user supplied data. This is just
obfuscating things right now. Choose one. I would use built in data for
initial testing.

Pay attention to the definition of in_a_row. Does it mean *exactly* n in a
row? The code says no. To determine that your code would have to look at
the next character - the one that breaks the sequence- , and it doesn't do
that. To me, exactly is the most sensible thing to compute. For example,
if in_a_row is 3 what does the following sequence of heads get counted as:
001111111100 ?

I tried the corner cases, in a row = 1 and in a row = 0 and got strange
results.

You might refuse to accept such questions as n = 1 in the final version of
your code.

The crucial number is count. If you still have problems, add code to print
the raw value of count.

There are also a few embedded comments.
#include <stdlib.h>
#include <stdio.h>
#define H 1
#define T 0
#define SENTINEL -1

int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;

void one_run(int seed_passed)
{
int i, x, row_h;
row_h = 0;
Don't separate the definition from the initial value.

IOW
int row_h = 0;
seed=(1+seed_passed);
srand(seed);

char A[limit+1];

for(i=0;i<limit;i++)
{
x=(int)(2.0*rand()/(1.0+RAND_MAX));
Too complicated.

Note that if the number drawn is less than 1/2 RAND_MAX, you have divided
the distribution into two almost equal parts.
if(x==H)
A[i]=H;

else
A[i]=T;
}

A[i]=SENTINEL;

i=0;

while(A[i]!=SENTINEL)
{
while(A[i]==H)
{
i++;
row_h++;
}

if(row_h==in_a_row)
count++;

row_h=0;

if(A[i]!=SENTINEL)
i++;
}
}

int main(int argc, char **argv)
{
int i;
double av_occur;

if (argc==2)
seed=atoi(argv[1]);

printf("\nEnter number of coin tosses: ");
scanf("%d", &limit);

printf("\nEnter number of heads to be found in a row: ");
scanf("%d", &in_a_row);

if(limit<=1000)
iterations=100000;

for(i=1;i<=iterations;i++)
{
one_run(seed);
}

(av_occur=1.0*count/iterations);
What are those parens for? Just a kind of idle question.
printf("\nIf a coin is flipped %d times:\n", limit);
printf("Average no. of occurances of %d heads in a row is %.5f"
, in_a_row, av_occur);
printf("\n(with %d tests)", iterations);

/* printf("\ncount is %d", count);
*/
return 0;
}

Jun 17 '06 #4

P: n/a
Ian Collins said:
CBFalconer wrote:
ce**********@hotmail.com wrote:
<snip>

int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;
<snip>
char A[limit+1];

This code should not compile unless you have a C99 system, which I
doubt.


Why? Compiles fine with either compiler on mine.


If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then your
C compiler is required to issue a diagnostic message for the above code,
which violates this constraint: "The expression that specifies the size of
an array shall be an integral constant expression that has a value greater
than zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 17 '06 #5

P: n/a

osmium wrote:
int i, x, row_h;
row_h = 0;


Don't separate the definition from the initial value.

IOW
int row_h = 0;


Is there a reason to use an initialization instead of
an assignment after the declaration? I prefer declaring
and then assigning, but the only reason is that I find
it annoying when I'm debugging and the debugger stops
in the declaration block. Is this more than just a stylistic
issue, or do some compilers generate different code for
the 2 cases?

Jun 17 '06 #6

P: n/a
"Bill Pursell" writes:
osmium wrote:
> int i, x, row_h;
> row_h = 0;


Don't separate the definition from the initial value.

IOW
int row_h = 0;


Is there a reason to use an initialization instead of
an assignment after the declaration? I prefer declaring
and then assigning, but the only reason is that I find
it annoying when I'm debugging and the debugger stops
in the declaration block. Is this more than just a stylistic
issue, or do some compilers generate different code for
the 2 cases?


My objection was based on documentation. I found a place in his code where
the value seemed to be an un-initialized datum. In fact it wasn't, but the
initialization was hidden, at least from me. For a while.

I doubt if there are any non-stylistic issues.
Jun 17 '06 #7

P: n/a

<ce**********@hotmail.com> wrote in message
news:11**********************@r2g2000cwb.googlegro ups.com...
cheers,
Ben
#include <stdlib.h>
#include <stdio.h>
#define H 1
#define T 0
#define SENTINEL -1

I might be able to provide comment on your data, but I crap out right here.
Unlike Keith Thompson, I am not 100% certain what this ultimate statement
means. BTW, I'm not even sure that 'statement" is the right descriptor for
something that doesn't necessarily end in a ';'. Anyways,
#define SENTINEL -1
probably instructs the preprocessor to replace every instance of SENTINEL
with negative one. When I looked at it, I thought you were decrementing. I
think better form would be
#define SENTINEL '-1'
or
#define SENTINEL (-1)
, I'm not sure which, but since '-' is a token, it needs something. Post
your "howdy and thanks, ben" below, so that they can be easily snipped.
furunculus

Jun 17 '06 #8

P: n/a
Bill Pursell wrote:

osmium wrote:
int i, x, row_h;
row_h = 0;
Don't separate the definition from the initial value.

IOW
int row_h = 0;


Is there a reason to use an initialization instead of
an assignment after the declaration? I prefer declaring
and then assigning,


So do I.
but the only reason is that I find
it annoying when I'm debugging and the debugger stops
in the declaration block.


I prefer to initialise just prior to usage because
my compiler issues a warning for unused variables,
which is a warning that I like.
My compiler considers an initialised variable,
to be a used one.

--
pete
Jun 17 '06 #9

P: n/a
Joe Smith wrote:

<ce**********@hotmail.com> wrote in message
news:11**********************@r2g2000cwb.googlegro ups.com...
#define SENTINEL -1

I think better form would be
#define SENTINEL '-1'
or
#define SENTINEL (-1)
, I'm not sure which, but since '-' is a token, it needs something.


I prefer
#define SENTINEL (-1)
because I don't know what '-1' means.

--
pete
Jun 17 '06 #10

P: n/a
osmium wrote:
"Bill Pursell" writes:

.... snip ...

Is there a reason to use an initialization instead of
an assignment after the declaration? I prefer declaring
and then assigning, but the only reason is that I find
it annoying when I'm debugging and the debugger stops
in the declaration block. Is this more than just a stylistic
issue, or do some compilers generate different code for
the 2 cases?


My objection was based on documentation. I found a place in his
code where the value seemed to be an un-initialized datum. In
fact it wasn't, but the initialization was hidden, at least from
me. For a while.

I doubt if there are any non-stylistic issues.


IMO the opposite is true. Since initialization of automatic
variables always involves generating code, lets have that code
where it is obviously such. If the routine is so long and involved
that you can miss the actual initialization, then it should be
chopped up into smaller more understandable portions. That way you
also avoid generating useless code for initializations that are
always just overwritten.

One further benefit: if you port your code to some C-like embedded
system with an almost C compiler, it has a better chance of
surviving unscathed.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Jun 17 '06 #11

P: n/a
Richard Heathfield wrote:
Ian Collins said:

CBFalconer wrote:
ce**********@hotmail.com wrote:

<snip>
int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;

<snip>
char A[limit+1];
This code should not compile unless you have a C99 system, which I
doubt.


Why? Compiles fine with either compiler on mine.

If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then your
C compiler is required to issue a diagnostic message for the above code,
which violates this constraint: "The expression that specifies the size of
an array shall be an integral constant expression that has a value greater
than zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.

Are Solaris users realy that small a minority?

Also gcc has supported variable length arrays as an extension for many
years. I've suffered the pain of porting from gcc more than once.

--
Ian Collins.
Jun 17 '06 #12

P: n/a
Richard Heathfield <in*****@invalid.invalid> writes:
Ian Collins said:
CBFalconer wrote:
ce**********@hotmail.com wrote:
<snip>
int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;
<snip>
char A[limit+1];
This code should not compile unless you have a C99 system, which I
doubt.


Why? Compiles fine with either compiler on mine.


If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then your
C compiler is required to issue a diagnostic message for the above code,
which violates this constraint: "The expression that specifies the size of
an array shall be an integral constant expression that has a value greater
than zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.


It also has declarations following statements within a block. Both of
these features are supported by C99 but not by C90. (They're also
supported by C++, and possibly by some C90 compilers in a
non-conforming mode.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 17 '06 #13

P: n/a
pete wrote:
Joe Smith wrote:
<ce**********@hotmail.com> wrote in message
news:11**********************@r2g2000cwb.googleg roups.com...


#define SENTINEL -1


I think better form would be
#define SENTINEL '-1'
or
#define SENTINEL (-1)
, I'm not sure which, but since '-' is a token, it needs something.

I prefer
#define SENTINEL (-1)
because I don't know what '-1' means.

Why not just use const int?

--
Ian Collins.
Jun 17 '06 #14

P: n/a
pete <pf*****@mindspring.com> writes:
Joe Smith wrote:
<ce**********@hotmail.com> wrote in message
news:11**********************@r2g2000cwb.googlegro ups.com...
> #define SENTINEL -1

I think better form would be
#define SENTINEL '-1'
or
#define SENTINEL (-1)
, I'm not sure which, but since '-' is a token, it needs something.


I prefer
#define SENTINEL (-1)
because I don't know what '-1' means.


I know what '-1' means. It means an implementation-defined value of
type int. It's unlikely to be what you want here. (Actually it will
probably work as long as the value is neither 0 nor 1, but it's a
silly way to do it.)

If you want to define a macro with the value -1, you should definitely
add parentheses:

#define SENTINEL (-1)

to avoid operator precedence problems.

Joe, your suggestion of

#define SENTINEL '-1'

was obviously a wild guess. That's fine if you're asking a question,
but I suggest that it's counterproductive if you're trying to answer a
question.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 17 '06 #15

P: n/a
Keith Thompson wrote:
Richard Heathfield <in*****@invalid.invalid> writes:
Ian Collins said:

CBFalconer wrote:

ce**********@hotmail.com wrote:


<snip>
>int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;
>


<snip>
> char A[limit+1];
This code should not compile unless you have a C99 system, which I
doubt.

Why? Compiles fine with either compiler on mine.


If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then your
C compiler is required to issue a diagnostic message for the above code,
which violates this constraint: "The expression that specifies the size of
an array shall be an integral constant expression that has a value greater
than zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.

It also has declarations following statements within a block. Both of
these features are supported by C99 but not by C90. (They're also
supported by C++, and possibly by some C90 compilers in a
non-conforming mode.)

No, VLAs are not supported by C++ (yet). A constant expression is
required. g++ has them as an (irritating for porters) extension.

--
Ian Collins.
Jun 17 '06 #16

P: n/a
Ian Collins said:
Richard Heathfield wrote:
Ian Collins said:

CBFalconer wrote:

ce**********@hotmail.com wrote:

<snip>
>int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;
>


<snip>
> char A[limit+1];
This code should not compile unless you have a C99 system, which I
doubt.

Why? Compiles fine with either compiler on mine.

If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then
your C compiler is required to issue a diagnostic message for the above
code, which violates this constraint: "The expression that specifies the
size of an array shall be an integral constant expression that has a
value greater than zero." Since limit+1 is not an integral constant
expression, a diagnostic message is required.

Are Solaris users realy that small a minority?


The 99.90813774% figure makes up in precision what it lacks in accuracy. :-)
But seriously, if Solaris is relevant to your point then your point is
almost certainly irrelevant to comp.lang.c. Yes, the code is valid C99, as
I already pointed out in my earlier reply, so if you are using a C99
compiler then the code is legal. But it is not /portable/ - for example, it
won't compile on the implementation I am presently using.

Also gcc has supported variable length arrays as an extension for many
years.
Using extensions is fine until the time comes to port. At that point, the
pain hits. If you want to avoid the pain, either avoid the port or avoid
the extensions.
I've suffered the pain of porting from gcc more than once.


See?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 17 '06 #17

P: n/a
Richard Heathfield wrote:
Ian Collins said:

Richard Heathfield wrote:
If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then
your C compiler is required to issue a diagnostic message for the above
code, which violates this constraint: "The expression that specifies the
size of an array shall be an integral constant expression that has a
value greater than zero." Since limit+1 is not an integral constant
expression, a diagnostic message is required.


Are Solaris users realy that small a minority?

The 99.90813774% figure makes up in precision what it lacks in accuracy. :-)
But seriously, if Solaris is relevant to your point then your point is
almost certainly irrelevant to comp.lang.c. Yes, the code is valid C99, as
I already pointed out in my earlier reply, so if you are using a C99
compiler then the code is legal. But it is not /portable/ - for example, it
won't compile on the implementation I am presently using.

My poorly made point was that C99 is more widely available than some
people make out.

I still find the "it's new so I won't use it" argument hard to swallow.
Every new tool or technology has its early adopters (if 6 years on is
early!). If no one uses new stuff because it isn't portable, progress
would grind to a halt.

--
Ian Collins.
Jun 17 '06 #18

P: n/a
Ian Collins said:

My poorly made point was that C99 is more widely available than some
people make out.
True. It is also /less/ widely available than some people make out.
I still find the "it's new so I won't use it" argument hard to swallow.


Nobody is arguing that as far as I can see. The reason I don't use C99
features is that they're not portable, so using those features makes my
code non-portable. When C99 becomes widespread, that'll be great,
marvellous, and fantastic, and suddenly I'll be able to use VLAs if I want
(not that I see the point) - but in the meantime I'm not holding my breath.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 17 '06 #19

P: n/a
Keith Thompson wrote:
pete <pf*****@mindspring.com> writes:
Joe Smith wrote:
<ce**********@hotmail.com> wrote in message
news:11**********************@r2g2000cwb.google groups.com...

#define SENTINEL -1

I think better form would be
#define SENTINEL '-1'
or
#define SENTINEL (-1)
, I'm not sure which, but since '-' is a token, it needs something.


I prefer
#define SENTINEL (-1)
because I don't know what '-1' means.

I know what '-1' means. It means an implementation-defined value of
type int. It's unlikely to be what you want here. (Actually it will
probably work as long as the value is neither 0 nor 1, but it's a
silly way to do it.)

If you want to define a macro with the value -1, you should definitely
add parentheses:

#define SENTINEL (-1)

to avoid operator precedence problems.


For example,

int array[] = { 1, 2, 3 }, *p = array + 1;
printf ("%d\n", SENTINEL[p]);

.... outputs "-3\n" if SENTINEL is -1, but "1\n" if it
is (-1).

(I *think* the only way to form an expression where
the presence or absence of parentheses around -1 makes
a difference is to use the bass-ackward array notation
as above. Can anyone come up with another?)

--
Eric Sosman
es*****@acm-dot-org.invalid
Jun 17 '06 #20

P: n/a
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:

[...]
It also has declarations following statements within a block. Both of
these features are supported by C99 but not by C90. (They're also
supported by C++, and possibly by some C90 compilers in a
non-conforming mode.)

No, VLAs are not supported by C++ (yet). A constant expression is
required. g++ has them as an (irritating for porters) extension.


See, that's what I get for discussing C++ in comp.lang.c!

(I was probably thinking of the fact that C++ has a looser definition
of constant expressions than C has; some things that would be VLAs in
C are ordinary constant-size arrays in C++.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 17 '06 #21

P: n/a
Ian Collins <ia******@hotmail.com> writes:
Richard Heathfield wrote:

[...]
If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then your
C compiler is required to issue a diagnostic message for the above code,
which violates this constraint: "The expression that specifies the size of
an array shall be an integral constant expression that has a value greater
than zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.

Are Solaris users realy that small a minority?


<OT>
Are you saying that Sun's compiler fully supports C99? If so, it's
news to me. What version?
</OT>

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 17 '06 #22

P: n/a
Richard Heathfield wrote:
Ian Collins said:
My poorly made point was that C99 is more widely available than some
people make out.

True. It is also /less/ widely available than some people make out.

I still find the "it's new so I won't use it" argument hard to swallow.

Nobody is arguing that as far as I can see. The reason I don't use C99
features is that they're not portable, so using those features makes my
code non-portable. When C99 becomes widespread, that'll be great,
marvellous, and fantastic, and suddenly I'll be able to use VLAs if I want
(not that I see the point) - but in the meantime I'm not holding my breath.

It's a classic chicken and egg situation, users won't use it because it
isn't portable, vendors won't support it because users won't use it!

--
Ian Collins.
Jun 17 '06 #23

P: n/a
Keith Thompson wrote:
Ian Collins <ia******@hotmail.com> writes:
Richard Heathfield wrote:
[...]
If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us, then your
C compiler is required to issue a diagnostic message for the above code,
which violates this constraint: "The expression that specifies the size of
an array shall be an integral constant expression that has a value greater
than zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.


Are Solaris users realy that small a minority?

<OT>
Are you saying that Sun's compiler fully supports C99? If so, it's
news to me. What version?


Studio 11 is getting close. As close as their C++ compiler was to the
C++ standard a few years ago.
</OT>

--
Ian Collins.
Jun 17 '06 #24

P: n/a
Keith Thompson wrote:
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:


[...]
It also has declarations following statements within a block. Both of
these features are supported by C99 but not by C90. (They're also
supported by C++, and possibly by some C90 compilers in a
non-conforming mode.)


No, VLAs are not supported by C++ (yet). A constant expression is
required. g++ has them as an (irritating for porters) extension.

See, that's what I get for discussing C++ in comp.lang.c!

(I was probably thinking of the fact that C++ has a looser definition
of constant expressions than C has; some things that would be VLAs in
C are ordinary constant-size arrays in C++.)

Yes, that's correct. Another thing I find strange in C: why isn't
'const int' a constant expression?

--
Ian Collins.
Jun 17 '06 #25

P: n/a
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:


[...]
It also has declarations following statements within a block. Both of
these features are supported by C99 but not by C90. (They're also
supported by C++, and possibly by some C90 compilers in a
non-conforming mode.)
No, VLAs are not supported by C++ (yet). A constant expression is
required. g++ has them as an (irritating for porters) extension.

See, that's what I get for discussing C++ in comp.lang.c!

(I was probably thinking of the fact that C++ has a looser definition
of constant expressions than C has; some things that would be VLAs in
C are ordinary constant-size arrays in C++.)

Yes, that's correct. Another thing I find strange in C: why isn't
'const int' a constant expression?


Because "const" doesn't really mean "constant" (at least not in the
sense used in the phrase "constant expression"); it means "read-only".

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
srand(time(NULL));
const int r = rand();
printf("r = %d\n", r);
return 0;
}

Yes, the similarity between the word "constant" and the keyword
"const" is an unforunate source of confusion.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 17 '06 #26

P: n/a
On 2006-06-17, Ian Collins <ia******@hotmail.com> wrote:
Keith Thompson wrote:
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:


[...]
It also has declarations following statements within a block. Both of
these features are supported by C99 but not by C90. (They're also
supported by C++, and possibly by some C90 compilers in a
non-conforming mode.)
No, VLAs are not supported by C++ (yet). A constant expression is
required. g++ has them as an (irritating for porters) extension.

See, that's what I get for discussing C++ in comp.lang.c!

(I was probably thinking of the fact that C++ has a looser definition
of constant expressions than C has; some things that would be VLAs in
C are ordinary constant-size arrays in C++.)

Yes, that's correct. Another thing I find strange in C: why isn't
'const int' a constant expression?


Well, there is a difference: A "constant expression" must be known at
compile-time, a const int can be initialized with an expression that
isn't evaluated until runtime, you just can't (or shouldn't) then change
the value. I may be wrong (and hope to be corrected if I am), but I
don't think "casting away const" causes any undefined behaviour.

In C++ you've got some special rules that mean "const int a = 2;" can
safely go in a header-file (i.e. you can include it in a lot of source
files and not end up with "duplicate symbol" errors), and works pretty
much just like "#define a (2)". But in "const int b = f();", "const int"
has a meaning much closer to what it always means in C.

I find this strange in C++.
Jun 17 '06 #27

P: n/a
Ben C wrote:
On 2006-06-17, Ian Collins <ia******@hotmail.com> wrote:
Another thing I find strange in C: why isn't
'const int' a constant expression?

Well, there is a difference: A "constant expression" must be known at
compile-time, a const int can be initialized with an expression that
isn't evaluated until runtime, you just can't (or shouldn't) then change
the value. I may be wrong (and hope to be corrected if I am), but I
don't think "casting away const" causes any undefined behaviour.

const int a = 2;
*(int*)(&a) = 3;

would cause UB.
In C++ you've got some special rules that mean "const int a = 2;" can
safely go in a header-file (i.e. you can include it in a lot of source
files and not end up with "duplicate symbol" errors), and works pretty
much just like "#define a (2)". But in "const int b = f();", "const int"
has a meaning much closer to what it always means in C.

I find this strange in C++.


Touché!

"const int a = 2;" is a compile time constant, where as "const int b =
f();" isn't.

I guess the clarity of the distinction depends on one's view of the world.

--
Ian Collins.
Jun 17 '06 #28

P: n/a
Ian Collins wrote:
.... snip ...
Also gcc has supported variable length arrays as an extension for
many years. I've suffered the pain of porting from gcc more than
once.


gcc, without suitable parameters, is NOT a C compiler. The minimum
recommended options for using it for portable coding are:

gcc -W -Wall -ansi -pedantic

which will convert it into a first class C90 compiler. You can
replace -ansi with -std=C99 to have a fairly good C99 compiler. I
add -O1 -Wwrite-strings -Wfloat-equal.

Note that non-portable code is NOT discussed here.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Jun 17 '06 #29

P: n/a
CBFalconer wrote:
Ian Collins wrote:

.... snip ...
Also gcc has supported variable length arrays as an extension for
many years. I've suffered the pain of porting from gcc more than
once.

gcc, without suitable parameters, is NOT a C compiler. The minimum
recommended options for using it for portable coding are:

gcc -W -Wall -ansi -pedantic

which will convert it into a first class C90 compiler. You can
replace -ansi with -std=C99 to have a fairly good C99 compiler. I
add -O1 -Wwrite-strings -Wfloat-equal.

Note that non-portable code is NOT discussed here.

Yawn...

But C99 is and the above mentioned gcc extension has been incorporated
into the standard.

--
Ian Collins.
Jun 17 '06 #30

P: n/a
Richard Heathfield <in*****@invalid.invalid> writes:
[...] your C compiler is required to issue a diagnostic message
for the above code, which violates this constraint: "The
expression that specifies the size of an array shall be an
integral constant expression that has a value greater than
zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.


I am not sure it is required, because of the following dictum in
the standard (in C99 it's 6.6p10; I seem to recall seeing the
same sentence in C90):

An implementation may accept other forms of constant
expressions.
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Jun 18 '06 #31

P: n/a
Ben Pfaff said:
Richard Heathfield <in*****@invalid.invalid> writes:
[...] your C compiler is required to issue a diagnostic message
for the above code, which violates this constraint: "The
expression that specifies the size of an array shall be an
integral constant expression that has a value greater than
zero." Since limit+1 is not an integral constant expression, a
diagnostic message is required.


I am not sure it is required, because of the following dictum in
the standard (in C99 it's 6.6p10; I seem to recall seeing the
same sentence in C90):

An implementation may accept other forms of constant
expressions.


I can't find that phrase in my C89 draft. A final trumps a draft, of course,
but I think my draft is quite close to the final. Do you have an exact cite
from C90?

Just to be clear that I have no quibble about its being legal C99, because
C99 does support VLAs. This is purely a C89/90/95/callitwhatyouwill issue.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 18 '06 #32

P: n/a
Ian Collins said:
CBFalconer wrote:
Ian Collins wrote:

.... snip ...
Also gcc has supported variable length arrays as an extension for
many years. I've suffered the pain of porting from gcc more than
once.

gcc, without suitable parameters, is NOT a C compiler. The minimum
recommended options for using it for portable coding are:

gcc -W -Wall -ansi -pedantic

which will convert it into a first class C90 compiler. You can
replace -ansi with -std=C99 to have a fairly good C99 compiler. I
add -O1 -Wwrite-strings -Wfloat-equal.

Note that non-portable code is NOT discussed here.

Yawn...

But C99 is and the above mentioned gcc extension has been incorporated
into the standard.


No, gcc's VLAs have not been incorporated into the Standard. The semantics
of gcc VLAs differs from that of C99 VLAs, according to gcc's own
documentation.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 18 '06 #33

P: n/a
Richard Heathfield wrote:

Ben Pfaff said:

I am not sure it is required, because of the following dictum in
the standard (in C99 it's 6.6p10; I seem to recall seeing the
same sentence in C90):

An implementation may accept other forms of constant
expressions.


I can't find that phrase in my C89 draft. A final trumps a draft,
of course, but I think my draft is quite close to the final.
Do you have an exact cite from C90?


ISO/IEC 9899: 1990

6.4 Constant expressions

Semantics

An implementation may accept other forms of constant expressions.

--
pete
Jun 18 '06 #34

P: n/a
Richard Heathfield wrote:
Ian Collins said:

But C99 is and the above mentioned gcc extension has been incorporated
into the standard.

No, gcc's VLAs have not been incorporated into the Standard. The semantics
of gcc VLAs differs from that of C99 VLAs, according to gcc's own
documentation.

My lesson for the day, I'd better go and look it up!

Cheers,

--
Ian Collins.
Jun 18 '06 #35

P: n/a
pete said:
Richard Heathfield wrote:

Ben Pfaff said:

> I am not sure it is required, because of the following dictum in
> the standard (in C99 it's 6.6p10; I seem to recall seeing the
> same sentence in C90):
>
> An implementation may accept other forms of constant
> expressions.


I can't find that phrase in my C89 draft. A final trumps a draft,
of course, but I think my draft is quite close to the final.
Do you have an exact cite from C90?


ISO/IEC 9899: 1990

6.4 Constant expressions

Semantics

An implementation may accept other forms of constant expressions.


Fair enough. The obvious implication is that a developer may get a clean
compile on one implementation, and yet get a show-stopping constraint
violation on another.

So, if your goal is portable code, steer clear.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 18 '06 #36

P: n/a
CBFalconer wrote:

ce**********@hotmail.com wrote:

I've written this coin toss program, and can't figure out why it isn't
giving accurate results...
cheers,
Ben

#include <stdlib.h>
#include <stdio.h>
#define H 1
#define T 0
#define SENTINEL -1

int count=0, seed=3645, limit=200, in_a_row=6, iterations=100;

void one_run(int seed_passed)
{
int i, x, row_h;
row_h = 0;

seed=(1+seed_passed);
srand(seed);

char A[limit+1];


This code should not compile unless you have a C99 system, which I
doubt. limit+1 is not a constant, so the compiler has no idea what
to do. In addition, you are defining storage after executable
code. Turn up your warning levels. Also you are allowed to use
blanks in expressions, the blank embargo was lifted some years ago.

....and you can take that to the blank. I laughed all the way...

--
+----------------------------------------------------------------+
| Charles and Francis Richmond richmond at plano dot net |
+----------------------------------------------------------------+
Jun 18 '06 #37

P: n/a
Ben
Hi,
I don't know what your problem is but I will make some observations anyway.
My initial problem was that I had read in a maths book that the average
no. of 6 heads in a row in a sequence of 200 tosses was at least one...
my program kept providing 0.77
I have since realised that they must have meant "at least 6"...
First of all, get rid of the global variables. There is no need to resort
to global variables in a program this small and simple.
I only started learning programming a few months ago- so I'm not sure
what the problem is with global variables? (And what's an alternative?)
Is there any reason not to use enum instead of the #defines? They are more
appropriate and would probably do what you want.
The #defines seem to do what I want - enums might be more appropriate,
but I haven't yet learnt what they are :)
Don't use the sentinel. Sentinels are something you resort to when there is
a good reason. There is no good reason here.
The sentinel seemed easy enough to use - what potential problems are
there with using them? Why are they only a last resort?
Reduce the program to its essence. You seem to be able to handle command
line, a default set of data, or user supplied data. This is just
obfuscating things right now. Choose one. I would use built in data for
initial testing.
The command line data is just for the seed, so I can manually assess
the degree of probability accuracy ... the default data is probably
unnecessary.
Pay attention to the definition of in_a_row. Does it mean *exactly* n in a
row? The code says no. To determine that your code would have to look at
the next character - the one that breaks the sequence- , and it doesn't do
that. To me, exactly is the most sensible thing to compute. For example,
if in_a_row is 3 what does the following sequence of heads get counted as:
001111111100 ?
It does compute 'exactly x in a row' ... which is what I intended...
(it looks at the character that breaks the sequence when 'i' is
incremented - which breaks the while loop)

while(A[i]==H)
{
i++;
row_h++;
}

if(row_h==in_a_row)
count++;

row_h=0;
I tried the corner cases, in a row = 1 and in a row = 0 and got strange
results.
You might refuse to accept such questions as n = 1 in the final version of
your code.


I'd like to be able to test for n=1 ... so I'll keep trying :)
If n=0, I could just assign the number of tosses to n, and test for
that instead.
x=(int)(2.0*rand()/(1.0+RAND_MAX));


Too complicated.

Note that if the number drawn is less than 1/2 RAND_MAX, you have divided
the distribution into two almost equal parts.


My uni textbook says "If you need your program to be portable, and
require the values to be uncorelated even when compiled with the
original rand and srand functions, you should extract the desired value
from high-order bits rather than low-order ones..."
(av_occur=1.0*count/iterations);


What are those parens for? Just a kind of idle question.


I'm a newbie ... by habbit I tend to stick in as many extra parens as
possible ;)
(I realise now they are reduntant).

Jun 18 '06 #38

P: n/a
On 2006-06-18, Ben <ce**********@hotmail.com> wrote:
Hi,
I don't know what your problem is but I will make some observations anyway.


My initial problem was that I had read in a maths book that the average
no. of 6 heads in a row in a sequence of 200 tosses was at least one...
my program kept providing 0.77
I have since realised that they must have meant "at least 6"...
First of all, get rid of the global variables. There is no need to resort
to global variables in a program this small and simple.


I only started learning programming a few months ago- so I'm not sure
what the problem is with global variables? (And what's an alternative?)

Globals are very difficult to maintain; it is impossible to tell what
functions modify the variables, and where. Much better to pass each variable
to each function.
Is there any reason not to use enum instead of the #defines? They are more
appropriate and would probably do what you want.


The #defines seem to do what I want - enums might be more appropriate,
but I haven't yet learnt what they are :)

enums are lists of variables:

enum MyList { itemOne, itemTwo, itemThree };

results in itemOne being 0, itemTwo being 1, and itemThree being 2. You can
also add in definitions:

enum MyList { itemOne, itemTwo = 9, itemThree };

will set itemTwo to 9.
Don't use the sentinel. Sentinels are something you resort to when there is
a good reason. There is no good reason here.


The sentinel seemed easy enough to use - what potential problems are
there with using them? Why are they only a last resort?

Sentinel values are difficult to read and maintain; there are far more elgant
solutions to most problems.
Reduce the program to its essence. You seem to be able to handle command
line, a default set of data, or user supplied data. This is just
obfuscating things right now. Choose one. I would use built in data for
initial testing.


The command line data is just for the seed, so I can manually assess
the degree of probability accuracy ... the default data is probably
unnecessary.

Ensure that your program will work with default values /first/, and then add
functionality for command lines. There's a reason that people are paid large
sums of money for programming: it isn't a one-step easy-to-do process.
Pay attention to the definition of in_a_row. Does it mean *exactly* n in a
row? The code says no. To determine that your code would have to look at
the next character - the one that breaks the sequence- , and it doesn't do
that. To me, exactly is the most sensible thing to compute. For example,
if in_a_row is 3 what does the following sequence of heads get counted as:
001111111100 ?


It does compute 'exactly x in a row' ... which is what I intended...
(it looks at the character that breaks the sequence when 'i' is
incremented - which breaks the while loop)

while(A[i]==H)
{
i++;
row_h++;
}

if(row_h==in_a_row)
count++;

row_h=0;

Don't use tabs on Usenet; use either 2 or 4 spaces for indentation. I've
heard of people using 3 spaces as well. Anything higher or lower is difficult
to read.
I tried the corner cases, in a row = 1 and in a row = 0 and got strange
results.
You might refuse to accept such questions as n = 1 in the final version of
your code.


I'd like to be able to test for n=1 ... so I'll keep trying :)
If n=0, I could just assign the number of tosses to n, and test for
that instead.


if (n == 1)
{
/* Do stuff here */
}

Tests aren't hard in programming languages.
> x=(int)(2.0*rand()/(1.0+RAND_MAX));


Too complicated.

Note that if the number drawn is less than 1/2 RAND_MAX, you have divided
the distribution into two almost equal parts.


My uni textbook says "If you need your program to be portable, and
require the values to be uncorelated even when compiled with the
original rand and srand functions, you should extract the desired value
from high-order bits rather than low-order ones..."

I can't imagine how you would make a program "portable" in that you will always
get reasonably random values. If I was in a malicious mood, I could develop a
system where rand() would always return an integer between 0.9 and 1.1.
> (av_occur=1.0*count/iterations);


What are those parens for? Just a kind of idle question.


I'm a newbie ... by habbit I tend to stick in as many extra parens as
possible ;)
(I realise now they are reduntant).

"habit" is how it is spelled. In general, you should avoid unnecessary
parentheses except in long or esoteric expressions.

Ex. x = (y << 3) + b;
x = (a + b) + (c - b) * (r + a) / ((t == y) ? m : n);

I hope that you never type that second one. :-)

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.
Jun 18 '06 #39

P: n/a
Andrew Poelstra <ap*******@localhost.localdomain> writes:
[...]
enums are lists of variables:

enum MyList { itemOne, itemTwo, itemThree };

results in itemOne being 0, itemTwo being 1, and itemThree being 2. You can
also add in definitions:


Quibble: constants, not variables.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 18 '06 #40

P: n/a
"Ben" wrote:
My initial problem was that I had read in a maths book that the average
no. of 6 heads in a row in a sequence of 200 tosses was at least one...
my program kept providing 0.77
I have since realised that they must have meant "at least 6"...
AFAICT they really meant exactly. I get about 1.5 "hits" under the problem
as I understand it.
First of all, get rid of the global variables. There is no need to
resort
to global variables in a program this small and simple.
I only started learning programming a few months ago- so I'm not sure
what the problem is with global variables? (And what's an alternative?)


Move the variables above main so they are included in main, or to whoever
they belong to. The idea is to pass information by passing paramters.
The #defines seem to do what I want - enums might be more appropriate,
but I haven't yet learnt what they are :)


That's a prefectly good reason.
Don't use the sentinel. Sentinels are something you resort to when there
is
a good reason. There is no good reason here.


The sentinel seemed easy enough to use - what potential problems are
there with using them? Why are they only a last resort?


Not many problems, they just make you look like a student. Instructors
often teach the use of sentinels to avoid teaching how to handle end of
file. The thought is that sentinels are easier to understand, and I agree.
But real programmers use end of file.

Pay attention to the definition of in_a_row. Does it mean *exactly* n in
a
row? The code says no. To determine that your code would have to look at
the next character - the one that breaks the sequence- , and it doesn't
do
that. To me, exactly is the most sensible thing to compute. For
example,
if in_a_row is 3 what does the following sequence of heads get counted
as:
001111111100 ?


It does compute 'exactly x in a row' ... which is what I intended...
(it looks at the character that breaks the sequence when 'i' is
incremented - which breaks the while loop)

while(A[i]==H)
{
i++;
row_h++;
}

if(row_h==in_a_row)
count++;

row_h=0;


I goofed and missed that. It is really hard to study code with no
indentation. And no comments. And no paycheck for all the effort. That (the
general area) was my leading candidate for the trouble you were having. So
you are back at square zero WRT my help.
> x=(int)(2.0*rand()/(1.0+RAND_MAX));


Too complicated.

Note that if the number drawn is less than 1/2 RAND_MAX, you have divided
the distribution into two almost equal parts.


My uni textbook says "If you need your program to be portable, and
require the values to be uncorelated even when compiled with the
original rand and srand functions, you should extract the desired value
from high-order bits rather than low-order ones..."


But they are talking really small numbers, like six (sides on a die). Not
half the numbers.
> (av_occur=1.0*count/iterations);


What are those parens for? Just a kind of idle question.


I'm a newbie ... by habbit I tend to stick in as many extra parens as
possible ;)


Better too many than too few. Much better.

If you want to indent and repost, I will take a fresh look at what you have.
I was bothered mostly by not knowing what it was that it was supposed to
compute.

Here's another cut at it. It is wordier than most C programs, in the hopes
of retaining some clarity. The array, as I suspect you already knew, was
just a crutch. There might be some ideas you can use. Or then it could be
all wrong. Probability and statistics are real bears. I tried to derive
the answer you quote from your book and couldn't get it.
------
#include <stdio.h>
#include <stdlib.h> // abort
#include <time.h> // time

// count the number of times that there are exactly w heads in a row
int count(int w)
{
if(w<2)
{
printf("Function count is not intended to work\nfor sequences "
"of lengths less than 2.\n\n"
"Aborting\n");
getchar();
abort();
}
static int mid_pt = RAND_MAX / 2.0;
int on = 0; // state. on means "in count mode"
int ct = 0; // number of occurances of heads
int bit = 0; // the coin. 1 is a head
int last = 0; // results for preceding flip
int k = 0; // number of heads in *this* sequence
int i;
for(i=1; i<128; i++)
{
bit = rand();
bit = (bit<mid_pt) ? 0 : 1;
if(bit && !last) // transition to heads
{
k = 1;
on = 1;
}
else if(!bit && last) // transition to tails
{
k++; // count this flip
if(k == w)
ct++; // count the winners
k = 0;
on = 0; // back to passive mode
}
else if(on && bit) // another head
k++;
else
/* do nothing */;
last = bit;
}
return ct;
} // end function
//====================
int main()
{
srand(time(NULL));
int sum = 0;
int n = 6; /* count the number of times there are *exactly* n heads in a
row.*/
int i;
for(i=1; i<1000; i++)
sum += count(n);
printf("Mean number of times there were exactly %d heads: %g",
n, (sum/1000.0) );
getchar();
}

Jun 18 '06 #41

P: n/a
"osmium" <r1********@comcast.net> writes:
"Ben" wrote:

[...]
The sentinel seemed easy enough to use - what potential problems are
there with using them? Why are they only a last resort?


Not many problems, they just make you look like a student. Instructors
often teach the use of sentinels to avoid teaching how to handle end of
file. The thought is that sentinels are easier to understand, and I agree.
But real programmers use end of file.


Using a sentinel when reading a file, rather than checking for EOF, is
rarely a good idea. But sentinels can be useful in other contexts.

Consider a function that takes a variable number of pointer arguments.
Using a null pointer as a sentinel is a reasonable approach.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 18 '06 #42

P: n/a
On 2006-06-17, Ian Collins <ia******@hotmail.com> wrote:
Ben C wrote:
On 2006-06-17, Ian Collins <ia******@hotmail.com> wrote:
Another thing I find strange in C: why isn't
'const int' a constant expression?

Well, there is a difference: A "constant expression" must be known at
compile-time, a const int can be initialized with an expression that
isn't evaluated until runtime, you just can't (or shouldn't) then change
the value. I may be wrong (and hope to be corrected if I am), but I
don't think "casting away const" causes any undefined behaviour.

const int a = 2;
*(int*)(&a) = 3;

would cause UB.


Why? Is this something to do with "type-punning"-- we're taking the
address of an object of one type (const int) and making a pointer to
another type (int) point to it, then dereferencing. This is always UB.
It allows for machines to use different sizes and shapes of pointers to
different types if they want to.

But

const int a = 2;
(int) a = 3;

is not UB, right?
In C++ you've got some special rules that mean "const int a = 2;" can
safely go in a header-file (i.e. you can include it in a lot of source
files and not end up with "duplicate symbol" errors), and works pretty
much just like "#define a (2)". But in "const int b = f();", "const int"
has a meaning much closer to what it always means in C.

I find this strange in C++.


Touché!

"const int a = 2;" is a compile time constant, where as "const int b =
f();" isn't.

I guess the clarity of the distinction depends on one's view of the world.


IIRC, in "The Design and Evolution of C++" Stroustrup justifies this as
part of a general crusade against the C preprocessor (which he aptly
describes as a "bulldozer").

In C# you get two different keywords-- "readonly" and "const" instead of
using "const" to mean both.
Jun 18 '06 #43

P: n/a
Richard Heathfield wrote:
Ian Collins said:
CBFalconer wrote:

This code should not compile unless you have a C99 system, which I
doubt.


Why? Compiles fine with either compiler on mine.


If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us,


GCC seems to be the most common compiler around. In
its default mode it accepts many C99 constructs. So I
think your figure should be revised downwards somewhat.

Jun 18 '06 #44

P: n/a
Ben C wrote:
But

const int a = 2;
(int) a = 3;

is not UB, right?


Well, it should fail to compile. (int)a is not an lvalue.

Whether or not constraint violations are UB is a bit of an
academic matter (half the NG seems to think they are and
half think they aren't).

Jun 18 '06 #45

P: n/a
"osmium" writes:
Here's another cut at it.


I see the copy I posted is where I was fooling around trying to see how many
trials it took to get a result of 1.0 It is in the vicinity of 128 trials.
Change the 128 to 200 to customize this to your question. Also note this
was compiled on a compiler that accepts some C99 syntax, E.g., \\ comments.

Note that if you had six coins and flipped them all, you would get six heads
with probability .0156 . That's available from tables of the binomial
distribution. A good statistics book will have that in the appendix.
Jun 19 '06 #46

P: n/a
Eric Sosman wrote:
For example,

int array[] = { 1, 2, 3 }, *p = array + 1;
printf ("%d\n", SENTINEL[p]);

... outputs "-3\n" if SENTINEL is -1, but "1\n" if it
is (-1).

(I *think* the only way to form an expression where
the presence or absence of parentheses around -1 makes
a difference is to use the bass-ackward array notation
as above. Can anyone come up with another?)


In pre-ANSI C we had:

int a = 1;
a =SENTINEL;

forming the =- operator.

Technically there is this:
#define PP(X) #X
#define PS(X) PP(X)

size_t value = sizeof PS(SENTINEL);
The only binary operators with higher precedence that unary
minus are () [] -> . and I don't see how to apply any of
them apart from [].

We could have:

void f(int i) { }

meaning that
f SENTINEL

is an expression (albeit, an expression that violates a constraint
in the no-brackets case).

Jun 19 '06 #47

P: n/a
Keith Thompson wrote:

Using a sentinel when reading a file, rather than checking for EOF, is
rarely a good idea. [...]


I'd say that using a sentinel (or equivalent, e.g. an
embedded count) is mandatory when reading a binary stream.
How else will you know when you've read all the data -- and
only the data?

--
Eric Sosman
es*****@acm-dot-org.invalid
Jun 19 '06 #48

P: n/a
Old Wolf wrote:
Richard Heathfield wrote:
Ian Collins said:
CBFalconer wrote:

This code should not compile unless you have a C99 system,
which I doubt.

Why? Compiles fine with either compiler on mine.


If you're using a C99 compiler, well, fair enough. If you're using
a compiler adhering to an older standard, like 99.90813774% of us,


GCC seems to be the most common compiler around. In
its default mode it accepts many C99 constructs. So I
think your figure should be revised downwards somewhat.


If you disapprove, I suggest you supply an equally precise revised
value. Otherwise why criticize the extensive research that has
gone into Richards figure? After all, 9 nines precision is not to
be sneezed at, and it does imply that Richard has polled at least
10E9 C users.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Jun 19 '06 #49

P: n/a
Eric Sosman <es*****@acm-dot-org.invalid> writes:
Keith Thompson wrote:
Using a sentinel when reading a file, rather than checking for EOF,
is
rarely a good idea. [...]


I'd say that using a sentinel (or equivalent, e.g. an
embedded count) is mandatory when reading a binary stream.
How else will you know when you've read all the data -- and
only the data?


I'm sure a lot of programs just read the entire file, but I realize
the standard allows binary files to be padded with zero bytes.

For a file that's just a linear sequence of fixed-size records,
reading up to EOF (at the cost of possibly not working on systems that
do padding) might be good enough. For anything more complex, the
structure of the file itself should tell indicate where the valid data
is (<PEDANTIC>are</PEDANTIC>). A sentinel is one of many possible
ways to do that.

Of course, C strings use '\0' as a sentinel value; the cost is that
you can't have '\0' in the string itself.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 19 '06 #50

52 Replies

This discussion thread is closed

Replies have been disabled for this discussion.