#C problems
24 messages in this thread
Hi Amiga folk! I have 2 puzzles on my mind right now and would appreciate
any help. 1) I can compile this without errors on my Aztec 3.6a but when I
link I get this message: Undefined symbol _printf it is in reference to the
default:
choice of the switch however it looks clean to me and when I put it in
remarks I can link normally. Problem 2) after starting the program,
getchar() accepts the choice ok however, the next time through it is
bypassed and goes to the default choice. It then stops on the third time
through and accepts a choice normally again. Thanks for any
help………….Henry #include <stdio.h> main() {
int go = 0;
char c;
while (go == 0){
printf ("\t (V)iew File (C)hange Record (A)dd Record\n");
printf ("\t (H)ard Copy (D)elete Record (Q)uit program\n");
c = 0;
c = getchar();
switch (c) {
case 'v': /* Note irrelevant code removed */
break;
case 'c':
break;
case 'a':
break;
case 'd':
break;
case 'h':
break;
case 'q':
go = 1;
break;
default:
printf ("something to print\n");
break;
} /*end of switch*/
} /*end of while loop*/ } /*end of main function*/
Are you saying that even though there are printf's up higher that you get
an unresolved printf until you comment out the printf associated with the
default??
Re the alternative getchar() every other time though, do you by any chance
do something like:d<return>? That is, is the other time the <return>?
BTW, why c = 0; immediately followed by c = getchar()?
Also, although it may not be obvious, you should make 'c' and int rather
than a char, as getchar() "returns" an int, not a char (since it's gotta
handle EOF being -1).
Hello Greg. Thanks for the help.
Yes, that is right. I had other printf's in the other cases but when I
got to the default choice the linker came back with the message…
undefined symbol: _printf. I put it in /* */ and the program linked
normally.
I copied the switch segment right from a book and it should work right? I
was aware that the getchar() returns an integer, it's just that I am using
it just for the purpose of receiving one of the six letters of my menu so I
felt it should pass ok. I know I could have used a scanf to do the same
thing but I'm learning and want to understand all possible uses for
everything. As far as a return goes, I had a printf in all the cases, and
all is inside the while loop in main. What you saw was just about all there
was. I was just starting the program (and didn't get too far<smile>), and
was testing the starting menu when I had this happen.
Regards Henry…..thanks again!
Henry,
In reference to the printf error…re-type the line. You may have
a hidden character in there (such as a control character) that your editor
doesn't display.
In reference to the getchar() call, you should always flush
standard input before using getchar() since the default is buffered i/o.
Don
>In reference to the getchar() call, you should always flush standard
>input before using getchar() since the default is buffered i/o.
I must take issue with that: flushing standard input should only be
something contemplated in respect to the logic of a *specific*
program and not all programs. Also, flushing the stream will not
give him unbuffered abilities (unless Aztec is not standard), he'll
have to use a set*buf() function for that if he deems it desirable.
Greg,
No, flushing the buffer won't give you the equivalent of unbuffered
input, but it will clear any extraneous characters from the input buffer.
Failing to flush the buffer prior to the read ends up causing the exact
problem that started this thread.
I would say it's the exception, rather than the rule where you
wouldn't want to flush stdin prior to using getchar().
Don
>No, flushing the buffer won't give you the equivalent of unbuffered
>input, but it will clear any extraneous characters from the input buffer.
Although input stream fflush's may appear to work in that manner, it is
very non-portable for a few reasons. I've mentioned some below.
>Failing to flush the buffer prior to the read ends up causing the exact
>problem that started this thread.
I'm not convinced it is. Being require to do a flush (fflush()) could be
too strong a requirement and is an indication to me that the program perhaps
didn't do something it should have done or that the users didn't do something
they should have done.
>I would say it's the exception, rather than the rule where you
>wouldn't want to flush stdin prior to using getchar().
Disagree. It should be up to the logic of the program at hand.
Furthermore as mentioned above, this is not what fflush() is for.
Fflush() is for *output* streams ONLY. A fflush() that works ok for
input is not standard. Furthermore, even if fflush() did work on stdin
(and it does for many compiler systems) it only buys you a bit … as then
you are assuming a number of things like line-buffering and tty input and
that needn't be the case at all.
Hi Don. I'll check on that hidden control character possibility.
I put #ifdef debug statements in the program and what happened was that
the first time through the while loop c was == to the chosen option by the
getchar(). But the second time through it printed nothing. Don't know if it
was a null, space or what. I put the c = 0 there trying to satisfy the
getchar try for the next char but it didn't help.
This flushbuffer thing. The only flush anything I have found in my manual
is FlushCList (cList). As you may recall, I'm teaching myself C at home as
a hobby, so I may not understand some of your lingo <smile>. I appreciate
the help all the same.
Thanks Henry
When you defined c as a char, but then set it as an int (c=0), I'm
surprised there were not any compiler errors (var vs. return mismatch).
Also, I think that when you surrond a switch choice e.g. 'd', the switch
integer is checked against the numeric value of d. Have you defined c as
an int and tried to compile that way? Robert 8)
If I recall his program there were probably no errors as a char *is* an
integer of sorts….
True enough, but beauty is only skin deep. If _everybody_ would learn how
to program in _assembly_, we wouldn't have these type of problems.
However, after looking the program over, I feel humbled by the root of the
problem. I use Manx, and you must link with the -lc32 library as: ln
program.o -lc32
Also, delete the c = 0, it is not needed. But of course, you will find
that now you have two "responses" every time you "enter" a keystroke. The
getchar() is not really suited to reading from the keyboard. What now
happens is that the correct choice he made is printed to screen first, then
the default choice is printed because getchar() also accepts and sends his
program the "enter" key (that is '\r', I believe). The programmer , would
be better off defining a char string of 2 char long, and just compare the
first char in the string with the case statement.
I felt humbled because it took me 1.5 hours of "ferocious" programming to
remember about the -lc32 thing and the printf for Manx.
Robert (when it rains, I get wet)
>you will find that now you have two "responses" every time you "enter" a
>keystroke. The getchar() is not really suited to reading from the keyboard.
Sorta… It is if you let it. Also, many C compiler do have strict console
oriented I/O routines, whether this one does I do not know.
>What now happens is that the correct choice he made is printed to screen
>first, then the default choice is printed because getchar() also accepts and
>sends his program the "enter" key (that is '\r', I believe).
No. <enter> is a character in its own right, so there is not two responses,
but two characters (I mentioned the fact that the original poster may have
been hitting the <enter> key in my original reply to the message, but I
do not believe that the poster has addressed this yet).
>The programmer , would be better off defining a char string of 2 char long,
>and just compare the first char in the string with the case statement.
But then he wouldn't be doing getchar() but something like gets()'s.
That would work if he only wanted to pull in the first character of
every line. There are numerous other programmable alternatives as well.
It sounds like you agree somewhat. But I did find out the enter key is the
newline character. That *is* the second response he is referring to. Also,
looking at his program, it is plain he only wants the _first_ char typed
in. Either way, the computer is not a smart machine, just fast. He must
find a way to deal with newline since he is dealing with a buffered input.
Either go to a char string input, or do the dreaded unbuffered input
routine (fear of the unknown, there). Of course, "there should be a call
to fflush() between input and output calls. The call ensures that any
input or output collected in intermediary buffers is sent on…….." This
is a direct quote from my C manual. I do use this on the DOS machines at
work, but I'm not doing anything dealing with console currently on the
Amiga. For me, it usually winds up being easier to just use a char string.
I'm not looking for eloquence, I'm looking for sturdiness and the easy way
to do things (as long as it doesn't resemble spaghetti). We both agree, and
I've born it out by a small program, the second time his program responds
it is due to the newline character as you mentioned in your first message.
I've never been able to read from the unbuffered console, of course I
haven't really _tried_ to either. BTW, IMHO, the char string is best (for
me), I need to check inputs some of the time and manipulate the string
itself. Robert 8)
>or do the dreaded unbuffered input routine
And what would that be? Don't Ami C compiler support setbuf/setvbuf()??
>Of course "there should be a call to fflush() between input and output
>calls. The call ensure that any input or output collected in
>intermediate buffers is sent on…" This is a direct quote from my >C
manual.
Your C manual is wrong from both a C standard perspective and a logistic
one (input buffers can't be "sent on", that makes no sense). A direct
quote from ANSI C tell us:
"If 'stream' points to an output stream or an update stream in which the
most recent operation was not input, the fflush function causes any
unwritten date for that stream to be delivered to the host environment to
be written to the file; otherwise, the behavior is undefined."
So like I said earlier, fflush() is for output even though many C compiler
do support fflush()ing input streams. Why standard doesn't allow the input
stream this capabilility is because the fflush() can become quite futile
given that the host environment has input mechanisms that occur before that
hit into the stdio subsytem with the effect that the fflush() becomes
innocuous in some cases and logically detrimental in other cases.
Well, it won't be the first time I ever read something that was wrong! On
the other hand, with Aztec 3.6a I couldn't find a setvbuf function. There
is a setbuf function. If he needs to use setvbuf, he will need to upgrade
to 5.0d. The dreaded unbuffered is a misnomer. I really meant to refer to
reading a keystroke as it occurrs, without waiting for return or enter. I
played with that a while today, and I think I'll just wait until I return
from vacation prior to playing with it anymore. It's against the law to do
anything that looks like work on vacation time. I suppose this means you'll
want me to clean up my dos code for the fflush stuff? If you insist (I was
working on a GUI anyway) <g>……..
Robert Life is too much fun for any foolish seriousness…..
>with Aztec I couldn't find a setvbuf function
setvbuf() is a superset of setbuf(), the former being ANSI and the
latter being a UNIXism.
>I suppose this means you'll want me to clean up my dos code for the
>fflush stuff?
So long as you brought it up, yes!
Ya see, what the compiler vendors are probably doing is just resetting
the buffer pointer and some other stuff which becomes innocuous for
something like stdin, so it *appears* that the “input buffer'' has
been cleared. What's at issue is exactly what this input buffer is
as well as where it is. In that light input is different from output
since you may have type a 20 character line but under most environments
stdio won't know anything about it until you hit the return (and then
there are all sort of other idiosyncrasies like your stdio buffering
requests as well as you environments buffering settings. And of course
it gets even more confusing when the input then comes from a file rather
than an “interactive device'').
Vacation already over, some vacation. Well, as far as this input and
output stuff is concerned, bear in mind that an "input" is really an
"output", and vice versa. You are only guided by common sense, e.g. you
wouldn't want to open the printer and try to get "input" from it. The
input and output names attached to streams are purely to assist in the art
of programming them, IMHO. As I said before, if everybody programmed in
_assembly_ you wouldn't have these problems. You'd have better, *bigger*
problems (think of the challenge). It does not surprise me that most
compilers might handle things different. The reason Manx 3.6a seems to lack
setvbuf compared to Manx 5.0d is due to the ANSI compliance of Manx Aztec
C. K&R left C vague in places, to allow for flexibility ( I *hope* ), and
now some committee wants to standardize to Cobol or Pascal type
restrictions. Then you wouldn't be able to get away with a statement like
char is a type of int, in reality. IMHO, C grew so fast, comparatively
speaking, due to the enormous flexibility (and hence responsibilities) of
the syntax; and now some committee is going to kill this flexibility for
programmers that can only live in a nonflexible environment where exacting
rules have to be followed. I will suffer with it as long as I can, and
then revert back to pure assembly programming since the only reason I took
up C several years ago was because other technical friends insisted it
wasn't the same old syntax restructured/relabeled. I actually have
assembly printouts several years old that I can still follow (due to
comments and structure). I just *hope* the committee doesn't butcher C,
but sometimes these guys are worse than congress. BTW, that is not to say
they haven't done _some_ excellent work, I just don't remember any.
8) 8) 8)
Robert (back and mean as ever)
Actually, the ANSI C committe killed although no flexibility and left the
language relatively intact. Also, I'd rather have some things lost rather
than the sad state of affairs that the "portability" of C was in when the
committee was formed (and for C, the sad state was a direct effect of
irresponsible vendors IMO). Anyway, it wasn't butchered…
Hi Robert. I'm aware that I didn't really need the c = 0. It was just done
in frustration in not working out the bug <smile>.
I don't understand why I need to link in the -lc32 library though. Would
it have to do with portability?
There is one problem I have been trying to figure out that you might be
able to help me with… If I wanted to print some text to the screen for a
period of time and then let it clear I see UNIX has the function
sleep(number); where number is a # of seconds. Have you seen the same
effective function in MANX? I have the 3.6a and haven't seen anything like
it. Another way would be is to have the user -Hit any key- and the program
continues. If it isn't to long an explanation, could you tell me how to get
that to work WITHOUT having to hit the return key? Or at least tell me what
section to read up on.
Thanks for your time!
Henry = Henry;
All I can say is that printf must be a 32 bit implementation, necessitating
(scooze my spelling) the linkage with the 32 bit library. There is a
function called Delay() in the Amiga. 50 ticks is a second, so to wait for
10 seconds your line would look like: Delay(50*10); /* wait 10 seconds */
Delay() is in the dos.library. Robert 8)
Okie dokie! Thanks again Robert.
Henry;
Henry,
You might try using the timer.device to time how long your message will
stay on screen or use the AmigaDOS function Delay(). By using the
timer.device your program can continue running while it's waiting for timer
event. If you use Delay() your program will not continue running during
the waiting period (but other tasks/programs will).
-sja
OK thank you Steve. It sounds like what I want.
Henry;
Hi Robert. I'll give the int declaration a try. Thanks for the
suggestion.
{ Henry };