https://learnxinyminutes.com/docs/c/
http://pubs.opengroup.org/onlinepubs/9699919799/
http://www.cprogramming.com/tutorial/
Ctrl + L = Clear screen
Get return value in the terminal
echo $?
Simple program
File: hello.c
#include <stdio.h>
int main(void){
printf("Hi!");
}
Run the program in terminal:
make hello
./hello
Run the program in Eclipse:
Right click on the project > Build Project
Right click on the project > Run
CLANG
- preprocesor (#include, #define)
clang -E hello.c
orclang -E hello.c > hello.c
File .i - compiler
clang -S hello.c
Compiles to assembly code File .s - assembler
clang -c hello.s
assembly code to machine code (object code) File .o - linker Combines object files into one file
clang hello.c -l[lib]
eg.clang hello.c -lm
File a.out
Libraries
All header files are in /usr/include eg. less /usr/include/stdio.h
#include <stdio.h>
#include<string.h>
#include <math.h>
// if header file is in the same directory
#include "mylib.h"
.c is implementation file
.c + .h -> .o
int x = 7;
int *y = &x;
// * is pointer and & is the address
(*y)++; // reference y and increment
Precedence
- inner parentheses
- i++, I–
- *x, &x ++i, –i
-
- / %
-
- –
Variables
Data types: char, double, float, int, long long, _Bool …
32 bits (2^31 -1 values)
printf displays float or double rounded to six decimal places by default.
int x; // declaration
x = 7; // assignment
int x, y;
int number = 7; // initialization
unsigned int x = 88U; // holds only positive numbers
printf("%i\n", x); // 88
printf("%3i\n", x); // 88 takes 3 spaces and is right aligned
// char
char z = 'a';
// character strings need to use double quotes "..." !
// Whenever a character constant or variable is used in an expression in C, it is automatically converted to, and subsequently treated as, an integer value.
c >= 'a' && c <= 'z'
c >= 97 && c <= 122
// octal
int octaly = 0171;
printf("%o\n", octaly); //171
printf("%#o\n", octaly); // 0171 - with leading zero
//hex
int hexy = 0xffffff;
printf("%x\n", hexy); // ffffff
printf("%#x\n", hexy); //0xffffff
// contant
const double pi = 3.14;
External variables
External variable can be accessed and changed by another module. Inside the module that wants to access the external variable, the variable is declared and the keyword extern
is placed before the declaration.
// variable defined in one module
int theNumber;
// variable imported in another module
extern int theNumber;
Remember that a variable defined outside a function is not only global variable, but also external.
Static variables
Static variables are accessible only withing the module where they are defined.
static int isBig = 0;
When a function is defined, it can be declared as extern (the default) or static.
static double squareRoot( double x) {... }
Bool
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
// default implementation
_Bool start = true;
printf("%i\n", start); // 1
// stdbool.h - The macro bool expands bool, true and false to _Bool.
bool x = true;
printf("%i\n", x); // 1
}
Type casting: (int), (float)
float num = (float) 2/10;
printf("%f\n", num); // 0.200000
Conditionals
If
Use boolean operators to check multiple conditions
&& and
|| or
! not
if (s != NULL) {}
if (n > 0)
{
printf("You picked a positive number!\n");
}
else if (n == 0)
{
printf("You picked zero!\n");
}
else
{
printf("You picked a negative number!\n");
}
Ternary operator
int x = (expression) ? 5 : 6;
string s1 = (bottles ==1) _ "bottle" : "bottles";
Switch
switch (n)
{
case 1:
case 2:
case 3:
printf("You picked a small number.\n");
break;
case 4:
case 5:
case 6:
printf("You picked a medium number.\n");
break;
case 7:
case 8:
case 9:
case 10:
printf("You picked a big number.\n");
break;
Loops
For
for (int i = 0; i < strlen(s); i++)
{
printf("%c\n", s[i]);
}
While
while(1>0)
{
// code add break; to break out of the code
}
Do while
do
{
printf("height: ");
height = GetInt();
}
while (height < 0 || height > 23);
Functions
Example
void cough (int n)
{
for(int i = 0; i < n ; i++)
{
printf("Cough\n");
}
}
int is_positive (int n)
{
if (n > 0)
{
return 1;
}
else
{
return 0;
}
}
Function declaration – tells compiler that the function exists before it is used in main. Function can also be moved at the top, but it’s a best practice to use prototypes.
void say(string word, int n);
Function definition
void say(string word, int n)
{
printf("Hey!");
}
Initialize multiple variables
for (int i = 0, n = strlen(s); i < n; i++) {}
Command Line Arguments
argc – argument count – integer
argv – argument vector – array of strings
void main (int argc, string argv[]){
}
Recursive function
It must have:
– base case which when triggered will terminate the recursive process
– recursive case which is where the recursion will actually occur
/**
* Returns sum of 1 through m; returns 0 if m is not positive.
*/
int sigma(int m)
{
// base case
if (m <= 0)
return 0;
// recursive case
else
return (m + sigma(m - 1));
}
// FACTORIAL
int fact(int n)
{
// base case
if (n == 1)
return 1;
// recursive case
else
return(n * fact(n-1));
}
// FIBONACCI
int Fibonacci(int n)
{
if ( n == 0 )
return 0;
else if ( n == 1 )
return 1;
else
return ( Fibonacci(n-1) + Fibonacci(n-2) );
}
Multiple recursive cases The Collatz conjecture
int Collatz(int n)
{
if ( n == 1 )
{
return 0;
}
else if ((n % 2) == 0)
{
return 1 + Collatz(n / 2);
}
else
{
return 1 + Collatz(3 * n + 1);
}
}
Why refursive functions work?
When we call a function, the system sets aside space in memory for that function to do its work – we call these chunks of memory stack frames or function frames.
More than one function;s stack frame may exist in memory at a given time. If main() calls move(), which then calls direction(), all three functions have open frames.
These frames are arranged in a stack. The frame for the most recently called function is always on top of the stack.
When a new function is called a new frame is pushed onto the top of the stack and becomes the active frame.
When a function finishes its work, its frame is popped off the stack and the frame immediately below it becomes the new, active, function on the top of the stack.This function pocks up immediately where it left off.
Example:
fact(1)
fact(2)
fact(3)
fact(4)
fact(5)
main()
Stack frames
String
In memory we separate strings with \0.
A character string that contains no characters other than the null character is called the null string.
char buffer[100] = “”;
backlash character a string can span over multiple lines
char letters[] = { “abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ” };
char letters[] = “abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”;
char letters[] =
{ “abcdefghijklmnopqrstuvwxyz”
“ABCDEFGHIJKLMNOPQRSTUVWXYZ” };
Access a character
char c = 'a'; // character
c[0]
printf("%c\n", c[0]);
Create a string
char* s = "foo"; // string
printf("%c\n", s[0]); // f
#include <string.h>
#include <ctype.h> // islower, toupper
More info on a function
man toupper
for (int i = 65; i<65+26; i++){
printf("%c is %i\n", (char) i, i);
}
printf ("Programming in C is fun\n");
printf ("Programming" " in C is fun\n");
printf ("Programming" " in C" " is fun\n");
%s string
%i integer
%c char
%lld long long
%f float, double
// null string
char buffer[100] = ""; // = \0
printf("%s", buffer);
// array of characters
char word[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char place[] = {'W', 'o', 'r', 'l', 'd', '\0'};
// concatenate
printf("%c\n", word[0]); // H
printf("%c%c\n", word[0], word[1]); // Ho
printf("%c %c\n", word[0], place[0]); // HW
printf("%s %s\n", word, place); // Hello World
char pair[2];
pair[0] = 'a';
pair[1] = 'b';
printf("%c%c\n", pair[0], pair[1]); // ab
// \0 null character signals the end of a string
char me [] = {'\0'};
me[0] = 'a';
printf("%c\n", me[0]);
// char array with \0 at the end
// all examples are the same
char show[] = { "Hello!" }; // saves \0 automatically
char shaw[7] = { "Hello!" }; // leave one space for \0!
char hide[] = { 'H', 'e', 'l', 'l', 'o', '!', '\0' };
char mute[] = "Hello!"; // braces are not needed
printf("%i\n", show[6]); // int of null character = 0
// %s format for character string that is terminated by a null character
printf("%s\n", shaw);
printf("%s\n", hide);
printf("%s\n", mute);
// pointer
char* s = "foo"; // string foo
printf("%c\n", s[0]); // f
// condition for the end of the string
// str1[i] != '\0';
/*
Escape Characters
\a Audible alert
\b Backspace
\f Form feed
\n Newline
\r Carriage return
\t Horizontal tab
\v Vertical tab
\\ Backslash
\" Double quotation mark
\' Single quotation mark
\? Question mark
\nnn Octal character value nnn - nnn is a one- to three-digit octal number \033
\unnnn Universal character name
\Unnnnnnnn Universal character name - \u followed by four hexadecimal numbers
\xnn Hexadecimal character value nn \x1b
*/
printf("\a"); // sound
- strlen to calculate the length of a character string
- strcmp to compare two strings
- strcat to concatenate two strings
- strcpy to copy one string to another
- atoi to convert a string to an integer
- isupper , islower , isalpha , and isdigit to test whether a character is uppercase, lowercase, alphabetic, or a digit
Typecasting
(char) i;
(int) n;
Input
int number;
printf ("What number do you want? ");
scanf ("%i", &number);
printf ("%i\n", number);
Arrays
Can save multiple items of the same data type.
Can be accessed by index. It starts with 0.
Array cant be copied as a whole. Use for loop to loop over all elements.
Passed by reference (Variables are passed by value – copies).
type name[size];
bool truthtable[] = { false, true, true };
bool truthtable[3] = { false, true, true };
bool truthtable[3];
truthtable[0] = false;
truthtable[1] = true;
truthtable[2] = true;
bool battleship[10][10];
int n = 4;
int age[n];
for (int i = 0; i<n; i++){
age[i] = GetInt();
}
Multidimensional array
int M[4][5] = {
{ 10, 5, -3, 17, 82 },
{ 9, 0, 0, 8, -7 },
{ 32, 20, 1, 0, 14 },
{ 0, 0, 8, 7, 6 }
};
Command line arguments
int main (int argc, string argv[]) {
printf("Hello, %s\n", argv[1]);
}
for(int i = 0; i < argc; i++) {}
if (argc == 2){}
Multidimensional array
argv[i][j]
Magic Numbers
C provides a preprocesor directive for creating symbolic constants.
At the time the program is compiled, #define goes through the code and replaces NAME with REPLACEMENT.
Define is like find/replace.
#define NAME REPLACEMNET
#define PI 3.14
#define COURSE "CS50"
#define DECKSIZE 52
Bitwise operators & | ^ ~ << >>
Access individual bits
& Bitwise and
0 & 0 0 False & False False
0 & 1 0 False & True False
1 & 0 0 True & False False
1 & 1 1 True & True True
| Bitwise or
0 | 0 0
0 | 1 1
1 | 0 1
1 | 1 1
^ Exclusive OR XOR
0 ^ 0 0
0 ^ 1 1
1 ^ 0 1
1 ^ 1 0
~ Bitwise Not
0 1
1 0
Leftshift operator
- to make small number bigger
1 << 3 1000
Rightshift operator
101101 >> 3 101
GDB – GNU Debugger
gdb program_name
b [ function name, line number ] (break)
r [ command line arguments ] ** (run)
**n step forward one block of code
s step forward one line of code
l lists ten lines, specify a line l 22, l 22, 25
p [ variable ] **prints out the value of the variable given
**info locals Prints out the values of all local variables
bt (backtrace) shows you what series of function calls have led you to the current point in the program
disable disable all breakpoints
q quits GDB
help
Valgrind
To identify memory leaks instal valgrind
Install
sudo apt-get install valgrind
Usage
valgrind program_name
// or
valgrind ./program_name
Debugging
#ifdef DEBUG
fprintf (stderr, "processed %i arguments\n", argc -1
#endif
Run the file with DEBUG defined
This is equivalent to adding #define DEBUG to the program
gcc -D DEBUG filename.c
Preprocessor
Define
Define statements can appear anywhere in the program, but it is required that a name is defined before it is referenced by the program. Best practice is to define them at the top of the program.
#define DOES NOT END WITH ;
#define NULL 0
while (listPtr != NULL)
#define AND &&
#define OR ||
#define PI 3.141
#define TWO_PI 2.0 * PI
// dealing with array bounds - easier to extend
#define MAX_DATAVALUES = 1000
for (i = 0; i < MAX_DATAVALUES; ++i)
Macros
Usage:
// Example 1
#define IS_LEAP_YEAR(y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0
if (IS_LEAP_YEAR(year))
// resolves to
if ( year % 4 == 0 && year % 100 != 0 || year% 400 == 0)
//Example 2
#define SQUARE(x) x * x
// v can be of type int, double, long!
y = SQUARE (v);
// Example 3
#define SQUARE(x) ( (x) * (x) )
y = SQUARE (v + 1);
// Example 4
// conditional expression
#define MAX(a,b) ( ( (a) > (b)) ? (a) : (b) )
limit = MAX (x + y, minValue);
// Example 5
#define IS_LOWERCASE(x) ( ((x) >= 'a') && ((x) <= 'z') )
// Example 6
#define debugPrintf(...) printf(""DEBUG: " __VA_ARGS__)
debugPrintf("Hello \n");
// outputs
DEBUG: Hello
Operator
If you place a # in front of a parameter in a macro definition, the preprocessor creates a constant string out opf the macro argument when the macro is invoked.
// Example 1
#define str(x) # x
str(testing)
// expands to
"testing"
// Example 2
#define printint(var) printf (# var " = %i \n", var)
Operator
Used in macro definitions to join two tokens together. It is preceeded or followed by the name of a parameter to the macro.
# define printx(n) printf ("%i\n, x ## n)
printx(20);
// is expanded into
printf ("%i\n", x20);
The #include statement
numbers.h
# define PI 3.14
Include header file into program
#include "numbers.h"
To include standard libraries saved in /usr/include/
use `#include <stdio.h>
Compliation
// compile files separately
gcc mod1c mod2.c main.c -o dbtest
cc mod1.o mod2.c main.o -o dbtest
// compile .o file
gcc -c mod2.c
// incremental compilation
gcc -c mod1.c
gcc -c mod2.c
gcc -c main.c
gcc mod1.0 mod2.0 mod3.o -o dbtest // creates executable
Conditional compliation
Conditional compliation is often used tro create one program that can be complied to run on different computer systems. It is also used to switch on or off various statements in the program.
# ifdef
#endif
#else
#ifndef
#if
#elif
#undef
// Example 1
#ifdef UNIX
#define DATADIR "/uxn1/data"
#else
#define DATADIR "\usr\data"
#endif
// compile
gcc -D UNIX program.c
// Example 2
#if OS == 1 /* Mac OS */
#elif OS == 2 /* Windows */
# elif OS == 3 /* linux */
#else
#endif
// Example 3
#if defined (WINDOWS)
#define BOOT_DRIVE "C:/"
#else
#define BOOT_DRIVE "D:/"
#endif
// Example 4
// remove the definition of a particular name
#undef name
Makefile
A file with specification of files and their dependencies. The make program automatically recompiles files only when necessary (based on the modification times). The makefile must be placed int he same folder as the files.
Example #1
SRC = mod1.c mod2.c main.c
OBJ = mod1.0 mod2.o main.o
PROG = dbtest
$ (PROG): $ (OBJ)
gcc $ (OBJ) -o $ (PROG)
$ (OBJ): $ (SRC)
Example #2
all: find generate
find: find.c helpers.c helpers.h
clang -ggdb3 -O0 -std=c11 -Wall -Werror -o find find.c helpers.c -lcs50 -lm
generate: generate.c
clang -ggdb3 -O0 -std=c11 -Wall -Werror -o generate generate.c
clean:
rm -f *.o a.out core find generate
Pointers
We usually pass data by value – making a copy of that data (except in the array).
Pointers enable us to pass the actual variable – memory address.
Each location in memory has an address. Pointers are just addresses.
A pointer’s value is a memory address
Pointer’s type describes the data located at that memory address.
Pointers allow data structures and/or variables to ve shared among functions.
The simplest pointer in C is a NULL pointer. When a pointer is created and no value is set immediatelly, the value should be set to NULL. To check whether a pointer is NULL use equality operator ==.
// set value to NULL if a value is not assigned immediatelly.
int *one;
one = NULL;
// pointer zero points to memory address of k
// extracts the address of an already existing variable
// & address extractor operator
int* zero;
zero = &k;
// points to the address of the first item in the array
int* arr;
arr = &name[0];
Array’s name is itself a pointer to it’s first element.
The main purpose of a pointer is to allow us to modify or inspect the location to which it points. We do this by dereferencing the pointer. If we have a pointer-to char called pc, then *pc is the data that lives at the memory address stored inside the variable pc.
Used in this context, * is known as the dereference operator. It goes to the reference and accesses the data at that memory location, alowing you to manipulate it at will.
If you dereference pointer NULL -> Segmentation fault. Which is good. If it wouldn’t be referenced to NULL it could return some value from the memory.
// value of p is an address
// we can dereference p with the * operator
// if we do we will find at that location an integer
int* p;
// * are important part of both type name and the variable name
// pointer to an integer pz and two variables px, and pz
int* px, py, pz
int* pa, *pb, *pc;
Pointer variables are declared by using the * operator
Pointer variables are used with or without the * operator
Without * the a pointer variable represents a memory location.
With * , the variable represents the value of that location.
A string (char* ) is a pointer to the address of the first character.
Strings and arrays don’t need & to reference memory address.
Allocate memory
malloc(size_in_bytes) – memory allocation
// MALLOC
// statically
int xx;
// dinamically
int *px = malloc(sizeof(int));
// array of dloats on the stack
float stack_array[10];
// array of floats on the heap
float *heap_array = malloc(10 * sizeof(float));
// array in C is a pointer to its first element!
// make sure memory leaks are dealt with free()
// a pointer to allocated space
char* t = malloc((strlen(s) +1) * sizeof(char)); // length of a string + 1 for \0 * size of char data type
// free allocated space when memory is allocated with malloc, calloc, ralloc to prevent memory leaks
// takes a pointer to block of memory on the heap and frees it for future use
free(t);
Three golden rules:
– Every block of memory that you malloc() must subsequentyl be free()d
– only memory that you malloc() should be free()d
– Do not free() a block of memory more than once
Structs
We usually define structures in separate .h file or atop the program outside of any functions.
// EXAMPLE 1
// FILE structs.h
typedef struct
{
string name;
string dorm;
}
student; // name of the struct
// FILE struct.c
#include "structs.h"
student students[3]
// ... for loop
students[i].name = GetString();
students[i].dorm = GetString();
// EXAMPLE 2a
struct car
{
int year;
char model[10];
char plate[7];
double engine_size;
int height;
};
// dot operator
// variable declaration
struct car mycar;
// access fields
mycar.year = 2011;
mycar. plate = "CS 50";
mycar.height = 200;
// EXAMPLE 2b
// dinamically allocate structures
// variable declaration
struct car *mycar = malloc(sizeof(struct car));
// dereference
(*mycar).year = 2001;
(*mycar).plate = "CS 30";
// EXAMPLE 2c ->
// -> arrow operator: first it dereferences the pointer on the left side of the operator
// and then accesses the field on the right side of operator
mycar->year = 2011;
mycar->plate = "CS50";
Defining custom data types
First define a type in a normal way and then alias it to something else.
// DATA TYPES
typedef <old name> <new name>
typedef unsigned char byte;
typedef char* string;
// STRUCTURE
struct car
{
int year;
char model[10];
char plate[7];
double engine_size;
int height;
};
typedef struct car car_t;
// STRUCTURE all included
typedef struct car
{
int year;
char model[10];
char plate[7];
double engine_size;
int height;
}
car_t;
// create variable
car_t mycar;
File
Save to file
FILE* file = fopen("students.csv", "w");
if(file != NULL)
{
// ... for loop
fprintf (file, "%s, %s \n", students[i].name, students[i].dorm);
}
fclose(file);
Swap without temp
void swap(int a, int b)
{
a = a^b; // ^ is XOR
b = a^b;
a = a^b;
}