[comp.lang.c] C problems

armhold@topaz.rutgers.edu (George Armhold) (05/30/89)

I started using my C compiler today (Manx Aztec V3.6a), and I'm really
frustrated with I/O. I have the K&R book, _Understanding C_ by Bruce
Hunter, as well as the documentation that came with Manx. All three of
them left me bewildered with the various file I/O conventions. There's
open, fopen, creat, etc... Which do I use when? What about writing to
the console? Can anyone recommend a GOOD book that explains the
various methods of I/O and also points out differences between
"standard" and "machine specific"? 

Also, here's some source I tried today. What I'm trying to do is
simply copy one file to another. When I compile it, I get error 125
which means "too many subscripts or indirection on integer". It occurs
wherever I mention argv[x].

#include <stdio.h>
main(argc, argv)
{
	int c;
	FILE *fp1, *fp2;
		       	
	if ((fp1=fopen(argv[1], "r"))==NULL) {
		printf("Can't open %s", argv[1]);
		exit();
		}

	if ((fp2=fopen(argv[2], "w"))==NULL) {
		printf("Can't open %s", argv[2]);
		exit();
		}
	
	while ((c=getc(fp1)!=EOF)) 
		putc(fp2);

}

Thanks
-George

deven@rpi.edu (Deven Corzine) (05/30/89)

In article <May.29.21.40.18.1989.8866@topaz.rutgers.edu> armhold@topaz.rutgers.edu (George Armhold) writes:

   I started using my C compiler today (Manx Aztec V3.6a), and I'm really
   frustrated with I/O.

Poor guy...  you'll surely be baffled by Amiga Exec I/O...

   Also, here's some source I tried today. What I'm trying to do is
   simply copy one file to another. When I compile it, I get error 125
   which means "too many subscripts or indirection on integer". It occurs
   wherever I mention argv[x].

   #include <stdio.h>
   main(argc, argv)
   {
   [...]

This error has nothing to do with the I/O; you never declared what the
parameters rto main were, so the compiler assumed integer for both.
argc is an integer, but argv is a char **.  You need to add a line
after main(argc,argv) but BEFORE the "{" which reads "char **argv;" or
"char *argv[];" (take your pick; they mean the same.) and you *should*
add right before it "int argc;" but you don't need to, since the
compiler will assume it.

It thought argv was an integer, and argv[x] was the indirection on
integer causing the error.

Deven
--
shadow@[128.113.10.2]   <shadow@pawl.rpi.edu> Deven T. Corzine (518) 272-5847
shadow@[128.113.10.201] <shadow@acm.rpi.edu>  2346 15th St.    Pi-Rho America
deven@rpitsmts.bitnet   <userfxb6@rpitsmts>   Troy, NY 12180-2306  <<tionen>>
"Simple things should be simple and complex things should be possible." - A.K.

armhold@topaz.rutgers.edu (George Armhold) (05/30/89)

Thanks to the many people who responded to my cries for help with C.
Only a few hours after I posted, I receieved around 20 replies! Now I
feel silly, of course declaring argv and argc was the problem!
Thanks again.

-George

grwalter@watmath.waterloo.edu (Fred Walter) (05/31/89)

In article <DEVEN.89May30033457@daniel.rpi.edu> deven@rpi.edu (Deven Corzine) writes:
>In article <May.29.21.40.18.1989.8866@topaz.rutgers.edu> armhold@topaz.rutgers.edu (George Armhold) writes:
>>  I started using my C compiler today (Manx Aztec V3.6a), and I'm really
>>  frustrated with I/O.

>argc is an integer, but argv is a char **.  You need to add a line
>after main(argc,argv) but BEFORE the "{" which reads "char **argv;" or
>"char *argv[];" (take your pick; they mean the same.) and you *should*
>add right before it "int argc;"

As well, the following code segment has a problem...

  	while ((c=getc(fp1)!=EOF)) 
  		putc(fp2);
                ^^^^^^^^^^

You really want to be using putc(c, fp2). (Not to mention adding spaces
would increase the readability of your code IMHO).

	fred

Yuklung_Morris_Ng@cup.portal.com (05/31/89)

You haven't define the type of argc and argv on main().  Remember, main() is a
a function, not a particular program like Pascal.
 
Try this:
 
main(argc,argv)
int argc;
char *argv[];
{
	......;
}
 
				- Morris

doug@xdos.UUCP (Doug Merritt) (05/31/89)

In article <May.29.21.40.18.1989.8866@topaz.rutgers.edu> armhold@topaz.rutgers.edu (George Armhold) writes:
>
>Also, here's some source I tried today. What I'm trying to do is
>simply copy one file to another. When I compile it, I get error 125
>which means "too many subscripts or indirection on integer". It occurs
>wherever I mention argv[x].

Oh well, I may as well join the hundreds of others who will all point out
the same problems. I usually resist but I feel like burning bandwidth
for once:

>main(argc, argv)
>{

You need to declare the parameters here, like for instance:
	main(argc, argv)
		int	argc;
		char	**argv;

>	while ((c=getc(fp1)!=EOF)) 
>		putc(fp2);

There are two problems here...one is that the while() is misparenthesized,
it should be:
>	while ((c=getc(fp1)) != EOF) 

As written it was doing (c = (getc(fp1) != EOF)), which always assigns
either a zero or a one to 'c'.

Second, you're not giving the right parameters, 'c' is missing from
the call:
		putc(c, fp2);

These are all pretty obvious bugs, so I suspect that your original
frustration in not being sure which functions to use in the first place
became a problem in itself. Pirsig called this a "gumption trap" in
"Zen and the Art of Motorcycle Maintenence". The recommended cure is
to stop, cool off, relax, and then go back to what you were doing.

For various reasons (style, portability, forming bug-avoiding habits)
you should also close the files before exiting, and also call exit
explicitly:
	fclose(fp1);
	fclose(fp2);
	exit(0);

The explicit exit provides a clean return code so that your programs
could be used in your 'make' scripts.

For the same reason, your error exits should give a non-zero exit code:
	if (...open fails...)
		exit(1);
Or on the Amiga, perhaps:
		exit(10);
	
Programming in C is fun once you get used to it.
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

"Welcome to Mars; now go home!" (Seen on a bumper sticker off Phobos)

dhesi@bsu-cs.bsu.edu (Rahul Dhesi) (05/31/89)

In article <365@xdos.UUCP> doug@xdos.UUCP (Doug Merritt) writes:
>		putc(c, fp2);
and
>	fclose(fp1);

May I respectfully suggest error-checking:

     if (putc(c, fp2) == EOF)
	... handle error ...

And yes, even fclose!

     if (fclose(fp1) == EOF)
	... handle error ...

It seems like overkill, but not detecting a full device is a *very*
common bug in C programs.  (However, a possible optimization is to call
ferror() just once before the output stream is closed instead of
testing the value from putc all the time.)
-- 
Rahul Dhesi <dhesi@bsu-cs.bsu.edu>
UUCP:    ...!{iuvax,pur-ee}!bsu-cs!dhesi
Career change search is on -- ask me for my resume

pat@mirror.TMC.COM (06/01/89)

/* Written  9:40 pm  May 29, 1989 by armhold@topaz.rutgers.edu in mirror:comp.lang.c */
/* ---------- "C problems" ---------- */

>I started using my C compiler today (Manx Aztec V3.6a), and I'm really
>frustrated with I/O. I have the K&R book, _Understanding C_ by Bruce
>Hunter, as well as the documentation that came with Manx. All three of
>them left me bewildered with the various file I/O conventions. There's
>open, fopen, creat, etc... Which do I use when? What about writing to
>the console? Can anyone recommend a GOOD book that explains the
>various methods of I/O and also points out differences between
>"standard" and "machine specific"? 

What I think that you should do, since it sounds like you are still
learning, is to use the higher level functions like fopen(), fclose(),
fscanf(), and such.  These functions take care of the needs for the 
I/O stream (with buffer allocation and such) for you and in that way
while you are learning you don't have to be bogged down with the 
sordid details of I/O.  As you progress and understand how the pointers
work and how to safely allocate memory and other needed things, then
you can get into lower level I/O with open, write, and things along
that nature.  If you are learning, be patient, those pointers can be
a b***h!


Also:

>Also, here's some source I tried today. What I'm trying to do is
>simply copy one file to another. When I compile it, I get error 125
>which means "too many subscripts or indirection on integer". It occurs
>wherever I mention argv[x].

Whenever you define a function (and main() IS a function) you must declare
the types of the arguments.  If you don't then the compiler will (at best)
default them to integers.  This is where you get "too many subscripts or
indirection on integer."

Here's how you correct it:

#include <stdio.h>
main(argc, argv)
int argc;
char **argv;      /* since you are learning it may be easier to understand
                     this syntax better by defining it as:  char *argv[]  */
{
	int c;
	FILE *fp1, *fp2;      ___subscript on an integer before fix.
		       	     /
	if ((fp1=fopen(argv[1], "r"))==NULL) {
		printf("Can't open %s", argv[1]);
		exit();
		}

	.
	.
	.

}


Good luck, George.

bill@twwells.uucp (T. William Wells) (06/02/89)

In article <7511@bsu-cs.bsu.edu> dhesi@bsu-cs.bsu.edu (Rahul Dhesi) writes:
: It seems like overkill, but not detecting a full device is a *very*
: common bug in C programs.  (However, a possible optimization is to call
: ferror() just once before the output stream is closed instead of
: testing the value from putc all the time.)

Not quite: if you are going to do this, call fflush and then ferror
and you still need to check the results of fclose.

The fflush is needed so that the final write occurs; the fclose to
deal with things like failing to update directory entries.

(I suppose that the fclose should return error on a failure to write
the final buffer, thus eliminating the need for any checks other than
on the fclose, but several stdio implementations I've seen don't.)

Even better is to determine some points in your program that don't
occur too frequently, say <5% of the frequency of character writes,
and call ferror there as well. That way you catch the error after only
a few "file system full" messages get printed on the console rather
than 600 billion. :-) Frequently, a good place for a text file is
after each newline is written.

The message printing, BTW, is a serious problem with some UNIX's: a
good way to bring those systems to their knees is to get the kernel to
generate an unending series of messages. What happens is that, since
kernel message writing for these systems is polled, while a message is
being written, nothing other than interrupts are processed.

---
Bill                            { uunet | novavax } !twwells!bill

porges@inmet.UUCP (06/02/89)

>/* Written  3:34 am  May 30, 1989 by deven@rpi.edu.UUCP in inmet:comp.lang.c */
   #include <stdio.h>
   main(argc, argv)
   {
   [...]

>This error has nothing to do with the I/O; you never declared what the
>parameters rto main were, so the compiler assumed integer for both.
>argc is an integer, but argv is a char **.  You need to add a line
>after main(argc,argv) but BEFORE the "{" which reads "char **argv;" or
>"char *argv[];" (take your pick; they mean the same.) and you *should*
>add right before it "int argc;" but you don't need to, since the
>compiler will assume it.
>

    Since noone else jumped in on this:  char **argv and char *argv[] are NOT
the same thing in delcarations.  In the first case you have a pointer to
a pointer to a character; you may in fact have a pointer to an array of
pointer to characters.  In the second case, however, you have an array
of unknown size of character pointers on the argument stack.  You
almost certainly want char *argv[].

					-- Don Porges
					porges@inmet.com
					{...mirror,ima}!inmet!porges

porges@inmet (06/03/89)

    OK, nobody send me mail reminding me I'm wrong: I'm wrong.  I was misled
by the section 3 routines, execl and execle, that are called as if you
put a series of string addresses on the stack.  They call execve (on
Sun Unix, at least) which pass in argc, argv, and envp, which are one
integer and two pointers to pointers to characters.  K&R version 1
explicitly states that char *x[] and char **x are identical IN FORMAL
PARAMETERS.  Sorry to have cluttered -- I tried to delete my posting
but it was too late.

					-- Don Porges
					porges@inmet.com
					{...mirror,ima}!inmet!porges

karl@haddock.ima.isc.com (Karl Heuer) (06/03/89)

In article <236100015@mirror> pat@mirror.TMC.COM writes:
>char **argv;      /* since you are learning it may be easier to understand
>                     this syntax better by defining it as:  char *argv[]  */

On the other hand, since this use of [] is a special case which exists nowhere
else in the language (it works *only* for formal arguments), it may be less
confusing to stick with "char **argv" after all.

(Just my opinion.  Decide for yourself.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

ark@alice.UUCP (Andrew Koenig) (06/05/89)

In article <124200016@inmet>, porges@inmet.UUCP writes:

>     Since noone else jumped in on this:  char **argv and char *argv[] are NOT
> the same thing in delcarations.

True; except for declarations of formal parameters.

That is:

	void f(x) char *x; { /* stuff */ }

means precisely the same thing as

	void f(x) char x[]; { /* stuff */ }

but

	void f() { char x[10]; }

is different from

	void f() { char *x; }

-- 
				--Andrew Koenig
				  ark@europa.att.com

les@chinet.chi.il.us (Leslie Mikesell) (06/06/89)

In article <13566@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>char **argv;      /* since you are learning it may be easier to understand
>>                     this syntax better by defining it as:  char *argv[]  */

>On the other hand, since this use of [] is a special case which exists nowhere
>else in the language (it works *only* for formal arguments), it may be less
>confusing to stick with "char **argv" after all.

Umm, isn't that the same as:

char *list[] = {
                "one",
                "two",
                "three",
                 0 };

which seems to work as a global definition.  Argv is something similar
so the char *argv[]; declaration makes sense.

Les Mikesell

chris@mimsy.UUCP (Chris Torek) (06/07/89)

>In article <13566@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer)
>writes:
>>... since this use of [] is a special case which exists nowhere
>>else in the language (it works *only* for formal arguments), it may be
>>less confusing to stick with "char **argv" after all.

In article <8639@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell)
writes:
>Umm, isn't that the same as:
>
>char *list[] = { "one", "two", "three", 0 };
>
>which seems to work as a global definition.

No, it is not the same---it only looks the same to the casual observer.
As Karl stated, `char *argv[]' is a special case because argv is a
formal parameter.  A C compiler is required silently to pretend that
you actually wrote `char **argv'.  That is:

	char *list[] = { 0, "hello", 0 };

	void foo() { (void) main(2, list); }

	int main(int argc, char *argv[]) {
		if (argc > 1) puts(argv[1]); else foo();
		return 0;
	}

is treated by the compiler as though argv (and only argv) were declared
with

	int main(int argc, char **argv) {

The declaration for `list' is *not* altered, because it is not a formal
parameter.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris