armhold@topaz.rutgers.edu (George Armhold) (12/31/89)
I've a rather neophyte question for the net: I have a program that employs a recursive routine to traverse a directory structure on a disk. If I have the program simply traverse the structure and "visit" each file and directory, the program works fine. But when I try to copy each file I find, the program crashes the machine, usually with a "Task held" requester. Here is the copyfile() function I call whenever I find a file: void copyfile(source, destination) char *source, *destination; { int file1, file2; /* file descriptors */ int n; char buf[1024]; /* buffer for data transfer */ if ((file1=open(source, O_RDONLY))==-1) /* open READ file */ my_error("Error opening ", source , FATAL); if ((file2=creat(destination, S_IWRITE | S_IREAD)) <0) my_error("Error opening ", destination, FATAL); while ((n=read(file1, buf, BUFSIZE)) >0 ) if (write(file2, buf, n) !=n) my_error("Write error on file ", destination, FATAL); close(file1); close(file2); } The program crashes when it is only 2 or 3 levels deep into the recursion (ie 2 or 3 directory levels.) If I increase the stack size to something like 10000 befre I run the program it works fine. My question is, where does the memory come from when the program calls copyfile()? Memory for variables comes from the stack, and dynamically alocated memory comes from the heap? If so, is it really necessary to increase the stack size for simple programs such as this? In an attempt to figure out what happens with the stack during recursive routines, I wrote the following program: main(argc, argv) int argc; char *argv[]; { foobar(1); } foobar(counter) int counter; { printf("%d", counter); if (counter<10000) foobar(counter+1); } } When I let it run, sometimes it crashes, and sometimes I get a requester saying "Program_foo: Stack overflow". Is Lattice inserting this into my code when it compiles? And why does it only work SOMETIMES?? Finally, can anyone recommend a good book for learning to program the Amiga in C? I ordered "Programmers Guide to the Amiga" by Rob Peck which I should get my hands on shortly. Any and all help much appreciated! -George
a464@mindlink.UUCP (Bruce Dawson) (12/31/89)
The stack is _not_ used as the heap on the Amiga. Local variables, including arrays are allocated on the stack. mallocs, AllocMem()s etc. are allocated out of the free memory 'heap', which includes all memory that has not already been allocated. Since stack memory has already been allocated, it won't be used by one of these calls. However, since the example program was declaring an array on the stack, it would indeed chew up stack space at an enormous rate. .Bruce.
caw@jolnet.ORPK.IL.US (Chris Wichura) (12/31/89)
Every time a routine is called it will use the stack. The return address gets pushed on and then most coimpilers will use a LINK command to get a local frame to store variables in. Thus, your copyfile() routine will eat up well over 1024 bytes from the stack when it is called as you have the buffer set at that size. On the amiga the stack is usually used as the heap as well. So there are two things you can do to help your program be less of a stack-o-hollic: 1) Instead of using the char buf[1024] use a char *buf and call your favorite memory alloc routine (ArpAlloc(), AllocMem(), malloc(), etc) to get the storage for the buffer and then free the memory after the copy file routine is done. This will drastically reduce the amount of stack space your copyfile routine needs. 2) If you can get around using a recursive function then by all means so so. I had a routine that scanned a dir and did various things that needed a stack of 30k to work with my HD (I have some rather sever levels of directory depth in some places...). I re-wrote the routine inside a big for(;;) {} loop adding a couple of variables to make it `think' it was recursive and now the same program will work just dandy with a 4000 byte stack (the AmigaDOS default). Idea two usually tends to be a fair amount trickier than the first one :-) -- Christopher A. Wichura u12401 @ uicvm.uic.edu (my home account) caw @ jolnet.UUCP (my Usenet feed)
groo@dsoft.UUCP (Bill Squier) (01/02/90)
In article <Dec.30.13.09.02.1989.28450@topaz.rutgers.edu> armhold@topaz.rutgers.edu (George Armhold) writes: ] ]I've a rather neophyte question for the net: ] ]I have a program that employs a recursive routine to traverse a ]directory structure on a disk. ] [stuff deleted] ]Here is the copyfile() function I call whenever I find a file: ] ] ]void copyfile(source, destination) ]char *source, *destination; ] ]{ ]int file1, file2; /* file descriptors */ ]int n; ]char buf[1024]; /* buffer for data transfer */ ] ] [ rest of code deleted... ] ] ]The program crashes when it is only 2 or 3 levels deep into the ]recursion (ie 2 or 3 directory levels.) ] [ more creative deleting... ] As was already mentioned, auto class variables created within functions are always allocated off the stack. The two previous suggestions for fixing this are valid, but it's my personal preference to declare buffers (such as your buf[1024]) as external variables. To do this, you would declare it outside all functions. I prefer to put my global variables near the functions that use them. For example: char buf[1024]; void copyfile(source,dest) /* ... */ This avoids a new copy of ``buf'' being generated each time you call copyfile(). ]Finally, can anyone recommend a good book for learning to program the ]Amiga in C? I ordered "Programmers Guide to the Amiga" by Rob Peck ]which I should get my hands on shortly. Any and all help much ]appreciated! ] ]-George The book you mention above is a good one, but you may also want to try "Programming in C" by Stephen Kochan, now in its second edition, I believe. This book will also teach you more about 'C' in general, such as recursion, and how different types of variables are stored. -- Bill Squier - Stevens Inst. of Tech | // "Only Amiga makes it possible" Bitnet: u93_wsquier@stevens | \X/ Internet: u93_wsquier@vaxc.stevens-tech.edu Temporary Inet (Please use until Jan. 13): ...uunet!tronsbox!dsoft!groo
walker@sas.UUCP (Doug Walker) (01/02/90)
In article <2617@jolnet.ORPK.IL.US> caw@jolnet.UUCP (Chris Wichura) writes: >1) Instead of using the char buf[1024] use a char *buf and call your > favorite memory alloc routine (ArpAlloc(), AllocMem(), malloc(), etc) > to get the storage for the buffer and then free the memory after the > copy file routine is done. This will drastically reduce the amount > of stack space your copyfile routine needs. Or, much simpler, just declare the buffer to be global (declare it outside the scope of the function, or put the 'static' keyword on it). Since you only need the buffer during the scope of the routine, this will work for your case. If you really needed a new buffer for each invocation of the routine, you would have to allocate and free each call, but in your case you don't. ***** =*|_o_o|\\=====Doug Walker, Software Distiller======================= *|. o.| || | o |// "READY! FIRE! AIM! (Software under development!) ====== usenet: ...mcnc!rti!sas!walker plink: dwalker bix: djwalker
duncant@mbunix.mitre.org (Thomson) (01/12/90)
Regarding the problem of stack usage with recursive functions, note that it is possible to use static allocation of data structures with recursive functions, as long as the usage of the data structure does not span a recur- sive call. In the copyfile() example under consideration, it would appear to be safe to allocate buff[ ... ] outside the function. This would solve your stack overflow problems without any major code changes. Duncan Thomson P.S. I think the best book for learning C programming, on the Amiga as well as on any other system, is the Kernighan and Ritchie classic, "The C Programming Language."