Chapitre 8 : solutions
#
Exemples
#
01_ArraysDeclarations
#
#include <stdio.h>
#define NMAX 32
int main(void)
{
double price[NMAX];
printf("Array \"price\" has a size of %d\n", (int)(sizeof(price) / sizeof(double)));
// Variable length array are not supported on Visual Studio
#ifndef _MSC_VER
const int nMAX = 43;
double price2[nMAX]; // VS : error C2057: expected constant expression
printf("Array \"price2\" has a size of %d\n", (int)(sizeof(price2) / sizeof(double)));
int nmax;
printf("Please enter \"price3\" array size: ");
scanf("%d", &nmax); // TODO: should use safe scanf here
double price3[nmax]; // VS : error C2057: expected constant expression
printf("Array \"price3\" has a size of %d\n", (int)(sizeof(price3) / sizeof(double)));
#endif
#ifdef __GNUC__
// NOTE: nMAX6 is actually not a constant.
// => price6 is a VLA and thus cannot be initialized like that.
const int nMAX6 = 3;
// double price6[nMAX6] = {1, 2, 3};
#endif
return 0;
}
02_ArraysInitialisations
#
#include <stdio.h>
int main(void)
{
// ALL elements are initialized
int tablo[5] = { -12, 9, 5, 47, 66 };
// SOME elements are initialized.
// The others are set to 0.
// SEE norm 6.7.9/19
int tab[5] = { 1, 4, 9 };
tab[3] = 11;
// Size is automatically set to 4 because of initialisation
double data[] = { 1.3, 2.6, -8.4, 0.1 };
// Better, when possible, to enforce the size directly
double data2[4] = { 1.3, 2.6, -8.4, 0.1 };
// TOO FEW init values => the remaining values are set to the default value
int tab2[4] = { 1, 2, 3 };
// TOO MANY init values => error
// int tab3[4] = { 1, 2, 3, 4, 5 };
// TOO FEW init values => the remaining values are set to the default value
char tab4[4] = { 'a', 'b', 'c' };
// TOO MANY init values => error
// char tab5[4] = { 'a', 'b', 'c', 'd', 'e' };
// TOO FEW init values using literals => the remaining values are set to the default value
char word[25] = "world";
printf("%s", word); // Prints "world" + garbage as word is missing the null terminating character
// TOO MANY init values using literals => "OK"
// SEE norm 6.7.9/14
char word2[5] = "world";
printf("%s", word); // Prints "world" + garbage as word is missing the null terminating character
return 0;
}
#include <stdio.h>
// Prototypes
int input_size(void);
double input_value(void);
int main(void)
{
// Variable length array are not supported on Visual Studio
#ifndef _MSC_VER
int size = input_size();
int tablo[size];
// [Error with GCC] error: variable-sized object may not be initialized
// double val[size] = { 1.1, 2.2, 3.3 };
#endif
double x = 1.23;
double values[3] = { 2.4, 1.2, x };
// Can we initialize an array with values known at runtime?
// Variable length array are not supported on Visual Studio
#ifndef _MSC_VER
int value2 = input_value();
// OK: constant-size array
double array2[] = { 1.1, 2.2, value2 };
int size3 = input_size();
// [Error with GCC] error: variable-sized object may not be initialized
// double array3[size3] = { 1.1, 2.2, value2 };
#endif
int nbElements = sizeof(values) / sizeof(double);
// Set all values in an array
for (int i = 0; i < nbElements; ++i)
{
values[i] = i / 10.;
}
// Print all values in an array
for (int i = 0; i < nbElements; ++i)
{
printf("%lf ", values[i]);
}
printf("\n");
// Copy values from one to array to the other
double values2[3];
for (int i = 0; i < nbElements; ++i)
{
values2[i] = values[i];
printf("%lf ", values2[i]);
}
printf("\n");
return 0;
}
int input_size(void)
{
int size;
printf("Please enter array size: ");
scanf("%d", &size); // TODO: use safe scanf here
return size;
}
double input_value(void)
{
// Handling User input errors:
// 1) Print what is expected
// 2) Read input from User
// 3) Empty the stdin buffer
// 4) Repeat until we got what we expected
int status = 0;
const int nbExpectedValues = 1;
// Variables to store User input values
int value;
do
{
printf("Input value: ");
status = scanf("%lf", &value);
// IMPORTANT: fflush(stdin) does not always work!
// It is strongly advised NOT to use it
// fflush(stdin);
// Instead, empty the buffer "manually"
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
}
// BIIIP to let user know when there is a problem
if (status != nbExpectedValues)
{
printf("\a");
}
} while (status != nbExpectedValues);
return value;
}
04_SideEffects
#
#include <stdio.h>
int main(void)
{
int daysInMonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
// Out of range access
// daysInMonth[12], daysInMonth[13] and daysInMonth[14] print garbage
for (int i = -3; i < 15; i++)
{
printf("daysInMonth[%d] = %d\n", i + 1, daysInMonth[i]);
}
return 0;
}
05_ArrayOfConsts
#
#include <stdio.h>
int main(void)
{
const double sinus[91] = { 0.000, 0.017, 0.035, 0.052, 0.070, 0.087 };
printf("sinus[4] = %f\n", sinus[4]);
// ERROR: error C2166: l-value specifies const object
sinus[0] = 1.0;
printf("sinus[0] = %f\n", sinus[0]);
return 0;
}
06_Size
#
#include <stdio.h>
int main(void)
{
int data[100] = { 1, 2, 3, 4, 5, 6, 7 };
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
// Total size
printf("Total size of array \"data\" = %d\n", (int)sizeof(data));
// Nb Elements in array data
int nbElementsInData = (int)sizeof(data) / sizeof(int);
printf("Number of elements in array \"data\" = %d\n", nbElementsInData);
// Nb Elements in array vowels
int nbElementsInVowels = (int)sizeof(vowels) / sizeof(char);
printf("Number of elements in array \"vowels\" = %d\n", nbElementsInVowels);
return 0;
}
07_ArraysParam
#
#include <stdio.h>
// NOTE: arrays cannot be passed by values so they decay into pointers when passed to functions
void display(int tab[], int nb)
{
int i;
// IMPORTANT: int tab[] here is treated as a pointer (an address). So sizeof(tab) returns the size of a pointer.
// ==>> ALWAYS pass an additional parameter giving the number of elements in the array
printf("Array size as seen OUTSIDE the function is %d elements\n", nb);
// NOTE: Visual Studio issues a warning here
printf("Array size as seen INSIDE the function is %d elements\n", (int)(sizeof(tab) / sizeof(int)));
for (i = 0; i < nb + 2; i++)
{
printf("%d\n", tab[i]);
}
}
int main(void)
{
int tablo[10] = { 1,2,3 };
display(tablo, sizeof(tablo) / sizeof(int));
return 0;
}
08_Multi
#
#include <stdio.h>
int main(void)
{
int value[20][40];
double volume[10][10][10];
int matrix[2][4] = { {10,20,30,40}, {15,25,35,45} };
printf("\"value\" size is %d\n", (int)(sizeof(value) / sizeof(int)));
printf("\"volume\" size is %d\n", (int)(sizeof(volume) / sizeof(double)));
printf("\"matrix\" size is %d\n\n", (int)(sizeof(matrix) / sizeof(int)));
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("matrix[%d][%d] = %d\n", i, j, matrix[i][j]);
}
}
printf("matrix[%d][%d] = %d\n", 1, 0, matrix[1][0]);
return 0;
}
09_StructureCopy
#
#include <stdio.h>
#include <string.h>
struct User
{
char login[16];
int id;
};
int main(void)
{
int current_id = 42;
struct User user1 = { "toto", current_id++ };
struct User user2 = { .id = current_id++, .login = "titi" };
struct User user3;
printf("INITIALISATION\n");
printf("user1 {id, login}: {%d, %s}\n", user1.id, user1.login);
printf("user2 {id, login}: {%d, %s}\n", user2.id, user2.login);
printf("user3 {id, login}: {%d, %s}\n", user3.id, user3.login);// NOTE: prints garbage
strcpy(user1.login, "tata");
printf("strcpy from literal\n");
printf("user1 {id, login}: {%d, %s}\n", user1.id, user1.login);
printf("user2 {id, login}: {%d, %s}\n", user2.id, user2.login);
printf("user3 {id, login}: {%d, %s}\n", user3.id, user3.login);// NOTE: prints garbage
strcpy(user3.login, user1.login);
printf("strcpy from other structure\n");
printf("user1 {id, login}: {%d, %s}\n", user1.id, user1.login);
printf("user2 {id, login}: {%d, %s}\n", user2.id, user2.login);
printf("user3 {id, login}: {%d, %s}\n", user3.id, user3.login);
user3 = user2;
printf("Full structure assignment\n");
printf("user1 {id, login}: {%d, %s}\n", user1.id, user1.login);
printf("user2 {id, login}: {%d, %s}\n", user2.id, user2.login);
printf("user3 {id, login}: {%d, %s}\n", user3.id, user3.login);
return 0;
}
10_MemoryAllocationStringInt
#
#include <stdio.h>
#include <string.h>
/* Allocation de:
k vaut 30 a la fin de la boucle
a=1 0x0001
b
c= -1 = 0xFFFF
t1="abcd"
t2="xyz"
En memoire on a :
x y z \0 a b c d \0 0xFFFF **** 1000 00021 ******
t1 t2 c b a k
strcpy(t2,"1234567890");
En memoire on a :
1 2 3 4 5 6 7 8 0x90FF **** 1000 00021 ******
t1 t2 c b a k
*/
int main(void)
{
int k;
int a = 1;
int b;
int c = -1;
char t1[] = "abcd";
char t2[] = "xvy";
printf("&a:%p(%d)\n&b:%p(%d)\n&c:%p(%d)\nt1:%p(%d)\nt2:%p(%d)\n", &a, &a, &b, &b, &c, &c, t1, t1, t2, t2);
printf("-----------------------\n");
for (k = 0; k < 30; k++)
{
printf("%p(%d) %c %d\n", &t2[k], &t2[k], t2[k], t2[k]);
}
printf("-----------------------\n");
strcpy(t2, "1234567890");
for (k = 0; k < 30; k++)
{
printf("%p(%d) %c %d\n", &t2[k], &t2[k], t2[k], t2[k]);
}
printf("-----------------------\n");
printf("\n%s", t1);
return 0;
}
11_StringsInitializations
#
#include <stdio.h>
#include <string.h>
int main(void)
{
char fileName[16] = "test.c";
printf("%s", fileName);
char word[] = {'H','e','l','l','o'};
printf("%s", word);
char chaine[256];
char mini[4];
scanf("%s", chaine);
scanf("%s", mini);
printf("%s\n", chaine);
printf("%s\n", mini);
return 0;
}
12_RevueCStrings
#
#include <stdio.h>
#include <string.h>
int main(void)
{
char letter = 'a';
char chaine[] = "a";
char temp [] = "";
char text [] = "Blablabla";
int i = 0;
for (; i < strlen(text)+1 ; i++)
{
temp[i] = text[i];
}
return 0;
}
1242.1_08.96_ArrayInitializationToZero
#
#include <stdio.h>
// Global or static array => elements automatically initialized to 0
int global_array[4];
int main(void)
{
// Not initialized by default
int local_array[4];
// First element initialized => all the others initialized too
int local_array1[4] = {0};
// Works with GCC but non-standard => do not use.
int local_array2[4] = {};
// Global or static array => elements automatically initialized to 0
static int static_array[4];
return 0;
}
1242.1_08.97_ScanfBufferOverflow
#
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
// IMPORTANT for Visual Studio: execute in RELEASE Mode to avoid additional debug padding around stack variables
int main(void)
{
// IMPORTANT for Visual Studio: variables order on the stack is not guaranteed.
// If we do char a[9] instead, then a and b will be in different order on the stack.
bool access_granted = false;
char expected_password[10] = "admin1234";
char actual_password[10];
printf("Please enter password: ");
scanf("%s", actual_password); // Enter "admin99999999999999999"
if (strcmp(actual_password, expected_password) == 0) // If password is correct
{
access_granted = true;
}
if (access_granted == true)
{
printf("CONGRATS: you gained control of the server!\n");
}
else
{
printf("SORRY: you do not have enough privileges!\n");
}
return 0;
}
1242.1_08.98_VLAs
#
#include <stdio.h>
// If not using MSVC
#ifndef _MSC_VER
// If C version is C11 or newer, VLAs are optional.
// => So explicitly check for their support
#if __STDC_VERSION__ >= 201100L
#ifndef _STDC_NO_VLA_
#define VLAS_SUPPORTED
#endif
// Else if C version is C99, VLAs are supported.
#elif __STDC_VERSION__ >= 199900L
#define VLAS_SUPPORTED
#endif
#endif
// OK with VS and GCC
#define DEF_ARRAY_SIZE 10
int array1[DEF_ARRAY_SIZE];
// NOTE: const in C means "read-only", not that it is a constant.
// => So const_array_size is still considered as a variable.
// VS: error C2057: expected constant expression
// GCC: error: variably modified tabg2 at file scope
const int const_array_size = 10;
// int array2[const_array_size];
void function(void)
{
// Compile error with VS
// VS: error C2057: expected constant expression
#ifdef VLAS_SUPPORTED
// OK with GCC
int array3[const_array_size];
// NOTE: const in C means "read-only", not that it is a constant.
// GCC: error: variable-sized object may not be initialized
// int array4[const_array_size] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// But the following is OK
int array5[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
#endif
}
int main(void)
{
#ifdef VLAS_SUPPORTED
printf("VLAs are supported on this compiler");
#endif
function();
return 0;
}
1242.1_08.99_StringOverflow
#
#include <stdio.h>
// Run it with the debugger and see what happens
int main(void)
{
char string[4] = "123";
printf("%s\n", string);
scanf("%s", string);
printf("%s\n", string);
return 0;
}
Solutions série 8.1
#