Imperative programming using C
In this document, we describe imperative programming techniques using
the C language.
There are a number of nodes that discuss generalities about
reusable and maintainable code. We recommend you read them in this
order:
- Purpose. Here we describe
what we hope to communicate in this document, which is roughly
to show how to use the C programming language to write reusable
and maintainable code.
- Reusability. Contains a
description of reusability and what parts of the program is
influenced by reusability issues.
- Maintainability.
Contains a description of maintainability and what parts of the
program is influenced by maintainability issues.
- The C programming language.
Discusses features of the C language that are good or bad with
respect to the writing reusable and maintainable code.
- Uniform
reference semantics. We define what we mean by uniform
reference semantics and what consequences it has on
programming.
- Automatic memory
management. Here we discuss the need for automatic memory
management and how that can be obtained for the C programming
language.
- Using advanced
features. Here we argue that there are very few language
constructs that are intrinsically hard to read, and that good
programmers should take advantage of advanced language
features.
Then, there are some nodes that more specifically discuss writing
reusable code. We recommend you read them in this order:
- Separate
interface and implementation. Here we discuss how it is
possible to use the C language to accomplish almost complete
separation between the interface of a module and its
implementation.
Following that, there are some nodes that discuss writing maintainable
code. We recommend you read them in this order:
- Minimizing variable
scope. Here we give hints that will make your programs
more readable through reduced variable scope.
- Naming conventions. Here we discuss
good and bad naming conventions for the identifiers in a
program.
- Normalization. Here we argue
that it is a bad idea to duplicate information, and we also
discuss methods to avoid duplication.
- Exceptional
situations. Here we discuss methods for error handling and
other exceptional situations. We also discuss different types
of exceptional situations.
Finally, there are a number of nodes that discuss specific programming
idioms to use in specific situations. We recommend you read them in
this order:
- Idioms. Here we explain the basics
about programming idioms, why they exist, and why to use them.
- Linked list. Here, we introduce the
idea of a linked list that we then use in many places in other
parts of the document.
- Stack implemented as a linked
list. This is a typical, and perhaps the simplest abstract
data type that uses a linked list for its implementation.
- Unsorted list. This contains
programming idioms for managing unsorted lists of elements.
- Sorted list. Same thing, except
that the elements are sorted.
- Sentinel. We describe a
fundamental programming technique that uses extra invisible
elements called sentinels to simplify the code or
simply to make it faster.
- Queue implemented as a list. We
describe how to implement a queue as a linked list,
first without a sentinel, then with a sentinel.
- Doubly linked list. We
introduce the idea of a doubly linked list that we then use to
implement a number of abstract data types.
- Circular list. We describe a
minor variation on lists, in which the last element is linked
to the first.
- Double-ended queue implemented as a
doubly linked list. We describe how to implement a
double-ended queue as a doubly linked list, first
without sentinels, then with two sentinels, and finally with
one sentinel.
- Buffer. We introduce the concept of a
buffer that we then use to implement a number of
abstract data types.
- Dqueue with buffer. We show
how to implement a double-ended queue using a buffer.
- Stack and queue with
buffer. We show how to implement a stack and a queue using
a buffer indirectly through the use of a double-ended
queue.
There is also a glossary.