DEV Community

Kevin Albertson
Kevin Albertson

Posted on • Updated on

Things learned from K&R C

#c

Pointers

Pointer arithmetic on void * is not allowed since the size of pointed-to data is unknown.

"dangling pointer" == points to a deleted object
"wild pointer" == points to uninitialized uninitialized pointer

Converting from an array to a pointer loses size information

char str[256];
printf ("%zu\n", sizeof str); // 256
char *pstr = str;
printf  ("%zu\n", sizeof pstr); // 4 or 8 (size of pointer). 
Enter fullscreen mode Exit fullscreen mode

Memory management

"static" == allocated at compile time
"automatic" == allocated on the stack
"dynamic" == allocated on the heap

Types of behavior

"implementation-defined" == implementation must document. E.g. propagation of sign bit on >> operation.
"undefined behavior" == no requirements. E.g. signed overflow.
"unspecified behavior" == two or more possible behaviors E.g. order of argument evaluation.
"locale-specific behavior" == depends on local conventions. E.g. whether tolower returns true for characters other than 26 lowercase Latin letters.

The number of bits in a byte is implementation defined.

An assignment is an expression evaluating to the left-hand side. E.g. (c = getchar()) evaluates to c.

extern can be used inside a function definition. E.g.

int x;
void foo() {
    extern int x;
}
Enter fullscreen mode Exit fullscreen mode

External and static variables are initialized to 0.

String literals cannot be modified. E.g.

char *s = "abc";
s[0] = `d`; // not allowed
Enter fullscreen mode Exit fullscreen mode

C89 int division with negative numbers is implementation defined. 7 / -2 can be -3 or -4 (round up or down). C99 defines as -3 (toss the decimal after division).

If fn is called but not declared, the compiler assumes it is defined as int fn().

Arithmetic and comparison of pointers that do not point to the same array is undefined behavior (exception is one past the last element in the array).

You may omit the first dimension of a multi-dimensional array in parameters. E.g. void f(int arr[][13])

argv[argc] is NULL.

sizeof does not require parenthesis for objects. sizeof object vs. sizeof (type name).

C supports bit fields. The order of bits is implementation defined. E.g.

struct {
    unsigned int is_keyword : 1;
    unsigned int is_extern : 1;
    unsigned int is_static : 1;
}
Enter fullscreen mode Exit fullscreen mode

printf format is %[-][<width>][.][<precision>][h|l][<conversion>]. <width> or <precision> may be *.

FILE* is OS independent. File descriptors are Unix specific.

Top comments (2)

Collapse
 
pauljlucas profile image
Paul J. Lucas

A "wild pointer" doesn't necessarily point to uninitialized memory. It's the pointer itself that is uninitialized. As a consequence, it can point to any address in memory. There's a chance it can just so happen to point to an arbitrary address already within your program such as the text segment of even in your current stack frame. Therefore, it could just so happen to point to memory that has already been initialized. If it's not a char*, then it's also likely unaligned. For example, it could point to the second byte of an already initialized 4-byte integer; or it could just by luck be aligned and your program might even appear to work.

Collapse
 
kevinalbs profile image
Kevin Albertson

@pauljlucas good catch. It was incorrectly transcribed from my written notes. The post has been updated.