// cour_21/12/2002 : structures statiques et dynamiques / pointeurs


/*

STRUCTURES STATIQUES  / DYNAMIQUES :
=================================
	 * une structure de données peut être déclarée statiquement
		et utilisée durant l'execution du programme sans changement de type ou de taille
		de la structure : elle est alors dite STATIQUE.

		ex: une déclaration de structure statique serait : int tab[30];
		ce tableau de 30 entiers est fixe, statique, (zone mémoire réservée à ce tableau )
		qu'il soit utilisé ou pas


	 * une structure de données peut être créée dynamiquement suite à un évènement
	justifiant cette création, et appartenir à un ensemble chainé de cellules : 
	elle alors dite DYNAMIQUE, ainsi que l'ensemble auquel elle appartient.

		ex: une structure dynamique :
		tête de liste  ---->  valeur /cellule suivante ----> valeur /cellule suivante ...etc...

		on peut ajouter ou supprimer des elements, ceci allouant ou libérant la zone mémoire
		associée.



STRUCTURE DYNAMIQUE : POURQUOI 
==============================
	 * elles vont permettre une gestion optimisée de données dont le flux d'arrivée
		est aléatoire. Une déclaration statique pour traiter un flux aléatoire comporte
		un risque : 
			- faible, sans conséquence, si le nombre d'éléments réservés est sous-utilisé,
			- grave, si le nombre de données du flux de données à traiter dépasse les zones
				mémoire reservées pour ces éléments ==> overflow, débordement. Il y aura soit 
				des elements non traités soit plantage du programme.

		ex: files d'attente

MISE EN OEUVRE  / IMPLEMENTATION DES STRUCTURES DYNAMIQUES
=========================================================
	 * cette implémentaion s'appuie sur un type particulier de données auquel sont associés 
		2 mécanismes :
			- allocation dynamique de mémoire, pointé par des variables de ce type
			- libération de la zone mémoire allouée

	 * ce type de données s'appelle POINTEUR.

UN POINTEUR
===========
	 * c'est une variable dont la valeur est l'ADRESSE d'une autre variable.

	 * à toute variable x (simple ou composée) correspond 2 champs : 
			- son adresse
			- sa valeur

		en C, int i;
			le compilateur crée une zone mémoire adéquate adressable reservée exclusivement à "i"
		Il y a création d'une table des symboles :
				nom de variable	-> adresse			adresse -> contenu
		Cette ADRESSE peut être mémorisée dans une variable dite POINTEUR (dans le cas de "i",
				pointeur sur un entier).
		Via le pointeur contenant l'adresse de "i", on peut changer la valeur de "i".
		
		En C :
			l'adresse de "i" est notée : &i
				& est une fonction qui en s'applicant sur "i" donne son adresse
			en applicant l'opérateur  *, on peut obtenir la valeur :  *&i
				 * est un opérateur qui en s'applicant sur l'adresse de "i" donne sa valeur

	 * un pointeur doit être déclaré, comme tout autre variable

DECLARATION DES POINTEURS
==========================
	 * un pointeur est typé dans le sens où on a besoin lors de sa déclaration de spécifier
		le type de variable dont il va contenir d'adresse.

		déclaration de variables : T x;		=> x est de type T
		déclaration de pointeur : T  *p		=> p est une variable qui peut contenir des adresses 
												de variables de type T

	 * ex :
		int x;		 / x est un entier
		int  *p;		 / p contenir des adresses d'entiers, dont x
		x=10;
		p=&x;

RESUME
======
une variable a une adresse, et via cette adresse on peut obtenir sa valeur.
Cette adresse d'appelle POINTEUR.



FONCTIONS PARAMETREES ET PASSAGE PAR ADRESSE
============================================
	 * voir exo



MECANISME D'ALLOCATION DYNAMIQUE
================================
	 * ce mécanisme est réalisé en C, avec la fonction "malloc(taille_à_allouer)".
		"taille_à_allouer" est un entier precise la taille en octets de la zone mémoire
		à créer. Cette zone est accessible /adressable par l'adresse retournée 
 */

#include "stdio.h"
 //#include "stdafx.h"
 //#include <malloc.h>
#include <stdlib.h>


 // valeur et adresse
void exo_0 () 
{
	printf("\n====Cours Exo 0");

	int i=5;

	printf("\nAdresse de i : %x",&i);
	printf("\nValeur de i (1): %i",i);
	printf("\nValeur de i (2): %i", *&i);

};

 // valeur et adresse
void exo_1 () 
{
	printf("\n====Cours Exo 1");

	int x;
	int  *p;

	x=10;
	p=&x;

	printf("\nValeur de x (1): %i",x);
	printf("\nAdresse de x : %i",p);
	printf("\nValeur de x (2): %i", *p);
	printf("\nValeur de x (3): %i", *&x);

};


 // MODE DE PASSAGE PAR VALEUR
void incrementer_exo_2 (int v)  // incrementation
	{
	printf("\nIncrementer : avant v=%i",v);
	v=v+10;
	printf("\nIncrementer : apres v=%i",v);
	 // le v utilisé est celui declaré localement
	};
void exo_2 ()
{
	printf("\n====Cours Exo 2");

	int x=10;

	printf("\nValeur de x avant: %i",x);
	incrementer_exo_2(x);  // passage par valeur
	printf("\nValeur de x apres: %i",x);

	printf("\nNE FONCTIONNE PAS : LA VALEUR INCREMENTEE N'EST PAS RETOURNEE");

};



 // MODE DE PASSAGE PAR ADRESSE
void incrementer_exo_3 (int  *v)  // incrementation grace à l'adresse
	{
	printf("\nIncrementer : avant v=%i", *v);
	 *v= *v+10;
	printf("\nIncrementer : apres v=%i", *v);
	};
void exo_3 ()
{
	printf("\n====Cours Exo 3");

	int x=10;

	printf("\nValeur de x avant: %i",x);
	incrementer_exo_3(&x);  // passage par adresse
	printf("\nValeur de x apres: %i",x);

};



 // incrémenter la valeur d'un entier x en passant par son adresse
void exo_4 () 
{
	printf("\n====Exo 4");

	int x;
	int y;
	int  *p;

	x=10;
	printf("\nValeur de x : %i",x);
	p=&x;
	printf("\nAdresse de x : %i",p);

	 *p= *p+1;  // equivalent à x=x+1 
	printf("\nNouvelle valeur de x : %i", *p);

	y=20;
	p=&y;
	printf("\nValeur de y : %i", *p);

};



 // allocation dynamique  : utilisation de malloc
 // sizeof(type) : retourne la longueur reservée pour type
void exo_5 () 
{
	printf("\n====Exo 5");

	int x=10;
	int  *p=&x;
	printf("\nValeur de x : %i", *p);

	p=(int *) malloc(sizeof(int));  // (int  *) signifie "conversion en pointeur sur entier"
	 *p=20;
	printf("\nValeur de  *p : %i", *p);
	printf("\nValeur de x : %i",x);

	 // cet exemple sera repris plus tard ...  A SUIVRE ...

	 // ex: macanisme de conversion
	 // float x=12.5;
	 // int z;
	 // z=(int)x;
	 // ou x=(float)z;

};


 // utilisation des adresses
void permutter_6(int * x,int * y)  // permuter les valeurs qui se trouvent aux adresses
{	
	int  *t=new int;  // allocation d'une zone mémoire 
	 *t= *x;
	 *x= *y;
	 *y= *t;


	 //ou
	 //int t= *x;
	 // *x= *y
	 // *y=t
};
void exo_6 () 
{
	printf("\n====Exo 6");

	int i=10;
	printf("\nValeur de i avant: %i",i);
 //		i
 //-----------------
 //I		I		I
 //I	&i	I	 *&i	I
 //I		I	10	I
 //-----------------

	int j=15;
	printf("\nValeur de j aavant: %i",j);
 //		j
 //-----------------
 //I		I		I
 //I	&j	I	 *&j	I
 //I		I	15	I
 //-----------------

	permutter_6(&i,&j);

	printf("\nValeur de i apres (1): %i",i);
	printf("\nValeur de j apres (1): %i",j);


	int *p=&i;
	int *r=&j;

	permutter_6(p,r);

	printf("\nValeur de i apres (2): %i",i);
	printf("\nValeur de j apres (2): %i",j);

};



void main()
{
	printf("\n=================\a");
	printf("\nDEBUT D'EXECUTION");
	printf("\n=================");

	 //exo_0();
	 //exo_1();
	 //exo_2();
	 //exo_3();
	 //exo_4();
	 //exo_5();
	  exo_6();

	printf("\n=================");
	printf("\nFIN D'EXECUTION");
	printf("\n=================\a\n");

}