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)
break;
printf("%i  %s", part_table[i].part_number,
part_table[i].description);
}
}
```

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.

by updated