"Growing up in C"

I would like to thank Greg Bacon for saving this article, and converting it to HTML. I didn't have any saved copies of this, and thought I'd lost it.

Path: info.uah.edu!news.msfc.nasa.gov!newsfeed.internetmci.com!howland.erols.net!www.nntp.primenet.com!nntp.primenet.com!mr.net!winternet.com!solon.com!not-for-mail From: seebs@solutions.solon.com (Peter Seebach) Newsgroups: comp.lang.c Subject: Re: How do you leave teenage-c to become a full grown c programmer....how? Date: 4 Oct 1996 12:34:32 -0500 Organization: Usenet Fact Police (Undercover) Lines: 227 Message-ID: <533hr8$q4m@solutions.solon.com> References: <nA+CDAApPPVyEwNU@tedros.demon.co.uk> Reply-To: seebs@solon.com NNTP-Posting-Host: solutions.solon.com In article <nA+CDAApPPVyEwNU@tedros.demon.co.uk>, Ted <tedros@tedros.demon.co.uk> wrote: >For those programmers who are self taught c programmer (such as myself) >may have encountered a problem in becoming an expert programmer (note i >understand that there are a few who just *become* experts overnight...or >so i'm told). This is a typical unfinished life history of a c >programmer which i'd like any expert to finish: Doesn't sound like what happened to me, but I think it's an interesting question. I never planned to learn C. Long ago, when 4.3BSD was a new system, I used to play a game called rogue. Then, someone (a friend of a friend of the family, or so) gave me a game called "hack" for my PC-type-machine. I loved it. My father got me the source. Now, the source was for a Unix system, and wouldn't have compiled on a PC. It was on paper, and I didn't have a scanner. It was in C, and I didn't know C. I also didn't know any of these things. I know how the game played, and I had something I had been told was the source. I knew what source was; source was stuff that looked like 120 GOTO 2300 2300 GOTO 120 and told the computer what to do. The source for hack seemed pretty readable. It had blocks of English text which were inside little boxes of asterisks. It had things like Print("You have a strange feeling."); It had stuff that looked like if (u.wep->type == OBJ_IRONBALL) tmp += 25; .... All of this was obvious. It didn't take time or effort to learn to read it; it was just plain old instructions for what to do. But, of course, I knew none of this. I just read it. When I wanted to edit my version of hack, I searched the binary until I found strings, and edited them, learning that strings are frequently stored next to each other in the output, and that a string starts at the same place, even if you overwrite it with other data. I continued searching, and I found tables, which had the same data in them as a struct did, in the same order. But none of this seemed like learning; I was just poking around with a disk editor. Years passed. I made a brief attempt to learn C, because it looked like a way to make the computer do things, but never got beyond char ary[10]; ary[0] = 'h'; ary[1] = 'e'; ... .... and I eventually got bored and did something else. In college, I started reading news, and reading mail, and playing muds (when they started being available.) One day, I was bored, because I couldn't play a game, because the system wouldn't let me play games during certain hours. A friend (actually the sysadmin, whom I'd love to get in touch with) showed me how to copy the source out of /usr/src (we had a source license), type 'make', and have a game I could play. So, of course, I looked at the source, and it was pretty readable. I'd been reading things like that five years ago, and it still looked like English. I started using ftp (this was back when you ftp'd from uunet.uu.net, not ftp.uu.net), and downloading things, and I'd say "make" and sometimes they'd build. Mostly, they'd give weird warnings. Not knowing anything about these, but being mindlessly agressive, I went in with an editor and tried to fix them, mostly unsuccessfully. But I kept trying, and started getting pretty good at it. At one point, I managed to get permission to install a game on the system, but I wanted to make it compress save files. A game I already had (omega; more on this later) did this, so I started trying to copy the code. It took me more than two hours of experimenting with strcat() and strcpy() and system(). But I *did* it. Later, I started playing more seriously with omega. Omega was in the same family as rogue or hack, but much bigger. It crashed on the computer I had (a NeXT) at home, so I tried to fix it. I failed. I later got a new version, and it compiled and ran. Joy! I was just getting into the game, so I would read the code, and play the game. Sometimes I'd look things up in the code. Sometimes I'd even try to fix bugs. Eventually, I *could* fix bugs. Mostly easy ones, but I found a fair number, and I got pretty good at fixing them. Then I started adding features. I spent a month or two doing very little but modifying the game. Then, of course, I decided to write my own. The astute reader will note that I had never written *ANYTHING* bigger than "hello, world" at this point. I wanted a game that had objects and rooms and monsters, and an interface like omega's, and was fun to play. About a month later, I *still* couldn't get linked lists to work, and I had tons of problems. My code wouldn't run, it wouldn't always compile, and I was mystified. About then, I ran into a wizard. A guy named Mike that my father introduced me to (one of his students) had asked me if I coded, or some such, and I started explaining my problems. He started explaining to me *why* they were problems. He told me about abstraction. I didn't really follow, of course. He showed me an example, and he suggested I try a few techniques. I did. The new version, two weeks later, let you cast spells at monsters, attack them, select weapons and armor, fight, leave town and go to a dungeon, and do other things like that. It was limited in ways, but it did things that even omega (my baseline) didn't do. I still have that code. I don't think it runs on any modern machine; it's full of illegal garbage, and it was horrifically ill-designed. The 2nd version was my first attempt at ANSI C. Leaping out to my better-trained eyes: void main Where *did* I get that stupid idea? char graphchar[] = "X .#Oo()~*6\"=^-+X.|-#^\";,*<>%)}&][{+^\"=!?/@"; Of course, there was an enum that indexed into it. I used a cross between 1TBS and GNU indenting. Too little whitespace. On the other hand, it was 213k of code (8659 lines), and it all seemed to work. Last I recall, it had no known bugs. The largest module was my monstrous linked list hackery. It was 26k; 95% of it would be handled by my 3k linked list library today. 25 modules of C, and 7 headers. Oh, wait; here's the "known bugs" list: 1] Occasionally an empty space will be marked solid. 2] Invisible monsters on occasion. 3] No idea if greedy monsters work... 4] Traps/loc_vis, and all that. New system? I think I actually found the bug that caused 1]. (4. was a comment where I had the problem that a space might have a door, a monster, an object, and a trap; what to draw?) I would be happy to put the unaltered source tree up for people to look at; it's utterly horrible code, but on the other hand, it was my first real project. It is moderately curses-dependant. (Heavily, even.) It uses a bit of Unixism, but not much; mostly, you'd just want to remove the signal handlers for non-standard signals. Anyway, much time passed. I had access to a Mac for a while, and I was really confused, because I couldn't find <curses.h> I tried including something like <CursorCrtl.h>, but it wasn't what I wanted, which struck me as insane; I remember being confused at the way the Mac implementor had hidden the header. I got an Amiga. I got a C compiler for it. I got a curses implementation for it. So I started doing a new version of that game (never came close to completion, but I did get the key-bindings working...)... And somewhere in here, was the event that moved me from "using C" to "learning C". I wanted to do some keyboard I/O. So, I tried to use getchar(). Of course, it didn't work the way I wanted it to. So, being thoughtful, I tried to ask my friends. The most help anyone could give me was to reccommend getch(). I tried it. It did exactly the same thing; observation revealed it was a macro for getchar(). (The wizard was elsewhere at the time...) So, like an idiot, I posted to comp.lang.c, asking if there was a portable way to do it. (I had learned onough to know I wanted a portable way to do it.) In my defense, I believe I had the brains to read the group looking for my answer. I didn't get a posted answer (or at least, not one which was of any use), but someone (I'm pretty sure it was either Steve Summit or Chris Torek, but I'm not sure I have the info anymore...) wrote me a very helpful letter, pointing out that this was a FAQ, and that there was no way to do this in *C*, although my platform could probably do it. It was like a dam burst. Suddenly, all the little irritations (no <curses.h> on the mac, having to find one on the amiga, discovering that it had bugs because it was for the other kind of compiler, getch() doing the "wrong" thing...) solidified into an understanding that the *language* was different from the *compiler*. I ran into that wizard type again, and he started trying to get me to learn things. I was interested, now; I had realized that I could be better at these things, and they could be easier. The abstraction thing had started to make sense when I did the 2nd version of my game; now it made a lot *more* sense. Somewhere in there, I had discovered that my game was unusably slow; it got to about 2-5 seconds per move. I optimized it, of course; I moved all of the refresh-related activities to one point, so all the game would do is flush screen activity *when you needed to know* - essentially, before any attempt to get input, it would update the screen, if a "dirty" bit had been set, then clear the dirty bit. This fixed everything, of course. I started reading comp.lang.c, and comp.std.c. Somewhere out there, I got a copy of the FAQ. I started programming a lot more, and I got a lot better at it. I had a brief fling with DOS programming, but gave up; it was too painful. I got in the habit of getting and using new versions of gcc. Much time passed. Somewhere in the last few years, I started *answering* questions, not just asking them. (I still ask a fair number of questions.) I've written applications. When I got a chance to run purify on an application, I found out that it had only one memory bug, which was a memory leak I had documented as a limitation of the POSIX spec for getenv/putenv. (You can't tell, when looking at an environment variable, whether or not it uses allocated space, but when you use putenv() with a piece of memory, you *lose* that memory, even if it was allocated.) That application has been in use for 8 months now, and the only bug in it was that, if you had no .rc file for it, it wouldn't use the right directory by default. This bug cannot be recreated without removing the setup file and running without your enivornment set correctly. It goes away if you open and close the options window. :) Any other bugs have remained hidden. That's how I got here; I just *like* programming, I program constantly, and I enjoy it. I learned a *lot* from reading the source to Omega; it's a very good program. Some bugs, some design flaws, but it uses abstraction and isolation of code to good effect. (I'm told it was the original author's first program.) -s -- Peter Seebach - seebs@solon.com - Copyright 1996 - http://www.solon.com/~seebs Unix/C Wizard - send mail for help, or send money for consulting! The *other* C FAQ, the hacker FAQ, et al. See web page above. Unsolicited email (junk mail and ads) is unwelcome, and will be billed for.