derangement: code review request

M

Merrill & Michele

MPJ:
[undeclared function]
Are you surprised?

No, I just couldn't figure out what the errors that the compiler was spewing
out meant. I forgot to declare the function. That I posted what I had was
a filibuster of sorts with regards to my newsreader. I'm going to get this
code right and stylistically acceptable. I really do not appreciate
disparagement when I'm working my ass off (elsethread directed). Last
night, I asked my uncle why he didn't use K&R to teach. I thought his
answer was interesting, but I wouldn't want to trouble this forum with my 2
decades of meta-ideas. MPJ
 
M

Merrill & Michele

/*derangement2 contributors: Eric Sosman, Dan Pop, Michael Mair*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FAMSIZ 20 /* between 2 and 2,000 */

int main(void){

int i, m, n, t, topnum, buysfor[FAMSIZ];
void swap(int *px, int *py);

/* get vanilla rand started well */
srand(time(NULL));
topnum = RAND_MAX - (RAND_MAX % FAMSIZ) - 1;
for (i = 0; i < 9; ++ i) t = rand();

/* initialize and permute */
for (i = 0; i < FAMSIZ; ++ i) buysfor = i;
m = 0;
while (m < FAMSIZ){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
swap (&buysfor[m] , &buysfor[n]);
++ m;
}

/*out to console*/
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",i);
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor);
putchar('\n');

/* remove collisions */
for (m = 0; m < FAMSIZ; ++ m){
while (buysfor[m] == m){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
if ((n == m) || (buysfor[m] == n)) continue;
swap (&buysfor[m] , &buysfor[n]);
}
}

/* to console*/

for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor);
putchar('\n');

return 0;
}

void swap(int *px, int *py){
int noscope;
noscope = *px;
*px = *py;
*py = noscope;
}

I think I finally got it. I couldn't get my head around the do-while
control loops. MPJ
 
Z

ZF Tang

Merrill & Michele said:
/*derangement2 contributors: Eric Sosman, Dan Pop, Michael Mair*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FAMSIZ 20 /* between 2 and 2,000 */

int main(void){

int i, m, n, t, topnum, buysfor[FAMSIZ];
void swap(int *px, int *py);

/* get vanilla rand started well */
srand(time(NULL));
topnum = RAND_MAX - (RAND_MAX % FAMSIZ) - 1;
for (i = 0; i < 9; ++ i) t = rand();

/* initialize and permute */
for (i = 0; i < FAMSIZ; ++ i) buysfor = i;
m = 0;
while (m < FAMSIZ){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
swap (&buysfor[m] , &buysfor[n]);
++ m;
}

/*out to console*/
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",i);
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor);
putchar('\n');

/* remove collisions */
for (m = 0; m < FAMSIZ; ++ m){
while (buysfor[m] == m){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
if ((n == m) || (buysfor[m] == n)) continue;
swap (&buysfor[m] , &buysfor[n]);
}
}

/* to console*/

for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor);
putchar('\n');

return 0;
}

void swap(int *px, int *py){
int noscope;
noscope = *px;
*px = *py;
*py = noscope;
}

I think I finally got it. I couldn't get my head around the do-while
control loops. MPJ
 
M

Michael Mair

Merrill said:
MPJ:

[undeclared function]
Are you surprised?

No, I just couldn't figure out what the errors that the compiler was spewing
out meant. I forgot to declare the function.

Er... No. You tried to define a function within another function.
Read the stuff about function definitions and declarations/prototypes
once more with special emphasis on where to put them.
That I posted what I had was
a filibuster of sorts with regards to my newsreader. I'm going to get this
code right and stylistically acceptable.

Yep, and we are ready to help you do that.
I really do not appreciate
disparagement when I'm working my ass off (elsethread directed).

The code you posted was so obviously not valid C code that Dan
and I assumed you are aware of that. Had you asked why it does
not compile, we would have pointed out your mistakes.
Apart from that: I was not disparaging you but your mode of
using this newsgroup.
Last
night, I asked my uncle why he didn't use K&R to teach. I thought his
answer was interesting, but I wouldn't want to trouble this forum with my 2
decades of meta-ideas.

*g* That really rankled, did it? SCNR
Apart from that, you would trouble us with your uncle's reasons.

Personally, I do not use K&R to teach, either, due to the circumstances.


Cheers
Michael
 
M

Merrill & Michele

Michael Mair said:
Merrill said:
MPJ:
:

"Merrill & Michele

[undeclared function]
void swap(int *px, int *py){
doesn't compile
Are you surprised?

No, I just couldn't figure out what the errors that the compiler was spewing
out meant. I forgot to declare the function.

Er... No. You tried to define a function within another function.
Read the stuff about function definitions and declarations/prototypes
once more with special emphasis on where to put them.
That I posted what I had was
a filibuster of sorts with regards to my newsreader. I'm going to get this
code right and stylistically acceptable.

Yep, and we are ready to help you do that.
I really do not appreciate
disparagement when I'm working my ass off (elsethread directed).

The code you posted was so obviously not valid C code that Dan
and I assumed you are aware of that. Had you asked why it does
not compile, we would have pointed out your mistakes.
Apart from that: I was not disparaging you but your mode of
using this newsgroup.
Last
night, I asked my uncle why he didn't use K&R to teach. I thought his
answer was interesting, but I wouldn't want to trouble this forum with my 2
decades of meta-ideas.

*g* That really rankled, did it? SCNR
Apart from that, you would trouble us with your uncle's reasons.

Personally, I do not use K&R to teach, either, due to the circumstances.
Did you see the final code posting? I think I got it. What does SCNR mean?
That didn't rankle. It was the "annoying, inane white noise" that go my
dander up. MPJ
 
M

Michael Mair

Merrill said:
>
Did you see the final code posting? I think I got it. What does SCNR mean?
That didn't rankle. It was the "annoying, inane white noise" that go my
dander up. MPJ

Well, it is not exactly the most clever idea to put the
prototype of swap() _inside_ another function. This makes it
possible to miss a few prototypes at changes and makes you type these
prototypes again and again as soon as you get to use more functions
and write complex code coming in several files.
Prototypes and typedefs usually (there are exceptions) should be
found at file scope or in header files, prior to your function
definitions.
Apart from that, it should work fine.

SCNR=Sorry, could not resist.

About the other: I really did not understand that you had a problem
and thought that you abused c.l.c as scratch for ideas not very
well thought out. As the stuff you posted obviously (for me) would
never ever compile, it seemed more like a collection of not so
well-ordered thoughts. Thus "white noise" and "inane".


Cheers,
Michael
 
M

Merrill & Michele

Michael Mair said:
Well, it is not exactly the most clever idea to put the
prototype of swap() _inside_ another function. This makes it
possible to miss a few prototypes at changes and makes you type these
prototypes again and again as soon as you get to use more functions
and write complex code coming in several files.
Prototypes and typedefs usually (there are exceptions) should be
found at file scope or in header files, prior to your function
definitions.
Apart from that, it should work fine.

SCNR=Sorry, could not resist.

About the other: I really did not understand that you had a problem
and thought that you abused c.l.c as scratch for ideas not very
well thought out. As the stuff you posted obviously (for me) would
never ever compile, it seemed more like a collection of not so
well-ordered thoughts. Thus "white noise" and "inane".

You asked earlier about why my uncle didn't go with K&R. It would be a very
bad idea for me to reveal the contents of such calls. Let me instead claim
that my uncle doesn't exist, and that my keystrokes are a collection of less
than well ordered thoughts. With that premise and caveat, I offer the
following criticism of K&R:

Q1) Is paper so precious that they couldn't include the swap function in its
full, isolated glory:

#include <stdio.h>
void swap(int *coconut, int *banana);
int main(void){
int a = 3;
int b = 5;
swap(&a, &b);
printf ("a equals %d\n", a);
printf ("b equals %d\n", b);
return 0;
}
void swap(int *px, int *py){
int tmp = *px;
*px = *py;
*py = tmp;
}

You err when you say that it was not the most clever idea for me to put the
function prototype within main. It wasn't an idea at all! I was just
trying to get something to work, and all my compiler was telling me was that
I was missing a semicolon. Further questions:

Q2) The following builds and behaves for me fine. Why do you make the
arguments in the prototype look like they matter?

#include <stdio.h>
void swap(int, int);
int main(void){
int a = 3;
int b = 5;
swap(&a, &b);
printf ("a equals %d\n", a);
printf ("b equals %d\n", b);
return 0;
}
void swap(int *px, int *py){
int tmp = *px;
*px = *py;
*py = tmp;
}

The election was a hard time for this native and politically-active Ohioan.
For thoughtful interaction at clc during this period I am grateful. MPJ
 
M

Mark McIntyre

Q2) The following builds and behaves for me fine. Why do you make the
arguments in the prototype look like they matter?

The declaration or prototype tells the compiler what type of arguments to
expect. If you then pass the wrong types, it has to convert them. This may
be impossible. Or it may convert it to some garbage value. For example,
passing 1 to a function expecting a pointer might cause it to create a
pointer to memory address 1, which is often inside hardware memory. This is
very likely to crash your computer.

Some computers even use different memory locations for different types of
object - 680x0 chips spring to mind - and so telling a function to expect
an int then feeding it a pointer will cause it to fetch an int from the
garbage heap.

#include <stdio.h>
void swap(int, int);
void swap(int *px, int *py){

If your compiler doesn't complain about this, you need to turn up
warninglevels, or get a better compiler. Your example is undefined
behaviour. Not only that, but despite appearances its not working - its
merely pretending to work ,and later on ,say when you demonstrate some code
to a customer, it will crash spectacularly, probably setting fire to his
club tie and pouring brake fluid on his porsche.
 
M

Merrill & Michele

Mark McIntyre said:
The declaration or prototype tells the compiler what type of arguments to
expect. If you then pass the wrong types, it has to convert them. This may
be impossible. Or it may convert it to some garbage value. For example,
passing 1 to a function expecting a pointer might cause it to create a
pointer to memory address 1, which is often inside hardware memory. This is
very likely to crash your computer.

Some computers even use different memory locations for different types of
object - 680x0 chips spring to mind - and so telling a function to expect
an int then feeding it a pointer will cause it to fetch an int from the
garbage heap.




If your compiler doesn't complain about this, you need to turn up
warninglevels, or get a better compiler. Your example is undefined
behaviour. Not only that, but despite appearances its not working - its
merely pretending to work ,and later on ,say when you demonstrate some code
to a customer, it will crash spectacularly, probably setting fire to his
club tie and pouring brake fluid on his porsche.


My compiler doesn't complain if smoke's coming out of it. That's within my
thousand most important problems. You err to think that I would talk to a
customer who drives a Porsche. WTF is the point of having a porsche in
Minneslowta except to show that you're type A. To the topic though, would I
not be fine calling those prototypes *coconuts or *Krijn OR indeed would
void swap(int *a, int *a);
work swell? MPJ
 
M

Mark McIntyre

To the topic though, would I
not be fine calling those prototypes *coconuts or *Krijn

Anything is ok as long as the prototype matches the definition, and the
function call matches the prototype. This generally restricts how you do it
to sensible forms.
OR indeed would void swap(int *a, int *a);
work swell? MPJ

A function can't have two parameters with the same name, because its a
redefinition of the parameter.

Do you actually have a book about C?
 
M

Merrill & Michele

"Mark McIntyre:
Anything is ok as long as the prototype matches the definition, and the
function call matches the prototype. This generally restricts how you do it
to sensible forms.


A function can't have two parameters with the same name, because its a
redefinition of the parameter.

Do you actually have a book about C?

As a strict Copenhagener, right now I possess exactly one book on c. K&R2
§5.2 looks at the swap function and §5.11 looks at prototypes. Frankly, it
makes my head spin.

Q) Good form has prototypes before the main call. These prototypes take
arguments. MUST EVERY keystroke (excepting white space) match the arguments
of the ultimate function call in order to have defined behavior? MPJ
 
C

Chris Torek

Q) Good form has prototypes before the main call.

(I would take out the word "main" here: I have no idea what it is
doing in this sentence. I would say that "good form has prototypes
for functions before calls to those functions." It is also
generally wise to have those same prototypes appear before the
definition of the function as well, in more complicated situations
involving header files and separate compilation.)
These prototypes take arguments.

Yes. Note in particular that even a function that has no arguments
at all -- such as:

void print_header(void) {
puts("==== header ====");
}

for instance -- needs to have the "void" keyword in a prototype:

void print_header(void); /* prototype */

because writing this:

void print_header(); /* not a prototype! */

gives you a declaration, but not a prototype. (This is a historical
oddity having to do with adding prototypes in 1989, where C had
none before that. The ANSI committee folks decided not to change
the meaning of "old style" declarations, so they had to invent new
syntax: "the absence of arguments here means nothing about the
arguments; the presence of a `void' keyword means there are no
arguments".)
MUST EVERY keystroke (excepting white space) match the arguments
of the ultimate function call in order to have defined behavior? MPJ

No -- but it is often a good idea to have them match, even to the
very whitespace.

The part(s) of the prototype arguments that matter *to the compiler*
are the number and type of arguments:

void fA(void); /* zero arguments */
void fB(int, char *); /* two arguments: int, pointer-to-char */
void fC(double); /* one argument: double */

but the rest is useful to humans:

void do_some_operation(char *output, char *input, int operation);
void do_other_operation(char *input, int operation, char *output);

Here the compiler cares only that there are three arguments, two
of type "pointer to char" and one of type "int", but a person
writing code probably wants to know which "char *" is the "output"
and which one is the "input". We could leave out the name "operation",
because there is only one "int", and if an operation has to be an
int, it is immediately obvious which of the one (count them 1)
"int" parameters is the "int" parameter. :)

Of course, "good design" would also suggest that all of the
various "do an operation" functions take their input, output,
and operation parameters in the same places -- but having the
names, too, is a good thing.

Note that those who intentionally obfuscate their code (perhaps
in an attempt to obtain job security) might name their parameters
in a deliberately-confusing way:

void do_third_operation(char *kumquat, int output, char *lemon);

While the computer does not care, I will say that *I* care, and
would complain quite a bit about such code.
 
J

Joe Wright

Merrill said:
As a strict Copenhagener, right now I possess exactly one book on c. K&R2
§5.2 looks at the swap function and §5.11 looks at prototypes. Frankly, it
makes my head spin.

Q) Good form has prototypes before the main call. These prototypes take
arguments. MUST EVERY keystroke (excepting white space) match the arguments
of the ultimate function call in order to have defined behavior? MPJ
Not every keystroke.

The purpose of the prototype is to clue the compiler as to how to
call the library function. This clue allows the compiler to perform
permitted type conversions as needed.

The compiler is interested in the 'name' of the function and its
type and the type and number of its arguments.

Naming the arguments is optional and only to to make the prototype
more 'expressive' to the human reader. The compiler doesn't care
whether you name them or not.
 
P

pete

Chris said:
(I would take out the word "main" here: I have no idea what it is
doing in this sentence. I would say that "good form has prototypes
for functions before calls to those functions." It is also
generally wise to have those same prototypes appear before the
definition of the function as well, in more complicated situations
involving header files and separate compilation.)


Yes. Note in particular that even a function that has no arguments
at all -- such as:

void print_header(void) {
puts("==== header ====");
}

for instance -- needs to have the "void" keyword in a prototype:

void print_header(void); /* prototype */

because writing this:

void print_header(); /* not a prototype! */

gives you a declaration, but not a prototype. (This is a historical
oddity having to do with adding prototypes in 1989, where C had
none before that. The ANSI committee folks decided not to change
the meaning of "old style" declarations, so they had to invent new
syntax: "the absence of arguments here means nothing about the
arguments; the presence of a `void' keyword means there are no
arguments".)


No -- but it is often a good idea to have them match, even to the
very whitespace.

The part(s) of the prototype arguments that matter *to the compiler*
are the number and type of arguments:

void fA(void); /* zero arguments */
void fB(int, char *); /* two arguments: int, pointer-to-char */
void fC(double); /* one argument: double */

but the rest is useful to humans:

void do_some_operation(char *output, char *input, int operation);
void do_other_operation(char *input, int operation, char *output);

Here the compiler cares only that there are three arguments, two
of type "pointer to char" and one of type "int", but a person
writing code probably wants to know which "char *" is the "output"
and which one is the "input".
We could leave out the name "operation",
because there is only one "int", and if an operation has to be an
int, it is immediately obvious which of the one (count them 1)
"int" parameters is the "int" parameter. :)

Of course, "good design" would also suggest that all of the
various "do an operation" functions take their input, output,
and operation parameters in the same places -- but having the
names, too, is a good thing.

Note that those who intentionally obfuscate their code (perhaps
in an attempt to obtain job security) might name their parameters
in a deliberately-confusing way:

void do_third_operation(char *kumquat, int output, char *lemon);

While the computer does not care, I will say that *I* care, and
would complain quite a bit about such code.

A reason I don't like parameter names in prototypes is because they
can be more subtly misleading without being noticed by the compiler.
void do_other_operation(char *input, int operation, char *output);
vs.
void do_other_operation(char *output, int operation, char *input);
I think looking at the prototype is the wrong place
to see how to call the function.
 
H

Herbert Rosenau

A reason I don't like parameter names in prototypes is because they
can be more subtly misleading without being noticed by the compiler.
void do_other_operation(char *input, int operation, char *output);
vs.
void do_other_operation(char *output, int operation, char *input);
I think looking at the prototype is the wrong place
to see how to call the function.

No, its not. It is on YOU to document anything. A well documented
interface as a prototype is makes the usage of the fuction much
easier. Use simply exactly the same letters and numbers in both, the
prototype and definition and anything wents well.

When you have learned to design your programs instead of blindly
hacking around you would start with defining the interfaces, giving
the parameters selfspeaking names. In later stage you would copy the
prototypes to build the implementation of the function - having the
names of the formal parameters already ready.

At least when your editor knows what syntax expansion is you would
build the key files for that based on the prototype too - so you can
use abbrevations to expand them to full flagged parameter list,
helping you to remember what parameter is on which position, e.g.

Type waa+Alt+h would expand to
WinAddAtom(HATOMTBL hAtomTbl, PSZ pszAtomName);
and remember you that the first parameter needs to be a handle of an
atom table and the second to be the string to be converted to an atom.
Having good names selected for the parameter will save yopu often the
time to type them too.

So, even as the compiler ignores the names of the parameters YOU would
need them more often. That is why you needs self speaking names in
parameter lists. It is YOU who will save lots of typing and time when
using full flagged prototypes not only for system fuctions but for
functions used in your project only too.
 
M

Mark McIntyre

A reason I don't like parameter names in prototypes is because they
can be more subtly misleading without being noticed by the compiler.
void do_other_operation(char *input, int operation, char *output);
vs.
void do_other_operation(char *output, int operation, char *input);

In my book, thats a bug. Inconsistency and documentation failures are just
as much bugs as coding errors.
I think looking at the prototype is the wrong place
to see how to call the function.

Since its where the compiler looks, its the most important place !

And often its the only place, other than the printed manual. Think "library
function".
 
P

pete

Mark said:
In my book, thats a bug. Inconsistency and documentation failures are just
as much bugs as coding errors.


Since its where the compiler looks, its the most important place !

And often its the only place, other than the printed manual.
Think "library function".

OK. I'll think about it harder.
 
M

Merrill & Michele

At the risk of developing a larger reputation as a dullard, I would like to
continue this discussion at a level that I can understand. The following
code, I believe, produces exactly the behavior--with good style--that we're
looking for from K&R2 §5.

#include <stdio.h>
void swap(int *px, int *py);
int main(void){
int a = 3;
int b = 5;
swap(&a, &b);
printf ("a equals %d\n", a);
printf ("b equals %d\n", b);
return 0;
}
void swap(int *px, int *py){
int tmp = *px;
*px = *py;
*py = tmp;
}

Q1) Does anyone think that this is lacking in any fashion?
Q2) If prototype and declaration are not the same thing, then which line
number is which?

MPJ

P.S. I've read this thread, but I simply need to back up a bit.
 
P

pete

Merrill said:
At the risk of developing a larger reputation as a dullard, I would like to
continue this discussion at a level that I can understand. The following
code, I believe, produces exactly the behavior--with good style--that we're
looking for from K&R2 §5.

#include <stdio.h>
void swap(int *px, int *py);
int main(void){
int a = 3;
int b = 5;
swap(&a, &b);
printf ("a equals %d\n", a);
printf ("b equals %d\n", b);
return 0;
}
void swap(int *px, int *py){
int tmp = *px;
*px = *py;
*py = tmp;
}

Q1) Does anyone think that this is lacking in any fashion?

Could use some indentation and maybe some blank lines.


#include <stdio.h>

void swap(int *px, int *py);

int main(void)
{
int a = 3;
int b = 5;

swap(&a, &b);
printf ("a equals %d\n", a);
printf ("b equals %d\n", b);
return 0;
}

void swap(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
Q2) If prototype and declaration are not the same thing,
then which line number is which?

A prototype is one kind of declaration.
 
R

Richard Bos

pete said:
Could use some indentation and maybe some blank lines.

True, but this could be M$OE's fault rather than MPJ's. In any case,
there's nothing wrong with the code as such.
A prototype is one kind of declaration.

And in this case, all declarations are also prototypes. The first is a
prototype and a declaration, but not a definition; the other two are all
three.

Richard
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top