Questions à choix multiples¶
Cette semaine, la matière porte sur l’organisation de la mémoire et l’utilisation des fonctions malloc(3) et free(3)
Question 1. Portée des variables¶
Lorsque l’on écrit un programme C, il est préférable d’éviter d’avoir deux variables qui ont le même nom et peuvent être utilisées dans une fonction. Un étudiant a écrit le programme ci-dessous :
#include <stdio.h> int i = 1; int main(int argc, char * argv[]) { int k; printf("A:%d\n", i); for(k=0; k<1; k++) { int i = 2, j = 1252; printf("B:%d %d\n", i, j); { int i = 0; printf("C:%d %d\n", i, j); } printf("D:%d\n", i); } return 0; }
A:1
B:2 1252
C:0 1252
D:2
Le programme ne se compile pas, il est interdit de redéfinir la variable globale i
.
A:1
B:1 1252
C:1 1252
D:1
A:1
B:2 1252
C:2 1252
D:2
A:1
B:2 1252
C:0 1252
D:0
Question 2. Portée des variables¶
L’extrait ci-dessous provient d’un programme écrit par un étudiant.
#include <stdio.h> int i = 1252; void f(int i) { // code non fourni } void g(char* c) { // code non fourni } int main(int argc, char * argv[]) { f(argc); g(argv[0]); }
- La fonction
g
peut accéder à la variable globalei
et modifier sa valeur - La fonction
g
ne peut lire la valeur deargc
- La fonction
f
ne peut modifier la valeur de la variable globalei
- La fonction
g
peut lire la variable globalei
mais pas modifier sa valeur - La fonction
g
ne peut lire la valeur deargc
- La fonction
f
peut modifier la valeur de la variable globalei
- La fonction
f
peut lire la variable globalei
mais pas modifier sa valeur - La fonction
g
peut lire la valeur deargc
- La fonction
f
peut modifier la valeur de la variable globalei
- La fonction
f
peut lire la variable globalei
et modifier sa valeur - La fonction
g
ne peut lire la valeur deargc
- La fonction
f
ne peut modifier la valeur de la variable globalei
Question 3. Organisation de la mémoire¶
Considérons le fragment de programme ci-dessous.
#include <stdio.h> int i,j,k = 1252; // ligne A int tab[1000]; // ligne B void f(int i) { // ligne C int j; // ligne D // code non fourni } void g(char c) { int i; // ligne E // code non fourni } int main(int argc, char * argv[]) { int k=1; // ligne F f(argc); g('a'); }
- la variable
i
déclarée enligne A
est stockée dans la zone des variables non-initialisées - l’argument
i
déclaré enligne C
est stocké sur la pile - la variable
j
déclarée enligne D
est stockée sur la pile - la variable
k
déclarée enligne F
est stockée sur la pile
- la variable
i
déclarée enligne A
est stockée dans la zone des variables non-initialisées - le tableau
tab
déclaré enligne B
est stocké dans la zone des variables non-initialisées - l’argument
i
déclaré enligne C
est stocké sur la pile - la variable
i
déclarée enligne E
est stockée sur la pile
- le tableau
tab
déclaré enligne B
est stocké dans la zone des variables initialisées - l’argument
i
déclaré enligne C
est stocké sur la pile - la variable
j
déclarée enligne D
est stockée sur la pile - la variable
i
déclarée enligne E
est stockée sur la pile - la variable
k
déclarée enligne F
est stockée dans la zone des variables non-initialisées
- le tableau
tab
déclaré enligne B
est stocké dans la zone des variables non-initialisées - l’argument
i
déclaré enligne C
est stocké sur le tas - la variable
k
déclarée enligne F
est stockée sur la pile
- le tableau
tab
déclaré enligne B
est stocké dans la zone des variables non-initialisées - l’argument
i
déclaré enligne C
est stocké sur la pile - la variable
j
déclarée enligne D
est stockée sur la pile - la variable
i
déclarée enligne E
est stockée sur le tas - la variable
k
déclarée enligne F
est stockée sur la pile
- la variable
i
déclarée et initialisée enligne A
est stockée dans la zone des variables initialisées - le tableau
tab
déclaré enligne B
est stocké dans la zone des variables non-initialisées - l’argument
i
déclaré enligne C
est stocké sur la pile - la variable
k
déclarée enligne F
est stockée sur le tas
Question 4. Initialisation des variables¶
En C, une règle de bonne pratique est d’initialiser toutes les variables avant leur utilisation. Utiliser une variable qui n’a pas été correctement initialisée pour être une source de problèmes. Un étudiant a écrit les déclarations ci-dessous :
int k=0; int i; short j; float f; double d; char c[10]; char* string; void* v; int* ptr; ptr=(int*) malloc(5*sizeof(int));
- la variable
i
est initialisée à la valeur0
- le pointeur
string
est initialisé à la valeurNULL
c[2]
contient le caractère'\0'
- Après exécution de
malloc
, le contenu de l’adresseptr+1
est indéterminé
- la variable
j
est initialisée à la valeur0
- le pointeur
v
est initialisé à la valeurNULL
c[4]
contient le caractère'\0'
- Après exécution de
malloc
, le contenu de l’adresseptr+4
est indéterminé
- la variable
f
est initialisée à la valeur0.0
- le pointeur
string
n’a aucune valeur et n’est pas utilisable c[2]
contient le caractère espace- Après exécution de
malloc
, l’adresseptr+1
contient le caractère'\0'
- la variable
f
est initialisée à la valeur0.0
- le pointeur
v
n’a aucune valeur et n’est pas utilisable c[2]
contient le caractère espace- Après exécution de
malloc
, l’adresseptr
contient le caractère'\0'
- la variable
f
est initialisée à la valeur0.0
- le pointeur
string
est initialisé àNULL
c[10]
contient le caractère espace- Après exécution de
malloc
, l’adresseptr+3
contient le caractère'\0'
- la variable
f
est initialisée à la valeur0.0
- le pointeur
v
est initialisé àNULL
c[6]
contient le caractère'\0'
- Après exécution de
malloc
, l’adresseptr+5
contient le caractère'\0'
Question 5. malloc(3) et compagnie¶
Cette question porte sur les fonctions malloc(3) et free(3) qui sont importantes pour la manipulation de la mémoire sur le tas.
la fonction malloc(3) retourne un pointeur de type
void *
la fonction free(3) prend comme argument un pointeur de type
void *
qui a été précédemment alloué par la fonction malloc(3)si l’appel à calloc(3) a retourné un pointeur différent de
NULL
, alors la zone mémoire demandée a été allouée et est initialisée à zéroune implémentation possible (non efficace) de realloc(3) est
void *realloc(void *ptr, size_t len) { void *r; r = malloc(len); if(r!=NULL) { memcpy(r, ptr, len); free(ptr); } return r; }
la fonction malloc(3) retourne un pointeur de type
void *
la fonction free(3) prend comme argument n’importe quel type de pointeur
si l’appel à malloc(3) a retourné un pointeur différent de
NULL
, alors la zone mémoire demandée a été allouée mais n’est pas initialisée à zéroune implémentation possible (non efficace) de realloc(3) est
void *realloc(void *ptr, size_t len) { void *r; r = malloc(len); memcpy(r, ptr, len); return r; }
la fonction calloc(3) retourne un pointeur de type
void *
la fonction free(3) prend comme argument un pointeur de type
void *
qui a été précédemment alloué par la fonction malloc(3)si l’appel à malloc(3) a retourné un pointeur différent de
NULL
, alors la zone mémoire demandée a été allouée et est initialiséeune implémentation possible (non efficace) de realloc(3) est
void *realloc(void *ptr, size_t len) { return malloc(len); }
la fonction calloc(3) retourne un pointeur de type
void *
la fonction free(3) prend comme argument un pointeur de type
void *
qui a été précédemment alloué par la fonction malloc(3)si l’appel à malloc(3) a retourné un pointeur différent de
NULL
, alors la zone mémoire demandée a été allouée et est initialiséeune implémentation possible (non efficace) de realloc(3) est
void *realloc(void *ptr, size_t len) { void *r; r = malloc(len); if(r) { return r; } else { return NULL; } }
Question 6. Stack¶
size
permettant de calculer le nombre d’éléments stockés dans la pile ?int size(struct node_t* stack)
{
struct node_t *curr = stack;
int count = 0;
while (curr!=NULL) {
count ++;
curr = stack->next;
}
return count;
}
int size(struct node_t* stack)
{
int count = 0;
while (stack!=NULL) {
count ++;
stack = stack->next;
}
return count;
}
int size(struct node_t* stack)
{
int count = 0;
while (stack!=NULL) {
count ++;
stack++;
}
return count;
}
int size(struct node_t* stack)
{
return sizeof(stack);
}
int size(struct node_t* stack)
{
struct node_t *curr = stack;
int count = 0;
while (curr) {
count ++;
curr++;
}
return count;
}
int size(struct node_t stack)
{
struct node_t curr = stack;
int count = 0;
while (curr) {
count ++;
curr = stack->next;
}
return count;
}
Question 7. strdup(3)¶
char *strdup(const char *s)
{
char *new = (char *) malloc ((strlen(s)+1) * sizeof(char));
if (new == NULL)
return NULL;
return memcpy(new, s, (strlen(s)+1) * sizeof(char));
}
char *strdup(const char *s)
{
char *new = (char *) malloc ((strlen(s)+1) * sizeof(char));
if (!new)
return NULL;
return memcpy(new, s, (strlen(s)+1) * sizeof(char));
}
char *strdup(const char s)
{
void *new = malloc (strlen(s));
if (new == NULL)
return NULL;
return memcpy(new, s, strlen(s));
}
char *strdup(const char *s)
{
char new [strlen(s)+1];
return memcpy(new, s, (strlen(s)+1) * sizeof(char));
}
char *strdup(const char * s)
{
void *new = malloc (strlen(s+1));
return memcpy(new, s, strlen(s+1));
}
char *strdup(const char *s)
{
char *new = (char *) calloc (strlen(s) * sizeof(char));
if (new == NULL)
return NULL;
return memcpy(new, s, (strlen(s) * sizeof(char)));
}
char *strdup(const char *s)
{
char *new = (char *) malloc (strlen(s) * sizeof(char));
return memcpy(new, s, (strlen(s) * sizeof(char));
}