No Such Number, Address Unknown

Understand one thing about C, and all its mysteries are revealed. C was -- and is -- a language meant as a portable replacement for machine-dependent assembly languages. Keep this in mind when you consider the following example.

Suppose you code an array of part numbers and their names and a few lines to display a list of parts, as shown in Figure 2.1. If you remember C is for machine-level programming, you won't be suprised to find there's no part number 11. In C, 011 is not 11; it's 9! Integer constants that begin with 0 are octal (Get it? The 0 looks like O for Octal.)

If you enter 011, the program outputs 9. Unsurprisingly, the format %i specifies an integer input and output field. Surprisingly, if the input is 011, the value of part_number is 9. You see, on input, %i means "decimal, hexadecimal, or octal integer," whereas on output, %i means simply "decimal integer." Unless this is an application for PDP-11 system programmers, the code should be

The format %d means "decimal integer" for both input and output. Unless your magic number is 8, you should use a lint utility or your editor to ferret out all %i format specifications and numbers that begin with 0.

The previous two examples actually have a much bigger problem than octal numbers. I miscoded the scanf function argument as part_number instead of &part_number. So instead of supplying scanf with the address where I want the input stored (i.e., the address of part_number), I supplied the uninitialized value of part_number. C is powerful, so powerful in fact, that scanf will trash some location in memory pointed to by whatever garbage is in part_number. If you're lucky, the trashed memory will be part of the debugger or operating system code, and you'll earn a C programming purple heart. To avoid winning too many battle ribbons, however, always double-check that you've supplied valid addresses for arguments to scanf and similar functions.