Tools

  • indent (format code)
  • gcc / clang (compile code)
  • man <function> (see function documentation)
  • tldr <command> (quick command usage examples)
  • valgrind (Look for memory leaks)
  • valgrind —tool=massif (check a program’s RAM usage)
    • View the output with Massif-Visualizer
  • gdb (debugger)
    • gdb —args <program> (if the program has command line args)
    • Type run to start debugging, and backtrace for error details.
  • file Check file information and, if it is an executable, compilation details.
  • perf stat -r 10 -d <program> Benchmark a program.

Data Types and Variables

The binary length of each data type depends on the CPU, OS, and compiler, but in general, they follow the C specifications. To check the exact values for your platform, see limits.h.

TypeC SPECx64 Linux (Example)
char≥ 8 bits8 bits
short≥ 16 bits16 bits
int≥ 16 bits32 bits
long≥ 32 bits64 bits
long long≥ 64 bits64 bits
float32 bits
double64 bits
long double128 bits
Unsigned Bytes (8 bits)Maximum Decimal Value
1255
265.535
44.294.967.295
818.446.744.073.709.551.615
16340.282.366.920.938.463.463.374.607.431.768.211.455
321.157 × 10^76

Examples

char a = 'C';      // single character    %c ''
char b[] = "Trude" // array of characters %s ""
unsigned int // Unsigned. The number must be positive.
int          // Signed. Negative and positive numbers.
char f = 100;                 // %d (number) %c (character)
unsigned char g = 255;        // %d (number) %c (character)
short h = 32767;              // %d
unsigned short i = 65535;     // %d
int j = 2147483647;           // %d
unsigned int k = 4294967295;  // %u
long long l = ...             // %lld
unsigned long long m = ...32U // %llu
float c = 3.141592;           // %f
double d = 3.141592653589793; // %lf

Format Specifiers

These format codes indicate which data type is being used. They are needed for printf and scanf, for example.

%Description
%%%
%-left align
%.1decimal precision
%1minimum field width
%ccharacter
%dsigned integer of base 10
%escientific notation
%ffloat
%hdsmall decimal (short)
%hhdvery small decimal (char)
%iinteger of any base (detects automatically)
%lfdouble
%ooctal (base 8)
%paddress/pointer
%sstring (array of characters)
%uunsigned integer of base 10
%xhexadecimal (base 16)
float item1 = 5.75;
printf("Item1: %-8.2\n", item1);

Numbers

C can handle multiple numeric bases.

int x = 255;  // Decimal
int y = 0xff; // Hexadecimal

Type Casting

Convert a type into another.

int x = 1, y = 10;
float z = (float) x / (float) y;

Escape Sequences

Escape sequences are used to allow typing characters in a string that would otherwise be interpreted as C instructions.

SeqNameDescription
\aAlarm or BeepIt is used to generate a bell sound in the C program.
\bBackspaceIt is used to move the cursor one place backward.
\fForm FeedIt is used to move the cursor to the start of the next logical page.
\nNew LineIt moves the cursor to the start of the next line.
\rCarriage ReturnIt moves the cursor to the start of the current line.
\tHorizontal TabIt inserts some whitespace to the left of the cursor and moves the cursor accordingly.
\vVertical TabIt is used to insert vertical space.
\\BacklashUse to insert backslash character.
\'Single QuoteIt is used to display a single quotation mark.
\"Double QuoteIt is used to display double quotation marks.
\?Question MarkIt is used to display a question mark.
\oooOctal NumberIt is used to represent an octal number.
\xhhHexadecimal NumberIt represents the hexadecimal number.
\0NULLIt represents the NULL character.
\eEscape sequenceIt represents the ASCII escape character.
\sSpace CharacterIt represents the ASCII space character.
\dDelete CharacterIt represents the ASCII DEL character.

Constants

Add const before a variable declaration to prevent the value from being changed.

const float PI 3.14159;

Another option is to use define.

#define MAX 9

This command replaces the ‘MAX’ word with ‘9’, using the preprocessor (before compiling). No extra memory required.

Arithmetic Operators

// +  (addition)
// -  (subtraction)
// *  (multiplication)
// /  (division)
// %  (modulus / remainder)
// ++ (increment)
// -- (decrement)
int x = 1;
int y = 2;
int z = x + y; // 3
// Augmented assignment operators
x++; // x = x + 1
y--; // y = y - 1
x+=2; // x = x + 2
x*=2; // x = x * 2

Control Flow

Boolean Values

In C, there are no true or false keywords, so integers are used instead.

  • 0 generally represents false.
  • Any non-zero value (1, -1, etc…) represents true.

IF Statement

if(a == 1) printf("A is 1.\\n");

Use {} for multiple items.

if(age == 18){
	printf("You are 18.");
}
else if(age < 0){
	printf("You haven't been born yet.");
}
else{
	printf("You are not 18.");
}

Switch Statement

Faster than IF when over 5 cases.

switch(grade){
	case 'A':
		printf("perfect.\n");
		break;
	case 'B':
		printf("good.\n");
		break;
	case 'C':
		printf("okay.\n");
		break;
	case 'D':
		printf("meh.\n");
		break;
	case 'F':
		printf("failed.\n");
		break;
	default:
		printf("Enter only valied grades.\n");
}
// If break; is missing, the next case is also executed.

Operators

Logical Operators

AND (&&)

if(temp >= 0 && temp <= 30){
	printf("\nThe weather is good.")
}

OR (||)

if(temp <= 0 || temp >= 30){
	printf("\nThe weather is good.")
}

NOT (!)

if(!(temp <= 0 || temp >= 30)){
	printf("\nThe weather is bad.")
}
NOT Truth Table
condition!(condition)
10
01

Ternary Operator

Shorthand syntax for if/else when assigning or returning a value.

// (condition) ? value if true : value if false
int max = (x > y) ? x : y;

Bitwise Operators

Special operators used in bit-level programming. (Logic gates)

int x = 6;  // 6  = 00000110
int y = 12; // 12 = 00001100
int z = 0;  // 0  = 00000000
z = x & y;  // AND         - 00000100 (4)
z = x | y;  // OR          - 00001110 (14)
z = x ^ y;  // XOR         - 00001010 (10)
z = x << 1; // Left Shift  - 00001100 (12) (Shift all bits to the left.)
z = x >> 1; // Right Shift - 00000011 (3)  (Shift all bits to the right.)

Functions

Functions are snippets of code that can be reused multiple times across the same file. These can receive multiple arguments as input, but can only return a single value.

void myFunction(); // Function Prototype
int main() {
	myFunction(); // Call function
	return 0;
}
void myFunction() { // Function Definition
	//...
}

Arguments

void greet(char x[], int y);
int main() {
	char name[] = "Trude";
	int age = 132;
	greet(name, age);
}
void greet(char x[], int y) {
	printf("\nHello %s, you are %d years old.", x, y);
}

Return Values

double square(double x);
int main() {
	double x = square(3.14);
	printf("%lf", x);
	return 0;
}
double square(double x) {
	return x * x;
}

Recursion

A function can call itself, creating a loop.

int i = 0;
void plusOne(int n) {
	printf("%d", n);
	if (n < 10000) plusOne(n);
}

Function Prototypes

Function declaration without a body, before main().
Prototypes ensure that calls to a function are made with the correct arguments, and allow functions to be defined under the function call.

void hello(char[], int); // Function Prototype
int main() {
	hello(//...);
	return 0;
}
void hello(char name[], int age){
	//...
}

Note: Many C compilers don’t check for parameter matching, so missing arguments can lead to unexpected behavior.

Function prototypes flag errors when arguments are missing.

While not necessary if functions are declared before main(), using prototypes first and then declaring functions after main() improves readability and aids debugging.

Loops

For Loop

Loop through an interval.

for(int i = 0; i < 10; i++){
	printf("%d\n", I); //0-9
}
//Multiple initial variables
for(int i = 0, int y = 1; i < 10; i++){
	printf("%d\n", I); //0-9
}

While Loop

Loop until a condition is met.

while(test == 1){
	printf("Test is not 1.\n");
}

Do While Loop

Run the code once, then repeat until a condition is met.

do {
	printf("Enter a number above 0: ");
	scanf("%d", &number)
} while (number > 0);

Endless Loop

while (true) {
	...
}

Continue & Break Statements

  • continue - Skips rest of code and forces the next iteration of the loop.
  • break - Exits a loop/switch.

Structs

Structs can group values. They are similar to classes, but can’t hold methods.
Being able to group variables avoids repetition and name collision (when two variables have the same name).

struct Player {
	char name[12];
	int score;
};
int main(){
	struct Player player1;
	struct Player player2;
	strcpy(player1.name, "Trude");
	player1.score = 4;
	strcpy(player2.name, "JCionx");
	player2.score = 7;
	player1.score; //4
}

Arrays of Structs

struct Student {
	char name[12];
	float gpa;
};
int main() {
	struct Student s1 = {"Peter", 3.0};
	struct Student s2 = {"Jean", 4.0};
	struct Student s3 = {"David", 2.5};
	struct Student students[] = {s1, s2, s3};
	printf("%f\n", students[0].gpa); // Print the student 1 gpa.
	return 0;
}

Typedef

Create a shortcut for a type of data.

typedef char user[25];
int main() {
	user user1 = "Trude";
}

Typedef can be used to simplify structs.

typedef struct {
	char name[25];
	char password[12];
	int id;
} User;
int main(){
	User user1 = {"Trude", "hello123", 12335};
}

Nul Character

\0 // This character represents 00000000 and marks the end of a string.
// Same as 0x0 and null.

Command-Line Arguments

  • argc is the number of arguments in argv.
  • argv[0] is the name of the program, all others are the user arguments.
int main(int argc, char argv[]) {
	if (argc == 2) {
		printf("hello, %s\n", argv[1]);
	} else {
		printf("You need to add 1 argument.\n");
		return 1;
	}
	return 0;
}

Enums

Enums are a list of constant values that help make programs more readable.
Enums are treated as integers.

// enum Day{Sun, Mon, Tue, Wed, Thu, Fri, Sat}; (This enum starts from 0 to 6.)
enum Day{Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7};
int main(){
	enum Day today = Sun;
	if(today == Sun || today == Sat){
		printf("It's the weekend.");
	}
}

Memory Management

  • a - A variable
  • &a - The address of the variable a in memory. (The format is %p)
  • int *p - A pointer. Holds the memory address of another variable. (8 bits usually, depends on the CPU architecture (max RAM supported).
  • *p - Dereference a pointer. Returns the value in the address stored. (go to address’s variable)
int age = 21;
int *pAge = &age;
int valueOfAge = *pAge;
printf("%p and %p are the same.", &age, pAge);

NOTE: A pointer must be int, as it points to a memory address.

Strings

Strings are arrays of characters.
A string can be returned as a memory address.
A string ends in \0, the null character.

/* Use char[] when:
		- The maximum string length is known.
		- No need to modify the whole string.
		- No need to pass the string to a function [that modifies it]
*/
char name[] = "Trude"; // 6 bits on stack memory.
name[0] = 'T'; // Elements of an array can be modified.
/* Use char* when:
		- The maximum string length is NOT known.
		- The string will later be modified.
		- The string will be passed to a function [that modifies it].
*/
const char *name = "Trude"; // 8 bits in stack + 6 bits read-only.
name = "TrudeEH"; // Pointers can be overwritten.
name++; // rudeEH - Works because the pointer is shifted to the next value.
peintf("%c\n", *(name+1)); // Prints 'r'.
printf("%c\n", name[1]); // Works with both for reading.
printf("%s\n", name);    // Print a string.
// The string in memory:
// [T][r][u][d][e][\\0]
// The memory address of T is stored.

String Operations

Compare String

#include <stdio.h>
#include <string.h>
char s* = "Trude";
char t* = "Trude";
if (strcmp(s, t) == 0) {
	printf("Same string.");
}

Copy String (malloc example) Manually

#include <stdlib.h>
char *s = "Trude";
char *t = malloc(strlen(s) + 1);
// 2 variables are declared, so strlen isn't called with every iteration.
for (int i = 0, n = strlen(s) + 1; i < n; i++) {
	t[i] = s[i];
)
//...
free(t);

Copy String (string.h)

#include <stdlib.h>
#include <string.h>
char *s = "Trude";
char *t = malloc(strlen(s) + 1);
strcpy(t, s);
//...
free(t);

Note: Use valgrind to detect memory leaks (lack of free())

Always initialize variables to a value, or random garbage values may be still in the variable’s memory address.

Input

Get Integer

#include <stdio.h>
int main(void){
	int x;
	scanf("%i", &x);
}

Get String (Length is Known, safe)

scanf reads up to a whitespace.

#include <stdio.h>
int main(void){
	char s[4];
	scanf("%4s", s);  //No &, s is an address already.
}

fgets reads whitespaces.

#include <stdio.h>
#include <string.h>
int age;
char name[25];
printf("What is your name? ");
fgets(name, 25, stdin); // name of variable, max size, input.
name[strlen(name)-1] = '\0'; // removes the line break fgets adds. String library is required.
printf("How old are you? ");
scanf("%d", &age);

Files

Write to a File

#include <stdio.h>
int main() {
	FILE *file = fopen("test.txt", "w"); // w - overwrite / a - append
	fprintf(file, "Some Text");
	fclose(file);
	return 0;
}

Delete a File

#include <stdio.h>
int main() {
	if(remove("test.txt") == 0){
		printf("File removed.\n");
	} else {
		printf("Failed to delete file.\n");
	}
	return 0;
}

Read a File

#include <stdio.h>
int main() {
	FILE *pF = fopen("test.txt", "r") // r - read.
	char buffer[255]; // Will hold 1 line of the file.
	if(pF == NULL){
		printf("File does not exist.");
		return 1;
	}
	fgets(buffer, 255, pF);
	printf("%s", buffer); // Print first line of file. Use in a while loop to print all of them.
	fclose(pF);
	return 0;
}

File manipulation accepts relative and absolute file paths.