C Language

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.)

Figure 2.1 Sample C Code

 struct part {
   int part_number;
   char description[30];
 main() {
   int i;
  /* Array of part numbers and descriptions */
  struct part part_table[100] =
    {011,   "Wrench"      },
    {067,   "Screwdriver" },
    {137,   "Hammer"      },
    {260,   "Pliers"   },
    /* etc. */
    {0,   "sentinel"   }
  for (i=0; i<100; i++); /* Print the list of parts */
   if  (part_table[i].part_number == 0)
   printf("%i  %s", part_table[i].part_number,

There are even more subtle ways octal constants can sneak up on you. Suppose you want to read an integer part from the standard input and then output it, using

   int part_number;
   scanf("%i", part_number);
   printf("Number %i", part_number);

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

   int part_number;
   scanf("%d", part_number);
   printf("Number %d", part_number);

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.