Weird usage of printf/scanf? Why do they work?

M

Meske Moday

I teach beginning C, and I've never run into this issue before. I have
a student who consistently uses the printf and scanf statements as
shown below. By all rights, I would have bet his programs wouldn't
compile. But they do...

Weird usage of printf:

printf( n, "^3 = ", cubed, "\n" ); /* n is an int */

and scanf:

scanf( "%d", &input1, &input2, &input3 ); /* variables are int's */

Compiling his code with "gcc -pedantic -ansi -Wall" doesn't generate
ANY errors. Checking it with splint generates the following message:

prog-2-1.c:23:12: Function printf expects arg 1 to be char * gets int: n
Types are incompatible.
prog-2-1.c:23:5: Format string parameter to printf is not a
compile-time constant: n
Format parameter is not known at compile-time. This can lead to security
vulnerabilities because the arguments cannot be type checked.

This same student uses scanf as shown above, with a single conversion
specification with three arguments. According to scanf specification
that I'm looking at (Linux-> man 3 scanf), scanf will evaluate the
excess pointer arguments, but otherwise ignores them. But it works! gcc
compiles again, without error. splint reports the following:

prog-2-3.c:21:5: Format string for scanf has 1 arg, given 3
Types are incompatible.

Any ideas? I want to tell the student this isn't correct, but I can't
seem to justify my gut instinct with any examples, since no one does
this! LOL And since his programs all compile cleanly and work properly,
I need something a little more concrete than my gut instinct.

Thanks for any thought comments.
Kevin
 
M

Morris Keesan

I teach beginning C, and I've never run into this issue before. I have a
student who consistently uses the printf and scanf statements as shown
below. By all rights, I would have bet his programs wouldn't compile.
But they do...

Weird usage of printf:

printf( n, "^3 = ", cubed, "\n" ); /* n is an int */

and scanf:

scanf( "%d", &input1, &input2, &input3 ); /* variables are int's */

Compiling his code with "gcc -pedantic -ansi -Wall" doesn't generate ANY
errors.

Does his code #include <stdio.h> ?
 
E

Eric Sosman

Meske said:
I teach beginning C, and I've never run into this issue before. I have a
student who consistently uses the printf and scanf statements as shown
below. By all rights, I would have bet his programs wouldn't compile.
But they do...

Weird usage of printf:

printf( n, "^3 = ", cubed, "\n" ); /* n is an int */

and scanf:

scanf( "%d", &input1, &input2, &input3 ); /* variables are int's */

Compiling his code with "gcc -pedantic -ansi -Wall" doesn't generate ANY
errors. Checking it with splint generates the following message:

prog-2-1.c:23:12: Function printf expects arg 1 to be char * gets int: n
Types are incompatible.
prog-2-1.c:23:5: Format string parameter to printf is not a compile-time
constant: n
Format parameter is not known at compile-time. This can lead to security
vulnerabilities because the arguments cannot be type checked.

This same student uses scanf as shown above, with a single conversion
specification with three arguments. According to scanf specification
that I'm looking at (Linux-> man 3 scanf), scanf will evaluate the
excess pointer arguments, but otherwise ignores them. But it works! gcc
compiles again, without error. splint reports the following:

prog-2-3.c:21:5: Format string for scanf has 1 arg, given 3
Types are incompatible.

Any ideas? I want to tell the student this isn't correct, but I can't
seem to justify my gut instinct with any examples, since no one does
this! LOL And since his programs all compile cleanly and work properly,
I need something a little more concrete than my gut instinct.

The scanf() stuff is explainable, at any rate: As you say,
the excess arguments are evaluated, but not otherwise used if
the format doesn't mention them (or if scanf() stops early for
some other reason).

The printf() thing is baffling, and all I can imagine is
that it's not the real printf() and/or it's not the real n.
Can you post a complete program, rather than just a snippet?
(If it's somebody else's work, I'm not sure what the copyright
situation might be ...)

One other thing to try is the "-W" flag -- despite the name,
gcc's "-Wall" does *not* turn on "all" diagnostics.
 
J

Jens Thoms Toerring

Eric Sosman said:
The printf() thing is baffling, and all I can imagine is
that it's not the real printf() and/or it's not the real n.
Can you post a complete program, rather than just a snippet?
(If it's somebody else's work, I'm not sure what the copyright
situation might be ...)

Perhaps there's a define like this somewhere well-hidden

#define printf(a,b,c,d) printf("%d%s%d%s",a,b,c,d)

and this is a joke by the student? Otherwise I would expect gcc
to emit a warning about a conversion from an int to a pointer
for the first argument of printf() (at least my version of gcc
complains about that even without any warning options)...

Regards, Jens
 
M

Meske Moday

Meske Moday said:
I teach beginning C, and I've never run into this issue before. I have
a student who consistently uses the printf and scanf statements as
shown below. By all rights, I would have bet his programs wouldn't
compile. But they do...

Weird usage of printf:

printf( n, "^3 = ", cubed, "\n" ); /* n is an int */

There's no way this should compile. Passing an int as the first
argument to printf is a constraint violation. (Well, a compiler
could produce a non-fatal warning for a constraint violation.)

If the first argument happens to be a string literal, there's no
constraint violation. printf's first argument is of type char*; the
other arguments are of (nearly) arbitrary types. The compiler cannot,
in general, enforce the rules, such as that "%d" requires an int
argument; it's up to the programmer to get this right.
and scanf:

scanf( "%d", &input1, &input2, &input3 ); /* variables are int's */

Additional arguments beyond what's specified by the format string are
quietly ignored.

[...]
Any ideas? I want to tell the student this isn't correct, but I can't
seem to justify my gut instinct with any examples, since no one does
this! LOL And since his programs all compile cleanly and work
properly, I need something a little more concrete than my gut instinct.

How about the fact that his code, even if it happens to compile,
doesn't produce the output he wants?

If you way the code actually works, can you post a concrete example (a
small complete program, not a code fragment)?

=======================================================
I'm posting the three assignments he completed. I'm honestly not
concerned about copyright given that these are common first course
programming assignments.

Script started on Mon Sep 7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c prog-2-2.c prog-2-3.c
darwin:~ kevin$ cat prog-2-1.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This Program accepts a user's integer (n) and
* returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int n; /* User's input integer */
int cubed; /* Variable which will store the user's variable, cubed */

printf("Enter an integer: "); /* prompt */
scanf("%d", &n); /* read an integer */

cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125
darwin:~ kevin$ cat prog-2-2.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This program accepts a user's input radius, and finds the
* area/circumference of that circle.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int radius; /* user's input radius */
float pi = 3.14159; /* approximation of Pi */

printf("Enter the radius of a circle: "); /* prompt */
scanf("%d", &radius); /* getting the user's radius */

printf("The area A of a circle with radius ", radius, " = %f",
pi * (radius * radius), "\n"); /* Printing the calculated area */

printf("The circumference C of a circle with radius ", radius,
" = %f", 2 * pi * radius, "\n"); /* Printing the calculated
circumference */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-2.c -o prog-2-2
darwin:~ kevin$ ./prog-2-2
Enter the radius of a circle: 10
The area A of a circle with radius 10 = 314.158997
The circumference C of a circle with radius 10 = 62.831802
darwin:~ kevin$ cat prog-2-3.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This program will return ths sum, average, product,
* smallest, and largest of 3 given integers.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{

int input1; /* User's first input integer */
int input2; /* User's second input integer */
int input3; /* User's third input integer */

printf("Input three different integers: "); /* prompt */
scanf("%d", &input1, &input2, &input3); /* get user input */

printf("Sum is ", input1 + input2 + input3, "\n"); /* printing sum */
printf("Average is ", (input1 + input2 + input3) / 3, "\n"); /*
printing average */
printf("Product is ", input1 * input2 * input3, "\n"); /* printing
product */


/* If block to find the smallest number */
if (input1 < input2 && input1 < input3){
printf("Smallest is ", input1, "\n");
} /* end if */
if (input2 < input1 && input2 < input3){
printf("Smallest is ", input2, "\n");
} /* end if */
if (input3 < input2 && input3 < input1){
printf("Smallest is ", input3, "\n");
} /* end if */


/* If block to find the largest number */
if (input1 > input2 && input1 > input3){
printf("Largest is ", input1, "\n");
} /* end if */
if (input2 > input1 && input2 > input3){
printf("Largest is ", input2, "\n");
} /* end if */
if (input3 > input2 && input3 > input1){
printf("Largest is ", input3, "\n");
} /* end if */


return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-3.c -o
prog-2-3
darwin:~ kevin$ ./prog-2-3
Input three different integers: -2 5 12
Sum is 15
Average is 5
Product is -120
Smallest is -2
Largest is 12
darwin:~ kevin$ exit
exit

Script done on Mon Sep 7 14:48:53 2009

I haven't tried this on another compiler, or for that matter another
machine. I'm "assuming" that the programs worked on the student's
machine as well, otherwise he would not have submitted them! I'm
uncertain what OS/compiler he's using (I don't require a specific set
up - just ANSI C).

Based on my rubric, I had no choice but to give him full credit and
then turn around say "don't do that anymore! - but don't ask why...

Kevin
 
J

James Kuyper

Meske Moday wrote:
....
Script started on Mon Sep 7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c prog-2-2.c prog-2-3.c
darwin:~ kevin$ cat prog-2-1.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This Program accepts a user's integer (n) and
* returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int n; /* User's input integer */
int cubed; /* Variable which will store the user's variable, cubed */

printf("Enter an integer: "); /* prompt */
scanf("%d", &n); /* read an integer */

cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125

This program generated precisely the expected warning message when
compiled on my machine:

~/testprog(55) gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
prog-2-1.c: In function ‘main’:
prog-2-1.c:23: warning: passing argument 1 of ‘printf’ makes pointer
from integer without a cast

The executable failed in one of the most plausible ways I might have
expected:

~/testprog(56) prog-2-1
Enter an integer: 5
Segmentation fault

I would expect similar results from the other two assignments. The
simplest way I can imagine for such code to compile without warning
messages, and to execute in accordance with requirements, as you said it
did for you, is if someone has fiddled with the contents of <stdio.h>.
However, reality has a better imagination than I do, so it may be
something else.
 
M

Mug

There's no way this should compile.  Passing an int as the first
argument to printf is a constraint violation.  (Well, a compiler
could produce a non-fatal warning for a constraint violation.)
If the first argument happens to be a string literal, there's no
constraint violation.  printf's first argument is of type char*; the
other arguments are of (nearly) arbitrary types.  The compiler cannot,
in general, enforce the rules, such as that "%d" requires an int
argument; it's up to the programmer to get this right.
Additional arguments beyond what's specified by the format string are
quietly ignored.
[...]
Any ideas? I want to tell the student this isn't correct, but I can't
seem to justify my gut instinct with any examples, since no one does
this! LOL And since his programs all compile cleanly and work
properly, I need something a little more concrete than my gut instinct..
How about the fact that his code, even if it happens to compile,
doesn't produce the output he wants?
If you way the code actually works, can you post a concrete example (a
small complete program, not a code fragment)?

=======================================================
I'm posting the three assignments he completed. I'm honestly not
concerned about copyright given that these are common first course
programming assignments.

Script started on Mon Sep  7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c  prog-2-2.c  prog-2-3.c
darwin:~ kevin$ cat prog-2-1.c
/*
 * Author:     xxx
 * Date:       9/5/09
 * Version:    1.0
 * Class:      CIT 131 / Fall 2009
 *
 * Assignment: This Program accepts a user's integer (n) and
 *             returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
    int n; /* User's input integer */
    int cubed; /* Variable which will store the user's variable, cubed */

    printf("Enter an integer: "); /* prompt */
    scanf("%d", &n); /* read an integer */

    cubed = n * n * n; /* cubing the user's integer */

    printf(n, "^3 = ", cubed, "\n"); /* print results */

    return 0; /* indicate a successful program end */

} /* End function main */

darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125
darwin:~ kevin$ cat prog-2-2.c  
/*
 * Author:     xxx
 * Date:       9/5/09
 * Version:    1.0
 * Class:      CIT 131 / Fall 2009
 *
 * Assignment: This program accepts a user's input radius, and finds the
 *             area/circumference of that circle.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
    int radius; /* user's input radius */
    float pi = 3.14159; /* approximation of Pi */

    printf("Enter the radius of a circle: "); /* prompt */
    scanf("%d", &radius); /* getting the user's radius */

    printf("The area A of a circle with radius ", radius, " = %f",
            pi * (radius * radius), "\n"); /* Printing the calculated area */

    printf("The circumference C of a circle with radius ", radius,
            " = %f", 2 * pi * radius, "\n"); /* Printing the calculated
circumference */

    return 0; /* indicate a successful program end */

} /* End function main */

darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-2.c -o prog-2-2
darwin:~ kevin$ ./prog-2-2  
Enter the radius of a circle: 10
The area A of a circle with radius 10 = 314.158997
The circumference C of a circle with radius 10 = 62.831802
darwin:~ kevin$ cat prog-2-3.c
/*
 * Author:     xxx
 * Date:       9/5/09
 * Version:    1.0
 * Class:      CIT 131 / Fall 2009
 *
 * Assignment: This program will return ths sum, average, product,
 *             smallest, and largest of 3 given integers.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{

    int input1; /* User's first input integer */
    int input2; /* User's second input integer */
    int input3; /* User's third input integer */

    printf("Input three different integers: "); /* prompt */
    scanf("%d", &input1, &input2, &input3); /* get user input */

    printf("Sum is ", input1 + input2 + input3, "\n"); /* printing sum */
    printf("Average is ", (input1 + input2 + input3) / 3, "\n"); /*
printing average */
    printf("Product is ", input1 * input2 * input3, "\n"); /* printing
product */

     /* If block to find the smallest number */
    if (input1 < input2 && input1 < input3){
        printf("Smallest is ", input1, "\n");
    } /* end if */
    if (input2 < input1 && input2 < input3){
        printf("Smallest is ", input2, "\n");
    } /* end if */
    if (input3 < input2 && input3 < input1){
        printf("Smallest is ", input3, "\n");
    } /* end if */

    /* If block to find the largest number */
    if (input1 > input2 && input1 > input3){
        printf("Largest is ", input1, "\n");
    } /* end if */
    if (input2 > input1 && input2 > input3){
        printf("Largest is ", input2, "\n");
    } /* end if */
    if (input3 > input2 && input3 > input1){
        printf("Largest is ", input3, "\n");
    } /* end if */

    return 0; /* indicate a successful program end */

} /* End function main */

darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-3.c -o
prog-2-3                
darwin:~ kevin$ ./prog-2-3  
Input three different integers: -2 5 12
Sum is 15
Average is 5
Product is -120
Smallest is -2
Largest is 12
darwin:~ kevin$ exit
exit

Script done on Mon Sep  7 14:48:53 2009

I haven't tried this on another compiler, or for that matter another
machine. I'm "assuming" that the programs worked on the student's
machine as well, otherwise he would not have submitted them! I'm
uncertain what OS/compiler he's using (I don't require a specific set
up - just ANSI C).

Based on my rubric, I had no choice but to give him full credit and
then turn around say "don't do that anymore! - but don't ask why...

Kevin

hi i test the program on my PC,i picked the last one, sine all those 3
have the similar problem
here is the result:
zsh/2 4641 % gcc -ansi -pedantic -Wall wierd_questions.c
wierd_questions.c: In function ‘main’:
wierd_questions.c:21: warning: too many arguments for format
wierd_questions.c:23: warning: too many arguments for format
wierd_questions.c:24: warning: too many arguments for format
wierd_questions.c:26: warning: too many arguments for format
wierd_questions.c:31: warning: too many arguments for format
wierd_questions.c:34: warning: too many arguments for format
wierd_questions.c:37: warning: too many arguments for format
wierd_questions.c:42: warning: too many arguments for format
wierd_questions.c:45: warning: too many arguments for format
wierd_questions.c:48: warning: too many arguments for format

so the warnings are from scanf

<mug@arch:/media/data/progC>
zsh/2 4642 % ./a.out
Input three different integers: 1 2 3
Sum is Average is Product is Smallest is Largest is %

in execution, we see that the all the elements after Sum is are
ignored, which is the normal behavious of printf
in conclusion, you must use the MAC, it always have some strange
behavious,i've once worked with a friend on a C project and
damn she had a mac, there were some strange behavious(like if she
don't initilize a int, the compilateur will initilize it to zero
automatiquely etc) on her code, they works correctly on her machine
but not on linux nor on windows,and i suppose ur student must use
windows or mac too.
i think that problably is the problem.
best regard
 
A

Alan Curry

On 2009-09-07 13:10:36 -0700, Keith Thompson <[email protected]> said:
darwin:~ kevin$ cat prog-2-1.c [...]
cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1

The absence of a warning could be a simple bug introduced by a vendor
modification of gcc.

But it runs, and doesn't segfault, and actually produces the desired output?
That's a crazy mystery!

Let's gather some clues:

gcc -v

gcc -C -dD -E prog-2-1.c

gcc -S prog-2-1.c -o -
 
R

Richard Bos

Meske Moday said:
I'm posting the three assignments he completed. I'm honestly not
concerned about copyright given that these are common first course
programming assignments.

Script started on Mon Sep 7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c prog-2-2.c prog-2-3.c
darwin:~ kevin$ cat prog-2-1.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This Program accepts a user's integer (n) and
* returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int n; /* User's input integer */
int cubed; /* Variable which will store the user's variable, cubed */

printf("Enter an integer: "); /* prompt */
scanf("%d", &n); /* read an integer */

cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125
darwin:~ kevin$ cat prog-2-2.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This program accepts a user's input radius, and finds the
* area/circumference of that circle.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int radius; /* user's input radius */
float pi = 3.14159; /* approximation of Pi */

printf("Enter the radius of a circle: "); /* prompt */
scanf("%d", &radius); /* getting the user's radius */

printf("The area A of a circle with radius ", radius, " = %f",
pi * (radius * radius), "\n"); /* Printing the calculated area */

printf("The circumference C of a circle with radius ", radius,
" = %f", 2 * pi * radius, "\n"); /* Printing the calculated
circumference */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-2.c -o prog-2-2
darwin:~ kevin$ ./prog-2-2
Enter the radius of a circle: 10
The area A of a circle with radius 10 = 314.158997
The circumference C of a circle with radius 10 = 62.831802
darwin:~ kevin$ cat prog-2-3.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This program will return ths sum, average, product,
* smallest, and largest of 3 given integers.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{

int input1; /* User's first input integer */
int input2; /* User's second input integer */
int input3; /* User's third input integer */

printf("Input three different integers: "); /* prompt */
scanf("%d", &input1, &input2, &input3); /* get user input */

printf("Sum is ", input1 + input2 + input3, "\n"); /* printing sum */
printf("Average is ", (input1 + input2 + input3) / 3, "\n"); /*
printing average */
printf("Product is ", input1 * input2 * input3, "\n"); /* printing
product */


/* If block to find the smallest number */
if (input1 < input2 && input1 < input3){
printf("Smallest is ", input1, "\n");
} /* end if */
if (input2 < input1 && input2 < input3){
printf("Smallest is ", input2, "\n");
} /* end if */
if (input3 < input2 && input3 < input1){
printf("Smallest is ", input3, "\n");
} /* end if */


/* If block to find the largest number */
if (input1 > input2 && input1 > input3){
printf("Largest is ", input1, "\n");
} /* end if */
if (input2 > input1 && input2 > input3){
printf("Largest is ", input2, "\n");
} /* end if */
if (input3 > input2 && input3 > input1){
printf("Largest is ", input3, "\n");
} /* end if */


return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-3.c -o
prog-2-3
darwin:~ kevin$ ./prog-2-3
Input three different integers: -2 5 12
Sum is 15
Average is 5
Product is -120
Smallest is -2
Largest is 12
darwin:~ kevin$ exit
exit

Script done on Mon Sep 7 14:48:53 2009

I haven't tried this on another compiler, or for that matter another
machine. I'm "assuming" that the programs worked on the student's
machine as well, otherwise he would not have submitted them! I'm
uncertain what OS/compiler he's using (I don't require a specific set
up - just ANSI C).

I don't know what cockamamie thing you've done to your implementation,
but on my system the first program does give a warning message when
compiling, and crashes when run, while the others don't print anything
but the first argument strings to printf(). I'd say something is wrong
on your system.
Based on my rubric, I had no choice but to give him full credit and
then turn around say "don't do that anymore! - but don't ask why...

Your rubric needs adjusting. Those programs are simply incorrect, no
matter how broken your system is.

Richard
 
B

Barry Schwarz

Meske Moday said:
I teach beginning C, and I've never run into this issue before. I have
a student who consistently uses the printf and scanf statements as
shown below. By all rights, I would have bet his programs wouldn't
compile. But they do...

Weird usage of printf:

printf( n, "^3 = ", cubed, "\n" ); /* n is an int */

There's no way this should compile. Passing an int as the first
argument to printf is a constraint violation. (Well, a compiler
could produce a non-fatal warning for a constraint violation.)

If the first argument happens to be a string literal, there's no
constraint violation. printf's first argument is of type char*; the
other arguments are of (nearly) arbitrary types. The compiler cannot,
in general, enforce the rules, such as that "%d" requires an int
argument; it's up to the programmer to get this right.
and scanf:

scanf( "%d", &input1, &input2, &input3 ); /* variables are int's */

Additional arguments beyond what's specified by the format string are
quietly ignored.

[...]
Any ideas? I want to tell the student this isn't correct, but I can't
seem to justify my gut instinct with any examples, since no one does
this! LOL And since his programs all compile cleanly and work
properly, I need something a little more concrete than my gut instinct.

How about the fact that his code, even if it happens to compile,
doesn't produce the output he wants?

If you way the code actually works, can you post a concrete example (a
small complete program, not a code fragment)?

=======================================================
I'm posting the three assignments he completed. I'm honestly not
concerned about copyright given that these are common first course
programming assignments.

Script started on Mon Sep 7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c prog-2-2.c prog-2-3.c
darwin:~ kevin$ cat prog-2-1.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This Program accepts a user's integer (n) and
* returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int n; /* User's input integer */
int cubed; /* Variable which will store the user's variable, cubed */

printf("Enter an integer: "); /* prompt */
scanf("%d", &n); /* read an integer */

cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */

My compiler generates the expected diagnostics:

D:\Barry\C\Programs\Test\test1.c(23) : warning C4047: 'function' :
'const char *' differs in levels of indirection from 'int '
D:\Barry\C\Programs\Test\test1.c(23) : warning C4024: 'printf' :
different types for formal and actual parameter 1
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1

I don't use gcc but I am a little surprised that after invoking the
compiler it does not produce any output upon finishing. Maybe you
could add an additional statement with a subtle error and tell him to
compile it for you.
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125

During execution the program fails (with an unhandled exception) after
accepting the input, also as expected.
darwin:~ kevin$ cat prog-2-2.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This program accepts a user's input radius, and finds the
* area/circumference of that circle.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int radius; /* user's input radius */
float pi = 3.14159; /* approximation of Pi */

printf("Enter the radius of a circle: "); /* prompt */
scanf("%d", &radius); /* getting the user's radius */

printf("The area A of a circle with radius ", radius, " = %f",
pi * (radius * radius), "\n"); /* Printing the calculated area */

printf("The circumference C of a circle with radius ", radius,
" = %f", 2 * pi * radius, "\n"); /* Printing the calculated
circumference */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-2.c -o prog-2-2
darwin:~ kevin$ ./prog-2-2
Enter the radius of a circle: 10
The area A of a circle with radius 10 = 314.158997
The circumference C of a circle with radius 10 = 62.831802

While the calls to printf are syntactically acceptable, on my system
the only output is the first string argument in each call, all on the
same line.
darwin:~ kevin$ cat prog-2-3.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This program will return ths sum, average, product,
* smallest, and largest of 3 given integers.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{

int input1; /* User's first input integer */
int input2; /* User's second input integer */
int input3; /* User's third input integer */

printf("Input three different integers: "); /* prompt */
scanf("%d", &input1, &input2, &input3); /* get user input */

This will not assign values to input2 and input3.
printf("Sum is ", input1 + input2 + input3, "\n"); /* printing sum */

This invokes undefined behavior by attempting to evaluate variables
with indeterminate values.
printf("Average is ", (input1 + input2 + input3) / 3, "\n"); /*
printing average */
Ditto.

printf("Product is ", input1 * input2 * input3, "\n"); /* printing
product */
Ditto.



/* If block to find the smallest number */
if (input1 < input2 && input1 < input3){
printf("Smallest is ", input1, "\n");
} /* end if */
if (input2 < input1 && input2 < input3){
printf("Smallest is ", input2, "\n");
} /* end if */
if (input3 < input2 && input3 < input1){
printf("Smallest is ", input3, "\n");
} /* end if */

On my system, none of the if statements evaluated to true (input2 and
input3 happened to have the same large negative value).
/* If block to find the largest number */
if (input1 > input2 && input1 > input3){
printf("Largest is ", input1, "\n");
} /* end if */
if (input2 > input1 && input2 > input3){
printf("Largest is ", input2, "\n");
} /* end if */
if (input3 > input2 && input3 > input1){
printf("Largest is ", input3, "\n");
} /* end if */


return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-3.c -o
prog-2-3
darwin:~ kevin$ ./prog-2-3
Input three different integers: -2 5 12
Sum is 15
Average is 5
Product is -120
Smallest is -2
Largest is 12
darwin:~ kevin$ exit
exit

On my system, the calls to printf printed out only the initial string
argument in each call - Sum is, Average is, Product is, Largest is.
All were on the same line.
Script done on Mon Sep 7 14:48:53 2009

I haven't tried this on another compiler, or for that matter another
machine. I'm "assuming" that the programs worked on the student's
machine as well, otherwise he would not have submitted them! I'm
uncertain what OS/compiler he's using (I don't require a specific set
up - just ANSI C).

Another possibility is that he is typing in the output instead of
compiling and executing the programs.
 
B

Ben Bacarisse

Meske Moday said:
I'm posting the three assignments he completed. I'm honestly not
concerned about copyright given that these are common first course
programming assignments.

Script started on Mon Sep 7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c prog-2-2.c prog-2-3.c

There is something suspicious about these escape characters being in
the output of ls but I can't put my finger on what. I don't get them
in my ls output for example. It may just be a remnant from ls's
colouring, but it may be more significant.
darwin:~ kevin$ cat prog-2-1.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This Program accepts a user's integer (n) and
* returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int n; /* User's input integer */
int cubed; /* Variable which will store the user's variable, cubed */

printf("Enter an integer: "); /* prompt */
scanf("%d", &n); /* read an integer */

cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125
darwin:~ kevin$

How odd. In the curious world of language standards the output is
perfectly acceptable, despite being the most surprising thing at first
glance. Since the program violates a language constraint, any output
all is possible, so this seemingly surprising result is perfectly
legal. The only error is that the compiler must issue a diagnostic
and it appears not to.

On a practical note, I'd suggest that gcc has been turned into a
script that silently refuses to generate code for erroneous programs
and you are running the result of compiling another source with the
same name which has since been deleted. Since it will be for the same
exercise, it generates the correct output interaction.

At least that is the least contrived explanation I can come up with.
Check the dates and times on the files and/or delete the executable
before compiling.

Based on my rubric, I had no choice but to give him full credit and
then turn around say "don't do that anymore! - but don't ask why...

I think you would be justified in deducting marks for not using printf
correctly but if the students also fail to see the required diagnostics
I'd be inclined to be lenient.

If they really are using a weird system that gives the output you show
(i.e. my guess above is wrong) then you need to be more lenient still,
but no reading of any reasonable C text (or presumably your notes)
could lead the student to write what they did.

On a side issue, no rubric should permit full marks for a program that
fails to check that the input was successful.
 
K

Keith Thompson

Meske Moday said:
I'm posting the three assignments he completed. I'm honestly not
concerned about copyright given that these are common first course
programming assignments.

Script started on Mon Sep 7 14:47:00 2009
darwin:~ kevin$ ls *.c
prog-2-1.c prog-2-2.c prog-2-3.c
darwin:~ kevin$ cat prog-2-1.c
/*
* Author: xxx
* Date: 9/5/09
* Version: 1.0
* Class: CIT 131 / Fall 2009
*
* Assignment: This Program accepts a user's integer (n) and
* returns the integer cubed.
*/
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int n; /* User's input integer */
int cubed; /* Variable which will store the user's variable, cubed */

printf("Enter an integer: "); /* prompt */
scanf("%d", &n); /* read an integer */

cubed = n * n * n; /* cubing the user's integer */

printf(n, "^3 = ", cubed, "\n"); /* print results */

return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1

It's astonishing that gcc with those options would not at least warn
about passing an int as the first argument to printf. On my system, I get:

prog-2-1.c: In function `main':
prog-2-1.c:23: warning: passing argument 1 of `printf' makes pointer from integer without a cast

And I'm frankly disappointed with gcc that it merely issues a warning.
printf expects a char* as its first argument. Apparently gcc is
generating an implicit conversion from int to char*. Which means that
printf most likely would try to read a string starting at address 5
and interpret it as a format string. I got a run-time segmentation
fault when I tried it on my system.
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125

I cannot think of any plausible explanation for this output that
doesn't involve some form of deliberate cheating. (The program's
behavior is undefined, so in theory any output is possible, but
"5^3 = 125" is about as likely as demons flying out of your nose.)
darwin:~ kevin$ cat prog-2-2.c [...]
#include <stdio.h>

/* function main begins program execution */
int main(void)
{
int radius; /* user's input radius */
float pi = 3.14159; /* approximation of Pi */

printf("Enter the radius of a circle: "); /* prompt */
scanf("%d", &radius); /* getting the user's radius */

printf("The area A of a circle with radius ", radius, " = %f",
pi * (radius * radius), "\n"); /* Printing the calculated area */

printf("The circumference C of a circle with radius ", radius,
" = %f", 2 * pi * radius, "\n"); /* Printing the calculated
circumference */

Both of these printf calls are perfectly legal, though I'd expect gcc
to warn about them. Any excess arguments not consumed by the format
string are quietly ignored (though of course the argument expressions
are evaluated during the call).
return 0; /* indicate a successful program end */

} /* End function main */
darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-2.c -o prog-2-2
darwin:~ kevin$ ./prog-2-2
Enter the radius of a circle: 10
The area A of a circle with radius 10 = 314.158997
The circumference C of a circle with radius 10 = 62.831802

Here there's no room for oddities due to undefined behavior. If the
first printf call produces any output other than "The area A of a
circle with radius ", then there's something wrong with the
implementation; similarly for the second call. (There's just the
slightest wiggle room due to the lack of a new-line at the end of the
output, but that's not going to have the observed effect on any system
that supports gcc.)

[third program with similar issues snipped]
I haven't tried this on another compiler, or for that matter another
machine. I'm "assuming" that the programs worked on the student's
machine as well, otherwise he would not have submitted them! I'm
uncertain what OS/compiler he's using (I don't require a specific set
up - just ANSI C).

Based on my rubric, I had no choice but to give him full credit and
then turn around say "don't do that anymore! - but don't ask why...

Just to be perfectly clear, did you compile and execute the student's
programs on your own system and get the same results? Was this a
system independent of the one the student is using? Can you try the
code on yet another system, one to which you're certain the student
has no access? (In effect, you've already done that by posting the
code here, and you've seen the results.)

There is no plausible legitimate way the posted programs could produce
the posted output. Some form of cheating is the only explanation I
can think of. Additionally, I suspect there's something relevant that
you're not telling us.
 
S

spinoza1111

I teach beginning C, and I've never run into this issue before. I have
a student who consistently uses the printf and scanf statements as
shown below. By all rights, I would have bet his programs wouldn't
compile. But they do...

Weird usage of printf:

        printf( n, "^3 = ", cubed, "\n" );   /* n is an int */

and scanf:

        scanf( "%d", &input1, &input2, &input3 );   /* variables are int's */

Compiling his code with "gcc -pedantic -ansi -Wall" doesn't generate
ANY errors. Checking it with splint generates the following message:

prog-2-1.c:23:12: Function printf expects arg 1 to be char * gets int: n
  Types are incompatible.
prog-2-1.c:23:5: Format string parameter to printf is not a
compile-time constant: n
  Format parameter is not known at compile-time.  This can lead to security
  vulnerabilities because the arguments cannot be type checked.

This same student uses scanf as shown above, with a single conversion
specification with three arguments. According to scanf specification
that I'm looking at (Linux-> man 3 scanf), scanf will evaluate the
excess pointer arguments, but otherwise ignores them. But it works! gcc
compiles again, without error. splint reports the following:

prog-2-3.c:21:5: Format string for scanf has 1 arg, given 3
  Types are incompatible.

Any ideas? I want to tell the student this isn't correct, but I can't
seem to justify my gut instinct with any examples, since no one does
this! LOL And since his programs all compile cleanly and work properly,
I need something a little more concrete than my gut instinct.

Thanks for any thought comments.
Kevin

The "power" of C is its weakness
The power of C is fatality.
I wouldn't be surprised if this bit of freakness
Compiled and ran with no error,
Or an error every other day.
True power rests in strong typing
And it amazes me to find people still hyping
A language whose power is the power of the weak
The power to smash and destroy, to conceal.
Beginning C is a road to Perdition
Teach Visual Basic to innocent chidren.
 
J

James Dow Allen

Perhaps there's a define like this somewhere well-hidden

#define printf(a,b,c,d) printf("%d%s%d%s",a,b,c,d)

and this is a joke by the student?

I think Jens has caught on. Far from being a weak
learner, kevin is your best student and bored enough to
hack into <stdio.h> or libc.a. The mystery, left here as
an exercise, is to reproduce the ifdef's kevin might have added
to stdio.h to get his special behavior while still allowing
the ordinary programs of ordinary students to compile ordinarily.

James Dow Allen
 
N

Nick Keighley

I teach beginning C, and I've never run into this issue before. I have
a student who consistently uses the printf and scanf statements as
shown below. By all rights, I would have bet his programs wouldn't
compile. But they do...

Weird usage of printf:

        printf( n, "^3 = ", cubed, "\n" );   /* n is an int */

that shouldn't compile on any reasonable system (assuming a prototype
in scope).
The first argument of printf() is wrong.
and scanf:
        scanf( "%d", &input1, &input2, &input3 );   /* variables are int's */

this is permitted to compile the extra arguments are just ignored.
Compiling his code with "gcc -pedantic -ansi -Wall" doesn't generate
ANY errors. Checking it with splint generates the following message:

as others ahve pointed out there is something very odd with your
version
of gcc. But ignoring that, ths printf(0 statement is plain constraint
violation and hence should generate a diagnostic (error or warning).
Check the standard or any good textbook.
prog-2-1.c:23:12: Function printf expects arg 1 to be char * gets int: n
  Types are incompatible.

this makes sense
prog-2-1.c:23:5: Format string parameter to printf is not a
compile-time constant: n
  Format parameter is not known at compile-time.  This can lead to security
  vulnerabilities because the arguments cannot be type checked.

well it isn't a compile-time constant, but I'd say that hardly
mattered
as it's the worng type...
This same student uses scanf as shown above, with a single conversion
specification with three arguments. According to scanf specification
that I'm looking at (Linux-> man 3 scanf), scanf will evaluate the
excess pointer arguments, but otherwise ignores them. But it works! gcc
compiles again, without error.

as it is supposed to
splint reports the following:

prog-2-3.c:21:5: Format string for scanf has 1 arg, given 3
  Types are incompatible.

there you are
Any ideas?

mark both of them as wrong. One isn't correct C and the other doesn't
work.

I want to tell the student this isn't correct,

do so

but I can't
seem to justify my gut instinct with any examples,

you don't program from examples you program from a specification
or standard.

since no one does this!

no-one puts embedded LISP in their C programs or expects quotes
fome Shakespere (now there's challange to clc!) to execute. They're
wrong as well. The number of things that are wrong is unboundedly
large.
You can't expect examples of all of them.
LOL And since his programs all compile cleanly and work properly,

I'm *very* dubious of that. Your tests aren't good enough.
I need something a little more concrete than my gut instinct.

Run it on another computer. Write a decent test harness. The scanf()
*can't work*
 
O

Old Wolf

#include <stdio.h>

/* function main begins program execution */
int main(void)
{
    int n; /* User's input integer */
    int cubed; /* Variable which will store the user's variable, cubed */

    printf("Enter an integer: "); /* prompt */
    scanf("%d", &n); /* read an integer */

    cubed = n * n * n; /* cubing the user's integer */

    printf(n, "^3 = ", cubed, "\n"); /* print results */

    return 0; /* indicate a successful program end */

} /* End function main */

darwin:~ kevin$ gcc -ansi -pedantic -Wall prog-2-1.c -o prog-2-1
darwin:~ kevin$ ./prog-2-1
Enter an integer: 5
5^3 = 125

Did you actually compile , run, and enter the
input yourself? Or are you just pasting what
the student said his result was?
 

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,054
Latest member
TrimKetoBoost

Latest Threads

Top