Ex 7-5

M

mdh

mdh said:

<snip>





Not like that, they don't. Compare and contrast the above with the actual
call, assignment, and comparison:

  while ( .......((c=getchar()) != EOF).....)


Sorry...was in a hurry this am. Yes...I meant to write it as you do.

Then it will be obvious to you why you pass scanf a char *, not an int *,
when you need scanf to read a char for you.


Hopefully it is so as to avoid ub? :)

If that is not obvious, then
you haven't really understood why c is an int.

Well...let me put my neck on the line, hoping that any sword swoops
will miss all the other scars!!!

In ( .......((c=getchar()) != EOF).....), c **might** not be of type
char, it might be an EOF which is guaranteed **not** to be the value
of any character, usually "-1" so c has to be big enough to hold this
value in addition to the full character set.


Now..having said that, it's the next line on p69 that I have simply
done because it has always worked, that I now ponder.




s = c; where s[] is a char array, and c is now, by exclusion, a
variable of type integer that contains an object of type character.
 
M

mdh

Keith...just saw your reply.


getchar() returns an int value, so of course you want to assign the
result to an int object.  (You can *mostly* get away with assigning
the result to a char object, since the assignment implicitly converts
the value to the required type before storing it.


Aha...that's what I was missing.


 I say "mostly"
because it causes problems if getchar() returns either EOF or a value
greater than CHAR_MAX; the latter is possible if plain char is
signed.)


Which..presumably is the reason one tests for the result of the
returned value?

scanf with "%c" requires a *pointer* to a char object; scanf will then
store a 1-byte value in that object.  If you pass it a pointer to an
int object, you're lying to it.  There's no implicit conversion to
save you; char and int values can be mixed, but char* and int* values
cannot.


got it...thank you.
 
M

mdh

mdh said:

<snip>





Not like that, they don't. Compare and contrast the above with the actual
call, assignment, and comparison:

  while ( .......((c=getchar()) != EOF).....)

The difference is significant, and has to do with precedence.


Then it will be obvious to you why you pass scanf a char *, not an int *,
when you need scanf to read a char for you. If that is not obvious, then
you haven't really understood why c is an int.



Richard...just read Keith's response to my further question..so thank
you.
 
M

mdh

mdh said:



I think you mean 'the return value of getchar might not represent a
character'...


Ah...of course....C truly is a precise language...and the funny thing
is, the more precise the language is, the clearer the concept becomes
to me. Thank you as always.
 
R

Ron Ford

scanf with "%c" requires a *pointer* to a char object; scanf will then
store a 1-byte value in that object. If you pass it a pointer to an
int object, you're lying to it. There's no implicit conversion to
save you; char and int values can be mixed, but char* and int* values
cannot.

I think that's the punchline, but I just realized where the gotcha may have
come from, which is the difference in the format specifiers between printf
and scanf. I tried

char s[] = "Constantinople";
printf (" %c \n", s);

and got:
c10.c:33: warning: format '%c' expects type 'int', but argument 2 has type
'char
*'

%c differs between printf and scanf.
 
R

Ron Ford

Ron Ford said:



Then post one, dear chap.

/* This is the same calculator that
Bob Wightman wrote for Ex 4-4 with a different Getop
I aced his unused flag variable */


#include<stdlib.h>
#include<stdio.h>
#include<ctype.h>
#include<math.h>

#define MAXOP 100
#define NUMBER 0
#define TRUE 1
#define FALSE 0



int Getop(char s[]);
void push(double val);
double pop(void);
void showTop(void);
void duplicate(void);
void swapItems(void);
void clearStack();

int main(void)
{
int type;
double op2;
char s[MAXOP];

while((type = Getop(s)) != EOF)
{
switch(type)
{
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop()- op2);
break;
case '/':
op2 = pop();
if(op2)
push(pop() / op2);
else
printf("\nError: division by zero!");
break;
case '%':
op2 = pop();
if(op2)
push(fmod(pop(), op2));
else
printf("\nError: division by zero!");
break;
case '?':
showTop();
break;
case '#':
duplicate();
break;
case '~':
swapItems();
break;
case '!':
clearStack();
case '\n':
printf("\n\t%.8g\n", pop());
break;
default:
printf("\nError: unknown command %s.\n", s);
break;
}
}
return EXIT_SUCCESS;
}

#define MAXVAL 100

int sp = 0; /* Next free stack position. */
double val[MAXVAL]; /* value stack. */

/* push: push f onto stack. */
void push(double f)
{
if(sp < MAXVAL)
val[sp++] = f;
else
printf("\nError: stack full can't push %g\n", f);
}

/*pop: pop and return top value from stack.*/
double pop(void)
{
if(sp > 0)
return val[--sp];
else
{
printf("\nError: stack empty\n");
return 0.0;
}
}

void showTop(void)
{
if(sp > 0)
printf("Top of stack contains: %8g\n", val[sp-1]);
else
printf("The stack is empty!\n");
}


void duplicate(void)
{
double temp = pop();

push(temp);
push(temp);
}

void swapItems(void)
{
double item1 = pop();
double item2 = pop();

push(item1);
push(item2);
}

/* pop only returns a value if sp is greater than zero. So setting the
stack pointer to zero will cause pop to return its error */

void clearStack(void)
{
sp = 0;
}

int getch(void);
void unGetch(int);

int Getop(char line[])
{
int rc, i;
// Tondo and Gimpel has the next declaration wrongly an int
char c;
static char lastc[] = " ";

sscanf(lastc, "%c", &c);
lastc[0] = ' ';

while ( (line[0]=c) == ' ' || c == '\t')
if ( scanf("%c", &c) == EOF) c=EOF;

line[1]= '\0';
if ( !isdigit(c) && c != '.') return c;

i = 0;
if ( isdigit(c)) do
{
rc = scanf("%c", &c);
if (!isdigit(line[++i] = c)) break;

} while (rc != EOF);

if ( c == '.') do
{
rc = scanf("%c", &c);
if (!isdigit(line[++i]= c)) break;
} while (rc != EOF);
line= '\0';
if ( rc != EOF) lastc[0] = c;
return NUMBER;
}


#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;

/* Getch: get a ( possibly pushed back) character. */
int getch(void)
{
return (bufp > 0) ? buf[--bufp]: getchar();
}

/* unGetch: push character back on input. */
void unGetch(int c)
{
if(bufp >= BUFSIZE)
printf("\nUnGetch: too many characters\n");
else
buf[bufp++] = c;
}

// gcc -o calc -Wall -std=c99 kr7_5_3.c
 
K

Keith Thompson

mdh said:
In ( .......((c=getchar()) != EOF).....), c **might** not be of type
char, it might be an EOF which is guaranteed **not** to be the value
of any character, usually "-1" so c has to be big enough to hold this
value in addition to the full character set.

Not quite. The value returned by getchar() is definitely of type int.
That value might or might not be within the range of type char (i.e.,
CHAR_MIN .. CHAR_MAX).
Now..having said that, it's the next line on p69 that I have simply
done because it has always worked, that I now ponder.

s = c; where s[] is a char array, and c is now, by exclusion, a
variable of type integer that contains an object of type character.


There are no types "integer" or "character". c is a variable of
type int. It *is* (not contains) an object of type int. It contains
a value of type int, a value which is also within the range of type
unsigned char (given that it was returned by getchar() and is not
equal to EOF).

Which is another wrinkle, BTW. The int value returned by getchar()
is either the value EOF or a value within the range of unsigned
char (0 .. UCHAR_MAX). Assuming it's not EOF, assigning this
value to a variable of type char will *probably* work, but
isn't guaranteed. For example, assume an implementation where
CHAR_BIT==8, plain char is signed, and there are no padding bits.
Reading a byte with the value 0xff causes getchar() to return 255,
which is outside the range of type char -- and converting 255 to
char yields an implementation-defined value or (in C99) raises an
implementation-defined signal. But we generally feel free to copy
the result of getchar() into an array of char.
 
K

Keith Thompson

Ron Ford said:
scanf with "%c" requires a *pointer* to a char object; scanf will then
store a 1-byte value in that object. If you pass it a pointer to an
int object, you're lying to it. There's no implicit conversion to
save you; char and int values can be mixed, but char* and int* values
cannot.

I think that's the punchline, but I just realized where the gotcha may have
come from, which is the difference in the format specifiers between printf
and scanf. I tried

char s[] = "Constantinople";
printf (" %c \n", s);

and got:
c10.c:33: warning: format '%c' expects type 'int', but argument 2 has type
'char
*'

%c differs between printf and scanf.

Well, for corresponding formats, printf generally expects an argument
of type foo and scanf expects an argument of type foo*, because scanf
has to store the value it reads in an object, and the pointer argument
tells it where the object is.

But even considering that, printf and scanf aren't entirely
consistent, and with good reason in most cases. The difference is
argument promotion -- or rather, the difference is motivated by
argument promotion. printf with "%c" expects an argument of type int
-- and if you pass it an object of type char, the value will be
promoted to int. And a character constant like 'x' is *already* of
type int. On the other hand, scanf with "%c" requires an argument of
type char* (treated as a pointer to a single char object, not as a
pointer to the beginning of a string), because it needs an actual char
object, not an int object, in which to store the value.

char can be promoted to int because the conversion just yields the
same value in a different type. char* can't be quietly promoted to
int* because a char* value, to be valid, must point to an object of
type char; there's no int object for the resulting int* value to point
to.
 
B

Ben Bacarisse

Ron Ford said:
/* This is the same calculator that
Bob Wightman wrote for Ex 4-4 with a different Getop
I aced his unused flag variable */

It looks like the Chapter 7 re-write exercise. Ex 7-5 (I think -- in
my K&R it is 7-2) says re-write the calculator to use scanf and/or
sscanf for the input and number conversion. Also, do you know if this
is Bob Wightman of Tondo and Gimpel's code? It looks much that the
posted by mdh with a correction but I am now unsure whose it is.

I have a few comments on the code:
void clearStack();

void clearStack(void); is better (like the others).

case '!':
clearStack();
case '\n':
printf("\n\t%.8g\n", pop());
break;

I think there is a missing break after clearStack(); The pop() does
not make sense if the stack has been cleared so a fall-though can't
have been intended.

switch(type)
{
case NUMBER:
push(atof(s));
break;

My big problem with the "solution" is that is does not do what is
intended! I don't interpret the suggestion to rewrite to use scanf
"for the number conversion" to include the use of scanf for the bit it
does badly (reading a single character) and not for the bit it does
well (reading and converting numbers). It seems to be a daft
non-solution.
int getch(void);
void unGetch(int);

These are not needed any more. Seems odd to leave them there.
int Getop(char line[])

I ask about the author because this version is a step backwards.
K&R's getop passes in the buffer length. Now you can get by with
"global" (#define) size but that is not such a good design. Worse,
though, is that this code does not even check that there is room. It
is, in effect, a giant gets.
{
int rc, i;
// Tondo and Gimpel has the next declaration wrongly an int
char c;
static char lastc[] = " ";

sscanf(lastc, "%c", &c);

Why on earth do this? Surely c = last[0]; is clearer, but I'd simple
have a single last_char variable. I seems way too complicated.
lastc[0] = ' ';

while ( (line[0]=c) == ' ' || c == '\t')
if ( scanf("%c", &c) == EOF) c=EOF;

line[1]= '\0';
if ( !isdigit(c) && c != '.') return c;

i = 0;
if ( isdigit(c)) do

Personally, I find hiding the "do" over here to very poor style.
{
rc = scanf("%c", &c);
if (!isdigit(line[++i] = c)) break;

} while (rc != EOF);

if ( c == '.') do
{
rc = scanf("%c", &c);
if (!isdigit(line[++i]= c)) break;
} while (rc != EOF);
line= '\0';
if ( rc != EOF) lastc[0] = c;
return NUMBER;
}


I don't think this is what K&R had in mind.
#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;

/* Getch: get a ( possibly pushed back) character. */
int getch(void)
{
return (bufp > 0) ? buf[--bufp]: getchar();
}

/* unGetch: push character back on input. */
void unGetch(int c)
{
if(bufp >= BUFSIZE)
printf("\nUnGetch: too many characters\n");
else
buf[bufp++] = c;
}

No longer needed.

OK, rather the all this knocking, here is my solution. I interpret
the intent as to try to use scanf to simplify the calculator, not to
complicate it by using scanf to read characters. At the same time,
you have to think about the problems of scanf. The main one being
that '+' and '-' are the start of numbers as far as it is concerned so
you can't just try to read a number. Also, at this stage ungetc has
not been introduced so my preferred solution of reading a char
(skipping space) using " %c" does not work because we can't put the
character back if it is a digit.

Anyway, I would do this (skip down to just after main for the getop
function if that is all you want to see):

#include <stdio.h>

#define NUMBER '0'

int getop(double *val);
double push(double val);
double pop(void);
void clear(void);

int main(void)
{
int op;
double num;

while ((op = getop(&num)) != EOF) {
switch (op) {
case NUMBER:
push(num);
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
num = pop();
push(pop() - num);
break;
case '/':
num = pop();
if (num)
push(pop() / num);
else fprintf(stderr, "Error: division by zero.");
break;
case '#':
push(push(pop()));
break;
case 'c':
clear();
break;
case '=':
printf("\t%g\n", push(pop()));
break;
default:
fprintf(stderr, "Error: unknown operation %c.\n", op);
break;
}
}
return 0;
}

int getop(double *num)
{
int rc;
char s[2];
if ((rc = scanf(" %1[^0-9]", s)) == 1)
return s[0];
else if (rc != EOF && scanf("%lf", num) == 1)
return NUMBER;
else return EOF;
}


/* This is the simple stack almost straight out of the original */

#define MAXVAL 100

static int sp = 0; /* Next free stack position. */
static double val[MAXVAL];

double push(double f)
{
if (sp < MAXVAL)
return val[sp++] = f;
else {
fprintf(stderr, "Error: stack full.\n");
clear(); /* Following K&R here -- seems reasonable. */
return 0;
}
}

double pop(void)
{
if (sp > 0)
return val[--sp];
else {
fprintf(stderr, "Error: stack empty.\n");
return 0;
}
}

void clear(void)
{
sp = 0;
}
 
M

mdh

It looks like the Chapter 7 re-write exercise.  Ex 7-5 (I think -- in
my K&R it is 7-2) says re-write the calculator to use scanf and/or
sscanf for the input and number conversion.  Also, do you know if this
is Bob Wightman of Tondo and Gimpel's code?


I do not know who Bob Whitman is, but the code I originally showed was
straight out of T&G, p176, 2nd ed.

 It looks much that the
posted by mdh with a correction but I am now unsure whose it is.

I have a few comments on the code:
 >  I interpret
the intent as to try to use scanf to simplify the calculator, not to
complicate it by using scanf to read characters.

int getop(double *num)
{
     int rc;
     char s[2];
     if ((rc = scanf(" %1[^0-9]", s)) == 1) /* <--Q1
          return s[0];
     else if (rc != EOF && scanf("%lf", num) == 1) <---- Q2
          return NUMBER;
     else return EOF;

}

/* This is the simple stack almost straight out of the original */


Ben...very elegant!
I just have a couple of questions.

Q1. What is the purpose of the "1" after the "%" as in "%1[^0-9]
(and I am hoping the [^0-9] is the same as regex ie a single character
that is not 0 through 9?) ( I am trying to understand what we are
looking for :) )

Q2. Will an "lf" directive match a negative double correctly?

Ps...have not heard the word "daft" since the Goon show!
 
C

CBFalconer

mdh said:
.... snip ...

May I just pursue this a little further....sadly, once again,
having given this some more thought!!! :)

K&R often use c ( declared as an int) to assign a character. So,
for example, p69, getline takes 2 arguments. A char array, and
an integer.

No, they use an int to receive the output of getc() (and similar
functions) because getc() returns an int. And getc returns an int
because such is needed to return EOF.
 
B

Ben Bacarisse

mdh said:
int getop(double *num)
{
     int rc;
     char s[2];
     if ((rc = scanf(" %1[^0-9]", s)) == 1) /* <--Q1
          return s[0];
     else if (rc != EOF && scanf("%lf", num) == 1) <---- Q2
          return NUMBER;
     else return EOF;

}
I just have a couple of questions.

Q1. What is the purpose of the "1" after the "%" as in "%1[^0-9]
(and I am hoping the [^0-9] is the same as regex ie a single character
that is not 0 through 9?) ( I am trying to understand what we are
looking for :) )

We need to (a) skip spaces -- hence the "<space>%[...]" and (b) read
any one character that is not a digit. The only format that can read
from a specified set (yes, ^ means any character not in the following
set) is %[] and that will read an unlimited number of characters
unless we say home many we want: 1.
Q2. Will an "lf" directive match a negative double correctly?

Yes, but in this case it will never see one. The whole point is read
a double only when we know there is one really there. This is exactly
what the "old" code does -- +12 and -13 are taken as an op (+ and -)
followed by a number not as a signed double. It is much harder to
allow scanf to read signed doubles *and* to interpret + and - as
operators.
Ps...have not heard the word "daft" since the Goon show!

My mother said "daft as brush" all the time. I'm rather fond of the
word.
 
R

Ron Ford

It looks like the Chapter 7 re-write exercise. Ex 7-5 (I think -- in
my K&R it is 7-2) says re-write the calculator to use scanf and/or
sscanf for the input and number conversion. Also, do you know if this
is Bob Wightman of Tondo and Gimpel's code? It looks much that the
posted by mdh with a correction but I am now unsure whose it is.

What I did, Ben, was import the soln posted for 4-4 for the clc wiki. The
fella's name who gets the attribution there is Bob Wightman. I cut out
Getop and pasted in the Tondo and Gimpel version of Getop that mdh is
trying to implement.

I didn't look closely at the Getop I cut out. My guess is that when I do,
I'll cut out more spare parts.

The thing I don't know how to do now is test. It behaves when I do:
10 5 * or
67 4 %

, but I don't know enough about scanf *and* testing an app that uses a
stack to know that this solution is robust. I was thinking that people
with greater experience could illuminate.
I have a few comments on the code:


void clearStack(void); is better (like the others).



I think there is a missing break after clearStack(); The pop() does
not make sense if the stack has been cleared so a fall-though can't
have been intended.



My big problem with the "solution" is that is does not do what is
intended! I don't interpret the suggestion to rewrite to use scanf
"for the number conversion" to include the use of scanf for the bit it
does badly (reading a single character) and not for the bit it does
well (reading and converting numbers). It seems to be a daft
non-solution.

Can you elaborate? I see 4 cases:
1) the posted solution for 4-4 is daft.
2) T&G's Getop is daft.
3) The inclusion of T&G's Getop in 4-4 is daft.
4) This portion of your criticism is daft.
These are not needed any more. Seems odd to leave them there.

These will probably end up as spare parts.
int Getop(char line[])

I ask about the author because this version is a step backwards.
K&R's getop passes in the buffer length. Now you can get by with
"global" (#define) size but that is not such a good design. Worse,
though, is that this code does not even check that there is room. It
is, in effect, a giant gets.

int Getop(char line[]) is a gemisch of a few things. K&R and T&G use getop
with a small g, which, according to gcc, differs from large G Getop. mdh
used line[] where T&G used s[], but the substitution was consistent
throughout. I would prefer using s[], so as to stay closer to known
solutions.

The T&G soln for this only shows getop, and the first sentence of the
explanation is:

The function getop (page 78 K&R) is the only routine modified.

< rest snipped for now>
 
B

Ben Bacarisse

Ron Ford said:
What I did, Ben, was import the soln posted for 4-4 for the clc wiki. The
fella's name who gets the attribution there is Bob Wightman. I cut out
Getop and pasted in the Tondo and Gimpel version of Getop that mdh is
trying to implement.

I think I follow. I was confused in part by the fact that exercise
4-4 is an "extend..." exercise but Bob Wightman's solution changes
some of K&R's original code. For example he removes the test for
there being room to store the input. I wonder if Tondo & Gimpel do as
well.

Can you elaborate? I see 4 cases:
1) the posted solution for 4-4 is daft.
2) T&G's Getop is daft.
3) The inclusion of T&G's Getop in 4-4 is daft.
4) This portion of your criticism is daft.

I mean 2 with a bit of 3. Chapter 7 covers scanf and things like
ungetc. I don't know the exact contents and order since I don't have
K&R2, but the exercise is to: "re-write the postfix calculator of
Chapter 4 to use scanf and/or sscanf to do the input and number
conversion".

To do this by ignoring scanf's ability to read and covert numbers
seems daft. The posted code (which I was having trouble believing was
from a published book of solutions until this was confirmed) simply
re-writes getop to read characters using scanf rather than using
getchar (or K&R's invented getch). Now it is likely that it looks
particularly daft when T&G's getop is pasted into a solution of 4-4
that uses atof to convert a numeric string, because the result fails
to use scanf to do the number conversion as asked.

I am guessing, but surely T&G's version uses sscanf in main rather
than atof so that it meets the requirements of the exercise? Even so,
I don't think single character input is a good use of scanf -- It is
not what scanf is good at.
These will probably end up as spare parts.

Example solutions should be free from such left-over parts.
int Getop(char line[])

I ask about the author because this version is a step backwards.
K&R's getop passes in the buffer length. Now you can get by with
"global" (#define) size but that is not such a good design. Worse,
though, is that this code does not even check that there is room. It
is, in effect, a giant gets.

int Getop(char line[]) is a gemisch of a few things. K&R and T&G use getop
with a small g, which, according to gcc, differs from large G Getop.

Not only gcc. Case matters in C's identifiers.
mdh
used line[] where T&G used s[], but the substitution was consistent
throughout. I would prefer using s[], so as to stay closer to known
solutions.

The T&G soln for this only shows getop, and the first sentence of the
explanation is:

The function getop (page 78 K&R) is the only routine modified.

Curious. This means they *don't* use sscanf in main to do the
conversion. If so, in what sense is it even a solution to the
exercise?

This clears up one thing. If only getop is modified, it must have the
length parameter that the K&R version had. Is it simply ignored in
the body of the function?
 
R

Ron Ford

I think I follow. I was confused in part by the fact that exercise
4-4 is an "extend..." exercise but Bob Wightman's solution changes
some of K&R's original code. For example he removes the test for
there being room to store the input. I wonder if Tondo & Gimpel do as
well.

I don't see it. I'm looking at T&G 4-4 now, and it's not a whole lot more
than the switch control.

My sense about the storage considerations was with the size of the stack
being #defined. It would take a lot of keystrokes to take up the space on
the stack of a PC, so that didn't seem relevant.

I mean 2 with a bit of 3. Chapter 7 covers scanf and things like
ungetc. I don't know the exact contents and order since I don't have
K&R2, but the exercise is to: "re-write the postfix calculator of
Chapter 4 to use scanf and/or sscanf to do the input and number
conversion".

"Daft" is one of those words. Those who have it, seem to have it in large
quantities.
To do this by ignoring scanf's ability to read and covert numbers
seems daft. The posted code (which I was having trouble believing was
from a published book of solutions until this was confirmed) simply
re-writes getop to read characters using scanf rather than using
getchar (or K&R's invented getch). Now it is likely that it looks
particularly daft when T&G's getop is pasted into a solution of 4-4
that uses atof to convert a numeric string, because the result fails
to use scanf to do the number conversion as asked.

I am guessing, but surely T&G's version uses sscanf in main rather
than atof so that it meets the requirements of the exercise? Even so,
I don't think single character input is a good use of scanf -- It is
not what scanf is good at.

I hadn't thought of using scanf in main. What would that look like?
Example solutions should be free from such left-over parts.

This is a work in progress. I thank you for your response; I'll ace these.

Curious. This means they *don't* use sscanf in main to do the
conversion. If so, in what sense is it even a solution to the
exercise?

This clears up one thing. If only getop is modified, it must have the
length parameter that the K&R version had. Is it simply ignored in
the body of the function?

Not sure what you mean here, but I've got to run. Blessed Sunday.

Cheers,
 
B

Ben Bacarisse

Ron Ford said:
I don't see it. I'm looking at T&G 4-4 now, and it's not a whole lot more
than the switch control.

Eh? In K&R's code, getop is passed a size and refuses to store more
characters than there is room for. In all the getop version being
passed about here, this is not so. They can all overrun the input
buffer when there are very large strings of digits. This is a bad
change to have made and has no place in any "good" solution.
My sense about the storage considerations was with the size of the stack
being #defined. It would take a lot of keystrokes to take up the space on
the stack of a PC, so that didn't seem relevant.

The PC's stack has nothing to do with it. Ah! Do you think this
code:

char *get_some(char line[])
{
int c, i = 0;
while ((c = getchar()) != EOF && c != '\n')
line[i++] = 0;
line = 0;
return line;
}

just keeps using more and more stack when the line is very long? If
so, you to go back and re-read about [] in parameters and C arrays in
general. I am not saying you do, I am just trying to how you can take
the code we've been talking about and say things about the PC's stack.
"Daft" is one of those words. Those who have it, seem to have it in large
quantities.

What does that mean? Do you seriously think the code that has been
posted is a reasonable solution, given the wording of the exercise?
It sounds as if you think I am throwing around this word without
sufficient justification.
I hadn't thought of using scanf in main. What would that look like?

I said sscanf -- to replace the use of atof. Without it, how does the
code "convert the number using scanf/sscanf" as a paraphrase of the
exercise would require?
Not sure what you mean here, but I've got to run. Blessed Sunday.

There is a mis-match between what has been posted as T&G's getop and
the claim that only getop has been modified. K&R has:

getop()
char s[];
int lim;
{
/* body */
}

which I image in new K&R2 style is something like:

int getop(char *s, int lim)
{
/* body */
}

The call in main is:

while ((type = getop(s, MAXOP)) != EOF) ...

so the 'lim' argument is used to ensure that 's' is never over-filled.
If T&G change only getop they must keep the call in main with two
parameters or they have broken code. Either what has been posted is
not as T&G wrote it, or their claim to have changed only getop is
wrong.

Going simply on what has been posted, both on the wiki and here, having
a getop function than can over-fill the input array if there is a long
string of digits in the input is simply bad coding and has no place in
any published solution.
 
M

mdh

mdh said:
What is the purpose of the "1" after the "%" as in "%1[^0-9]

We need to (a) skip spaces -- hence the "<space>%[...]" and (b) read
any one character that is not a digit.

Ben...one last point of clarification.
K&R (p159) say this.
"scanf ignores blanks and tabs in it's format string. Furthermore, it
skips over white space( blanks, tabs, newlines, etc) as it looks for
input values"

Now, I assume that the space you have will work, but could you perhaps
explain the seemingly contradictory statements.

Thanks.
 
B

Ben Bacarisse

mdh said:
On Sep 14, 8:52 am, Ben Bacarisse <[email protected]> wrote:
We need to (a) skip spaces -- hence the "<space>%[...]" and (b) read
any one character that is not a digit.

Ben...one last point of clarification.
K&R (p159) say this.
"scanf ignores blanks and tabs in it's format string. Furthermore, it
skips over white space( blanks, tabs, newlines, etc) as it looks for
input values"

Now, I assume that the space you have will work, but could you perhaps
explain the seemingly contradictory statements.

K&R are maybe out of date. Is this K&R2? I don't know exactly when
whitespace-as-a-directive came into scanf, but I have known about it
for quite a long time.

In ISO scanf implementations, %c does not skip white space and any
sequence of white space in the format is taken to be an instruction to
skip white space in the input. This has been true for nearly 20 years
(it was true in C90).
 
J

James Kuyper

mdh said:
mdh said:
What is the purpose of the "1" after the "%" as in "%1[^0-9]
We need to (a) skip spaces -- hence the "<space>%[...]" and (b) read
any one character that is not a digit.

Ben...one last point of clarification.
K&R (p159) say this.
"scanf ignores blanks and tabs in it's format string. Furthermore, it
skips over white space( blanks, tabs, newlines, etc) as it looks for
input values"

K&R was simplifying matters. What the standard actually says is that a
directive can consist of "one or more white-space characters" (7.9.16.2p3).

What it says about such directives is in p5: "A directive composed of
white-space character(s) is executed by reading input up to the first
non-white-space character (which remains unread), or until no more
characters can be read."

When you consider what p8 says about conversion specifications : "Input
white-space characters (as specified by the isspace function) are
skipped, unless the specification includes a [, c, or n specifier.", the
net result is that white space directives in a format strings usually
has precisely the same effect as if it were absent. However, this is not
the case for white space directives that precede a conversion
specification with a [, c, or n specifier, which is precisely what's
relevant here.

Though it does not come up in this example, there's another related why
in which K&R's statement about blanks and tabs is incorrect. A blank or
tab which occurs inside of a '[' specifier, as for example "%[ab \t]" is
not "a directive composed of white-space characters", it is only a
directive containing white-space. It is not ignored, but plays a key
role in determining how that directive is applied to the input.
 
M

mdh

mdh said:
K&R (p159) say this.
"scanf ignores blanks and tabs in it's format string. Furthermore, it
skips over white space( blanks, tabs, newlines, etc) as it looks for
input values"

K&R was simplifying matters. What the standard actually says is that a
directive can consist of "one or more white-space characters" (7.9.16.2p3).
"A directive composed of
white-space character(s) is executed by reading input up to the first
non-white-space character (which remains unread), or until no more
characters can be read."

When you consider what p8 says about conversion specifications : "Input
white-space characters (as specified by the isspace function) are
skipped, unless the specification includes a [, c, or n specifier."..........

this is not
the case for white space directives that precede a conversion
specification with a [, c, or n specifier, which is precisely what's
relevant here.
there's another related why
in which K&R's statement about blanks and tabs is incorrect. A blank or
tab which occurs inside of a '[' specifier, as for example "%[ab \t]" is
not "a directive composed of white-space characters", it is only a
directive containing white-space. It is not ignored, but plays a key
role in determining how that directive is applied to the input.



When you put all this together, is there some logic as to why those
who wrote the specifications chose to do it this way, or is this
simply something you remember? I **though** I had figured out some
reason earlier, but I know better than to give my theory!!!! :)
 

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,780
Messages
2,569,608
Members
45,241
Latest member
Lisa1997

Latest Threads

Top