View on GitHub

CCheatSheet

Basics of the tremendously ubiquitous C language that permeates most of computing!

Easily Making CheatSheets with Org-mode

Basics of the tremendously ubiquitous C language that permeates most of computing!

The listing sheet, as PDF, can be found here, while below is an unruly html rendition.

This reference sheet is built around the system https://github.com/alhassy/CheatSheet.

Table of Contents

  1. Adminstriva
  2. Conditionals & Assertion-Based Testing
  3. Assignments
  4. Loops
  5. Arithmetic and Logic
  6. Floats & Other Types
  7. Forming Numbers using Octal & Hexadecimal
  8. The Preprocessor
  9. Pointers
    1. Pointer initialisation
  10. Arrays and Strings and Things
    1. Strings, Arrays, and Pointers
  11. Input –getting things into the machine

Adminstriva

Conditionals & Assertion-Based Testing

In C, true ≈ non-zero. Form of the conditional: \vspace{-0.5em}

if (condition)
  statementBlock
// The rest is optional.
else
  statementBlock

\vspace{-0.5em}

assert(e) does nothing when expression e is true; otherwise it gives a message showing the filename, function name, line number, and the condition e that failed to be true.

#include <stdio.h>

// Disable assertions at compile time by enabling NODEBUG.
// #define NDEBUG

#include <assert.h>
// assert(n)  ≈  if (n) {} else ⟪Terminate and display error message⟫

int sum(int n)
{
  int total = 0, i = 0;
  while (i != n + 1)
    total += i, i++;

  return total;
}

int main ()
{
  // print-based testing
  if (1) printf("here"); else printf("there");
  printf("Sum of 0 + 1 + ⋯ + 99 + 100 = %d", sum(100));

  // assertion-based testing
  assert( sum(100) == 5050 );
  assert( (1 ? "here" : "there") == "here" );

  // Is completely ignored if the #define is enabled.
  // assert(0);  // Otherwise, this causes a crash.

  return 0;
}

hereSum of 0 + 1 + ⋯ + 99 + 100 = 5050

\vspace{-0.5em} Enforce a particular precedence order by enclosing expressions in parentheses.

== equals          != differs from     !  not
>= at least        <= at most          && and
>  greater than    <  less than        || or

Assignments

/* Abbreviations */
  x ⊕= y   ≈  x = x ⊕ y
  x++       ≈  x += 1
  --x      ≈  x -= 1

The increment and decrement, ++/--, operators may precede or follow a name:

Avoid using these in complex expressions, unless you know what you’re doing.

Loops

Here’s the general form.

while (condition)
  statementBlock

/* Abbreviations */
/* for      loop */   for(A; B; C;) S  ≈  A; while(B) S
/* do-while loop */   do S while B     ≈  S; while(B) S

do/while: The conditional is evaluated after the statement has been executed and so the statement is obeyed at least once, regardless of the truth or falsity of the condition. This is useful for do once, and possible more operations.

int i = 0;
do printf("%d \n", i++);
while (i != 10); //Note the ending semicolon.

Arithmetic and Logic

…and then the different branches of arithmetic —Ambition, Distraction, Uglification, and Derision.

—Alice’s Adventures in Wonderland

The modulus operator % gives the remainder of a division.

printf("rem = 10 %% 3 = %d  ⇒  ∃ quot •  10 = 3 × quot + rem  ∧  quot = %d", 10 % 3, 10 / 3);

rem = 10 % 3 = 1  ⇒  ∃ quot •  10 = 3 × quot + rem  ∧  quot = 3

When x is a number, the shift operations correspond to multiplication and division by 2ⁿ, respectively.

Left Shift `x << n` append the bit representation of `x` with `n`-many 0s
Right Shift `x >> n` throw away `n` bits from the end of the bit representation of `x`

The bitwise operators and &, or |, not !, and xor ^ operate at the bit representation of an item. For example, the ASCII code of a character consists of 7 bits where

Bit Function
7 0 digit, 1 letter
6 0 upper case, 1 digit or lower case
5 0 for a-o, 1 for digit or p-z

Whence, to convert a character to uppercase it suffices to change bit 5 to be a 0 and leave the other bits alone. That is, to perform a bitwise and with the binary number 11011111, which corresponds to the decimal number 223.

// Mask, or hide, bit  6 to be a ‘1’.
#define toLower(c) (c | (1 << 6))

#define toUpper(c) (c & 223)

#define times10(x) ( (x << 1)  +  (x << 3)) // Parens matter!
// x  ⇒  2·x + 8·x  ⇒  10 · x

How did we know is was 223?

0. Ninth bit is on `100000000` `1 << 8`
1. Negate it: Eight ones `11111111` `~(1 << 8)`
2. Sixth bit is on `100000` `1 << 5`
3. Xor them `11011111` `⋯ ^ ⋯`
4. See it as a decimal `223`  

Ironically, C has no primitive binary printing utility.

Floats & Other Types

Type aliases: typedef existingType newName;

// A named product: String × ℤ × ℝ   having names  name, age, height.
struct entry
{
  char   name[30];
  short  age;
  float  height;
}; // Note that this is a statement

// Alias for readability.
typedef   struct entry   Person;

int main()
{                                            // Exponent form for numbers.
  struct entry qasim = {"qasim", 0, 613e-2}; // 613e-2 ⇒ 613 × 10⁻² ⇒ 6.13
  Person q = qasim;
  q.age = 23;

  printf("Hello! My name is %s and I'm %d years old, being %f ft tall",
     q.name, q.age, q.height);
  return 0;
}
Hello! My name is qasim and I'm 23 years old being 6.130000 ft tall

Forming Numbers using Octal & Hexadecimal

Numbers that begin with a 0 are interpreted as octal and those beginning with 0x or 0X are hexadecimal. These forms are obtained from binary by grouping using 3 bits and 4 bits, respectively. E.g., 129 ≈ 0201 ≈ 0x81 since:

Indeed:

int x = 129, y = 0201, z = 0x81, zz = 0X81, b = (x == y) && (x == zz);
printf("%d ≈ %d ≈ %d; %d", x, y, z, b);

129 ≈ 129 ≈ 129; 1

The Preprocessor

The preprocessor performs alterations to a program before it is compiled; e.g., the following ensures the replacement of every occurrence of this(⋯, ⋯) after it with whatever that is.

#define this(arg1, arg2)  that

Pointers

Variables may be used without having values declared! This is akin to buying the land —computer memory— but not building the house —assigning a value— thereby leaving us with a vacant lot that contains trees, garbage, and whatever was there before you get there —as is the case in C.

char c;
int i;
long x;
float f;
double d;

// Uninitalised ⇒ have random values.

printf("char   %c\n",c);
printf("int    %i\n",i);
printf("long   %l\n",x);
printf("float  %f\n",f);
printf("double %d\n",d);

#RESULTS:

char  
int 32766
long  
float 0.0
double 73896

Rather than being set to 0, variables automatically obtain the random values in memory and one should always initialise variables upon declaration.

  1. Here’s some useful conversion laws

    • *&-inverses: p = &x ≡ *p = x
      • The lhs lives in the land of addresses and locations, whereas the rhs lives in the land of values.
    • []&-array: arr + i = &arr[i]

    From these we obtain:

    • []*-array: *(arr + i) = arr[i] —immediate from the above two laws.
    • *-array: *arr = arr[0] —immediate from the above two laws.
    • ***-array:** **arr = arr[0][0] —the previous law iterated twice.

Tips:

✓ Pointers must be declared with the asterisk
✓ When a pointer is used without its asterisk, it refers to a memory location
✓ When a pointer is used with its asterisk, it indirectly refers to a value
✓ To assign a pointer a memory location, prefix the other variable with &
✓ Pointers are memory addresses and can be displayed as unsigned integers using `%u`

Pointer initialisation

int a[30], *p;

// Make p point to the beginning of the array a, since a is itself a pointer to the
// beginning of the array.
p = a;

// Determine the actual machine address of a variable by predicing it with &.
int fred;
p = &fred;

// If we need to know exactly where in the machine C had decidede to allocate space
// to fred, we need only to print out p; whence & is read “address of”.
printf("%p", p);

0x7ffee36348ac

Since the name of an array is itself a pointer to the beginning of an array, we have

arr ≈ &arr[0]
// Find furthest points of ‘int a[N-1]’ that are identical.
#define N 12
int a[] = {9,8,1,2,3,4,4,3,2,1,7,6};

int * p = a, *q = &a[N-1];
while(*p != *q) p++, q--;

assert(*p == a[2] && *q == a[9]);

Before C99, function return types could be omitted with the understanding that the default is int. However, main still needs its return type. The following works with many warnings.

f() {return 9; }
g() {return 'c'; } // Remember that chars are actually numbers.

int main() { printf("%d", f() + g()); return 0; }

108

Arrays and Strings and Things

Strings, Arrays, and Pointers

We can now rewrite the length function with even less square brackets.

int length(char* c)
{
  char* start = c;
  while( *c ) c++; // Local copy of c is affected.
  return c - start;
}

assert(length("hello world") == 11);

Input –getting things into the machine

Let’s extend getchar to work on buffers of length, say, 20:

#include <stdio.h>

#define BUFFER_LENGTH 10

int main()
{
  printf("Please enter a string, only first %d chars or newline will be read: \n\t\t",
         BUFFER_LENGTH);
  char cs[BUFFER_LENGTH];
  int keep_reading = 1;
  char * p = cs;
  while(keep_reading && p < cs + BUFFER_LENGTH)
    {*p = getchar(); if (*p == '\n') keep_reading = 0; else p++;}

  *p = '\0'; // Strings are a null-terminated arrays of chars.

  printf("\nYou entered: %s", cs);
  printf("\nBye\n");

  return 0;
}