Menu

C basics

November 4, 2016 - C

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

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

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

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

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;
}

Tags: , ,