Commit d2495261 authored by Xavier Besseron's avatar Xavier Besseron
Browse files

Update

parent b98a69e1
#include <stdio.h>
// This program lists the arguments it has been called with.
//
// Examples of usage:
//
// ./01-logic_syntax_bugs
// ./01-logic_syntax_bugs param1
// ./01-logic_syntax_bugs param1 2
// ./01-logic_syntax_bugs param1 2 testParam
//
int main(int argc, char** argv)
{
// number of parameters
int nb_params = argc - 1;
// first print a message
if ( nb_params > 1 )
{
printf("This program was called with %i parameters\n", nb_params);
}
else if ( nb_params == 1 )
{
printf("This program was called with only 1 parameter\n");
}
else
{
printf("This program was called without any parameter\n");
}
// print program name and all parameters
printf("program = '%s'\n", argv[0] );
int i;
for ( i = 0 ; i < nb_params ; i++ )
{
printf("parameter %i = '%s'\n", i, argv[i] );
}
return 0;
}
# Exercise `01-logic_syntax_bugs.c`
## Solution
Compile with the warnings
```
$ gcc -Wall -g 01-logic_syntax_bugs-solution.c -o 01-logic_syntax_bugs
01-logic_syntax_bugs-solution.c: In function 'main':
01-logic_syntax_bugs-solution.c:24:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
else if ( nb_params = 1 )
^
```
The compiler gives a warning about an assignment at line 24.
The code contains a mistake here as comparison should be done here instead of an assignment.
We should replace `=` by `==`.
#include <stdio.h>
#include <stdlib.h>
// This program computes factorial.
//
// Examples of usage:
//
// ./02-integer_overflow 4
// ./02-integer_overflow 10
// ./02-integer_overflow 20
//
long long int factorial(int n)
{
long long int result = 1;
int i;
for ( i = 2 ; i <= n ; i++ )
{
result *= i;
}
return result;
}
int main(int argc, char** argv)
{
// check number of parameters
if ( argc != 2)
{
printf("Error: exactly one parameter is required!\n");
return 1;
}
// get first parameter
int n = atoi(argv[1]);
// cannot calculate factorial correctly above 20
if ( n > 20 )
{
printf("Error: cannot calculate factorial above 20!\n");
return 1;
}
long long int fact = factorial(n);
printf(" fact(%i) = %lli\n", n, fact);
return 0;
}
# Exercise `02-integer_overflow.c`
## Solution
This programs calculate the factorial of the parameter.
Execution with parameter 13 or above returns a wrong value because of an integer overflow.
A `int` variable cannot hold value bigger than 2^31-1.
```
$ ./02-integer_overflow 12
fact(12) = 479001600
$ ./02-integer_overflow 13
fact(13) = 1932053504
```
One solution is to use an integer type that can use larger integer value, for example `long long int`. This allows to calculate factorial correctly up to 20.
```
$ ./02-integer_overflow-solution 20
fact(20) = 2432902008176640000
```
We can also add an error message if the user asks for factorial above 20.
```
$ ./02-integer_overflow-solution 21
Error: cannot calculate factorial above 20!
```
#define _GNU_SOURCE
#include <fenv.h>
#include <stdio.h>
#include <math.h>
// Notes:
//
// Add -lm on the compilation command line to link with the math library
// Add -Ddivbyzero -Dinvalidop or -Doverflow to compile only the relevant part
int main(int argc, char** argv)
{
feenableexcept(FE_DIVBYZERO|FE_INVALID|FE_OVERFLOW);
#ifdef divbyzero
// Division by zero error
double a = 1.0 / 0.0;
printf("Division by zero: 1.0 / 0.0 = %e\n", a);
#endif
#ifdef invalidop
// Invalid operation
double b = sqrt(-1.0);
printf("Invalid operation: sqrt(-1.0) = %e\n", b);
#endif
#ifdef overflow
// Overflow
double c = exp( 1e30 );
printf("Overflow: exp( 1e30 ) = %e\n", c);
#endif
return 0;
}
# Exercise `03-floating-point_exceptions.c`
## Solution
We compile and execute the different type of floating-point exceptions:
```
$ gcc -Wall -g -lm 03-floating-point_exceptions.c -Ddivbyzero -o 03-floating-point_exceptions-divbyzero
$ ./03-floating-point_exceptions-divbyzero
Division by zero: 1.0 / 0.0 = inf
```
```
$ gcc -Wall -g -lm 03-floating-point_exceptions.c -Dinvalidop -o 03-floating-point_exceptions-invalidop
$ ./03-floating-point_exceptions-invalidop
Invalid operation: sqrt(-1.0) = -nan
```
```
$ gcc -Wall -g -lm 03-floating-point_exceptions.c -Doverflow -o 03-floating-point_exceptions-overflow
$ ./03-floating-point_exceptions-overflow
Overflow: exp( 1e30 ) = inf
```
In all the above cases, the program continues its execution without error but shows incorrect value.
In order to identify the origin of the error, we enable the floating-point exception using
```
feenableexcept(FE_DIVBYZERO|FE_INVALID|FE_OVERFLOW);
```
Now, the programs crashes when the error occurs and it is possible to locate where the error occurs with GDB.
#include <stdio.h>
#include <stdlib.h>
// Notes:
//
// Add -Dfailedalloc -Ddoublefree -Dfreenonalloc or -Ddoublealloc to compile only the relevant part
int main(int argc, char** argv)
{
#ifdef failedalloc
short SIZE = 1111;
double *array = malloc( sizeof(double) * -SIZE );
// We need to check the return value of malloc
if ( array == NULL )
{
printf("Error: failed to allocate memory with malloc()\n");
return 1;
}
array[0] = 2.0;
free(array);
#endif
#ifdef doublefree
int *p = malloc( 2 * sizeof(int) );
// We need to check the return value of malloc
if ( p == NULL )
{
printf("Error: failed to allocate memory with malloc()\n");
return 1;
}
free(p);
// p has already been freed
// free(p);
#endif
#ifdef freenonalloc
double d[100];
// d is a static variable not alllocated with malloc()
// free(d);
#endif
#ifdef doublealloc
void *p;
p = malloc( 100 );
// We need to check the return value of malloc
if ( p == NULL )
{
printf("Error: failed to allocate memory with malloc()\n");
return 1;
}
// if we don't free p now, the memory will be lost when p is reassigned
free(p);
p = malloc( 10 );
if ( p == NULL )
{
printf("Error: failed to allocate memory with malloc()\n");
return 1;
}
free(p);
#endif
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// This program will print all its parameters in uppercase
// Convert buffer to uppercase
// This function allocates a buffer that must be freed by the caller
char* uppercase( char* buffer )
{
int size = strlen(buffer);
char* buffer_up = malloc( size+1 );
int i;
for ( i = 0 ; i < size ; i++ )
{
if ( buffer[i] >= 'a' && buffer[i] <= 'z' )
buffer_up[i] = buffer[i] + 'A' - 'a';
else
buffer_up[i] = buffer[i];
}
buffer_up[size] = '\0';
return buffer_up;
}
int main(int argc, char** argv)
{
int i;
for( i = 0 ; i < argc ; i++ )
{
char* up_str = uppercase(argv[i]);
printf("%s ", up_str );
free(up_str);
}
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
// Notes:
//
// Add -Duninitstatic -Duninitdynamic or -Duninitnonalloc to compile only the relevant part
int main(int argc, char** argv)
{
#ifdef uninitstatic
double x,y;
y = 0;
x = y + 2;
printf("x = %f\n",x);
printf("y = %f\n",y);
#endif
#ifdef uninitdynamic
int size = 10;
double *array = malloc( sizeof(double) * size );
array[0] = 42.0;
int i;
for( i = 1 ; i < size ; i++ )
array[i] = array[i-1];
for( i = 0 ; i < size ; i++ )
printf(" array[%i] = %f\n", i, array[i] );
free(array);
#endif
#ifdef uninitnonalloc
int size = 10;
double *array1 = malloc( sizeof(double) * size );
double *array2 = malloc( sizeof(double) * size );
int i;
// initialize array1
for( i = 0 ; i < size ; i++ )
array1[i] = 0.0;
for( i = 0 ; i < size ; i++ )
array2[i] = array1[i];
for( i = 0 ; i < size ; i++ )
printf(" array2[%i] = %f\n", i, array2[i] );
free(array1);
free(array2);
#endif
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int size = 100;
double *fibo = malloc( sizeof(double) * size );
fibo[0] = 1; fibo[1] = 1;
int i;
for( i = 2 ; i < size ; i++ )
{
fibo[i] = fibo[i-1] + fibo[i-2];
}
printf(" fibo = %f\n", fibo[size-1] );
free(fibo);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int fibo(int n)
{
if (n <= 1)
return 1;
else
return fibo(n-1) + fibo(n-2);
}
int main(int argc, char** argv)
{
int n = 10;
int res = fibo(n);
printf("fibo(%d) = %d\n", n, res);
return 0;
}
#include <stdio.h>
#include <string.h>
#define SIZE 10
void print_uppercase(char* str)
{
// buffer to store uppercase string
char str_up[SIZE];
int i = 0;
// firt copy string
// use strncpy() to avoid buffer overflow
strncpy( str_up, str, SIZE-1 );
str_up[SIZE-1] = '\0';
// change lowercase to uppercase
for ( ; i < SIZE ; i++ )
{
if ( str_up[i] >= 'a' && str_up[i] <= 'z' )
str_up[i] = str_up[i] + 'A' - 'a';
}
// print
printf("'%s' -> '%s'\n", str, str_up);
}
int main(int argc, char** argv)
{
print_uppercase("First test");
print_uppercase("This is the second test!");
return 0;
}
#include <stdio.h>
#define SIZE 1024
int main(int argc, char** argv)
{
FILE* file = fopen("/foo.bar", "r");
if ( file == NULL )
{
printf("Error: failed to open file with fopen()\n");
return 1;
}
char buffer[SIZE];
fscanf( file, "%s", buffer );
printf("'%s'\n", buffer);
return 0;
}
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
// Notes:
//
// Add -pthread on the compilation command line to link with the pthread library
#define NB_THREADS 8
#define NB_DEPOSIT 1000000
typedef struct
{
int balance;
pthread_mutex_t mutex;
} Account;
void deposit(Account* account, int amount)
{
pthread_mutex_lock(&(account->mutex));
account->balance += amount;
pthread_mutex_unlock(&(account->mutex));
}
// Use one global account object
Account account;
void *thread_start()
{
// Each thread will call deposit NB_DEPOSIT times
int i;
for ( i = 0 ; i < NB_DEPOSIT ; i++)
{
// Add one pesos to the account
deposit( &account, 1 );
}
pthread_exit(NULL);
}
int main(int argc, char** argv)
{
// Set initial balance to 0
account.balance = 0;
pthread_mutex_init( &account.mutex, NULL );
pthread_t threads[NB_THREADS];
// Create all thread
int i;
for( i = 0 ; i < NB_THREADS ; i++ )
{
int res = pthread_create( &threads[i], NULL, thread_start, NULL );
if (res)
{
printf("Error: pthread_create() failed with error code %d\n", res);
exit(-1);
}
}
// Wait for all the threads to finish
for( i = 0 ; i < NB_THREADS ; i++ )
{
int res = pthread_join(threads[i], NULL);
if (res)
{
printf("Error: pthread_join() failed with error code %d\n", res);
exit(-1);
}
}
printf("Final balance is %d\n", account.balance );
pthread_mutex_destroy(&account.mutex);
pthread_exit(NULL);
return 0;
}
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
// Notes:
//
// Add -pthread on the compilation command line to link with the pthread library
#define NB_THREADS 8
#define NB_DEPOSIT 1000000
typedef struct
{
int balance;
} Account;
void deposit(Account* account, int amount)
{
__sync_add_and_fetch( &(account->balance), amount);
}
// Use one global account object
Account account;
void *thread_start()
{
// Each thread will call deposit NB_DEPOSIT times
int i;
for ( i = 0 ; i < NB_DEPOSIT ; i++)
{
// Add one pesos to the account
deposit( &account, 1 );
}
pthread_exit(NULL);
}