====== mémo-C ======
* Objet : fiche mémo langage C
* Niveau requis : {{tag>débutant avisé}}
Référence : [[http://www.squalenet.net/fr/ti/tutorial_c/sommaire.php5]]
===== Introduction =====
===installation gcc sous debian===
apt-get install build-essential
===Première compilation===
* Création d'un fichier :
vim fichier.c
__Code minimal :__
#include
#include
int main(void){ // peut s'écrire aussi: int main(int argc, char *argv[])
instructions; // par exemple : printf("Hello world!\n");
return 0;
}
>**''stdio.h''** et **''stlib.h''** sont des **bibliothèques** (des fichiers source tout prêts).
>**''main''** est une **fonction**
>C'est toujours par la fonction main que le programme commence.
>Les instructions de la fonction se mettent entre accolade ouvrante **''{''** (début) et fermante **''}''** (fin). Une fonction est forcément délimitée par des accolades.
>Toute instruction se termine obligatoirement par un point-virgule « **;** »
>**''return 0;''** : Cette ligne indique qu'on arrive à la fin de notre fonction main et demande de renvoyer la valeur 0.
__Exemple :__\\
#include
int main(void){
printf("Hello World\n");
}
* \n : retour à la ligne
* \t : tabulation
__printf :__ \\
*Syntaxe :
printf("")
printf("%type",variable)
ou
printf("%type", variable)
>La virgule est obligatoire.
printf("%type1 %type2",var1,var2)
>Les virgules sont obligatoires
* Compilation (se trouver dans le répertoire parent du fichier):
gcc main.c
* Il s'est créé un exécutable :
ls
a.out main.c
* Exécuter :
./a.out
===Ligne de commandes pour compilation et exécution===
* Choisir le nom de l'exécutable :
gcc -o nom-exécutable nom fichier-à-compiler
gcc -o main.x main.c
ls
a.out main.c main.x
>-o : donner le nom "main.x" à l'exécutable ;
>main.x : nom choisi pour l'exécutable ;
>main.c : nom du fichier de code c qui va être compilé ;
* compilation et exécution :
gcc -o main.x main.c; ./main.x
* ./main.x : pour lancer l'exécutable issu de la compilation ;
===== Variables =====
Les variables sont typées. Deux grands types, numériques, caractères.
^type ^déclaration ^ récupération de valeur ^
|int |int nombre=n (n est un nombre de 0 à 255) | "%d,nombre" |
|char |char caratere='x' (x est une lettre) | "%c,x" |
|char |char chaine[nombre-max]="chaine" | "%s,chaine" |
====Nombre entier ====
* Variable nombre entier (int)
#include
int main(void){
int age=22;
int taille=175;
printf("valeur age: %d valeur taille: %d\n",age,taille);
}
* La dernière valeur d'une même variable est celle enregistrée.
#include
int main(void){
int age=22;
age=23;
int taille=175;
printf("valeur age: %d valeur taille: %d\n",age,taille);
}
gcc -o main.x main.c; ./main.x;
valeur age: 23 valeur taille: 175
====char : caractère, chaîne de caractères ====
Pour désigner un caractère imprimable, il suffit de le mettre entre apostrophes (par ex. 'A' ou '$'). Les seuls caractères imprimables qu'on ne peut pas représenter de cette façon sont __l'antislash et l'apostrophe__, qui sont respectivement désignés par **''\\''** et **''\'''**.\\ Le point d'interrogation et les guillemets peuvent aussi être désignés par les notations **''\?''** et **''\"''**.\\ Les caractères non imprimables peuvent être désignés par **'''\code-octal'''** où code-octal est le code en octal du caractère.\\ On peut aussi écrire '\xcode-hexa' où code-hexa est le code en hexadécimal du caractère (cf. page X).\\ Par exemple, **'''\33'''** et **'''\x1b'''** désignent le caractère escape.\\
Toutefois, les caractères non-imprimables les plus fréquents disposent aussi d'une notation plus simple :
\n nouvelle ligne
\t tabulation horizontale
\v tabulation verticale
\b retour arrière
\r retour chariot
\f saut de page
\a signal d'alerte
Suivant les implémentations, le type char est signé ou non. En cas de doute, il vaut mieux préciser **unsigned char** ou **signed char**.
===char : %c (un caractère) ===
#include
int main(void){
char lettre='x';
lettre='a';
printf("%c\n",lettre);
}
===char : %s (chaîne de caractères)===
^ ^ ^ ^
|**%c**|unsigned char |caractère |
|**%s** |char* | chaîne de caractères |
#include
main()
{
char c = 'A';
char *chaine = "chaine de caracteres";
printf("\nimpression de c: \n");
printf("%c \t %d",c,c);
printf("\nimpression de chaine: \n");
printf("%s \t %.10s\n",chaine,chaine);
printf("\t%.7s \t %.5s\t %.3s\n",chaine,chaine,chaine);
printf("\n");
}
gcc -o char.x char.c; ./char.x
impression de c:
A 65
impression de chaine:
chaine de caracteres chaine de
chaine chain cha
* __**Autre méthode**__ :
#include
int main(void){
char chaine[6]="a b c";
printf("%s\n",chaine);
}
>Ne pas oublier de pointer un espace mémoire pour chaque caractère (ou plus) de la chaîne.
>les guillemets doubles autour de la valeur sont obligatoires.
Une des particularités du type char en C est qu'il peut être assimilé à un entier : tout objet de type char peut être utilisé dans une expression qui utilise des objets de type entier.\\ Par exemple, si c est de type char, l'expression c + 1 est valide. Elle désigne le caractère suivant dans le code ASCII.\\ Ainsi, le programme suivant imprime le caractère 'B'.
main()
{
char c = 'A';
printf("%c", c + 1);
}
===Déclaration de plusieurs types de variables ===
* Soit le programme "declare.c" :
#include
main(void){
printf("Bonjour\n");
char lettre='a';
printf("valeur \"lettre\": %c\n",lettre);
char chaine[10]="Hypathie"; // [10] pour déclarer une chaîne, il faut indiquer le nombre max
printf("valeur \"chaine\": %s\n",chaine);
int age=22;
printf("Valeur \"age\": %d\n",age);
return 0;
}
gcc -o declare.x declare.c ; ./declare.x
Bonjour
valeur "lettre": a
valeur "chaine": Hypathie
Valeur "age": 22
===Une seule instruction peut appeler plusieurs variables===
#include
int main(void){
char nom[10]="Hypathie"; // 10 max, "hypathie -> de 0 à 7"
char lettre='a';
printf("valeur nom : %s\nvaleur lettre : %c\n",nom, lettre);
}
gcc -o main.x main.c; ./main.x;
valeur nom : Hypathie
valeur lettre : a
===Référence à une lettre d'une chaîne : la première est zéro===
#include
int main(void){
char nom[10]="Hypathie";
printf("valeur nom : %s\nvaleur lettre n°5 de nom : %c\n",nom, nom[5]);
}
gcc -o main.x main.c; ./main.x;
valeur nom : Hypathie
valeur lettre n°5 de nom : h
===Remplacement d'un caractère d'une chaîne ===
#include
int main(void){
char nom[10]="Hypathie";
nom[3]='A'; // On ne la re-type pas !
printf("lettre n°5 de nom : %s\n",nom);
}
lettre n°5 de nom : HypAthie
===Récupération d'éléments d'une chaîne===
#include
int main(void){
int var[2];
var[0]=2;
var[1]=4;
var[2]=6;
printf("%d %d %d\n",var[0], var[1], var[2]);
}
2 4 6
===déclarations de plusieurs variables (même type) sur une ligne ===
#include
int main(void){
int a, b, c; // int a,b,c;
}
* équivalent de :
#include
int main(void){
int 1;
int 2;
int 3;
}
=====Tableau =====
#include
int main(void){
int tableau1[3]={2,4,6}; //tab-de-0=2, tab-de-1=4, tab-de-3=6
printf("%d %d %d\n",tableau1[0],tableau1[1],tableau1[2]);
}
2 4 6
=====Arithmétique =====
#include
int main(void){
int age=24;
age=age+1;
printf("%d\n",age+5);
}
30
> ''age=age+1'' : modification de la valeur de la vaiable "age" ;
> mais le résultat de "age+5" n'est pas enregistré, la variable "age" a toujours la valeur 25.
__**Opérateurs de calcul**__ :
* + addition
* - soustraction
* * multiplication
* / division (quotient)
* % modulo (reste de division euclidienne)
On peut utiliser des parenthèses pour définir des ordres de priorités dans un calcul.\\
x=(a+b)*2
=== Autre type de variables numériques===
Pour les nombres flottant, la virgule est remplacée par un point.
^Nom du type ^Minimum ^Maximum ^
| signed char | -127 |127 |
|int | -32 767 | 32 767 |
|long | -2 147 483 647 | 2 147 483 647 |
|float | -1 x1037 | 1 x1037 |
|double |-1 x1037 |1 x1037 |
|unsigned char |0 | 255 |
|unsigned int | 0 |65 535 |
|unsigned long |0 |4 294 967 295|
* affichage du contenu de variable :
^Format ^Type attendu ^
|"%d" | int |
|"%ld" |long |
|"%f" | float |
|"%f" | double |
=====Les conditions =====
===if else===
* si plusieurs instructions, accolades :
#include
int main(void){
déclarations1;
déclaration2;
...;
if(condition){
instruction1;
instruction2;
}
else{
instruction1;
instruction2;
}
}
> entre les parenthèses : condition
> entre accolades : instructions
> accolades dans le **''if'' et dans le ''else''**,
>accolades **nécessaires** dans le ''if'' et dans le ''else'', si **plusieurs instructions** dans le ''if'' et dans le ''else''; s'il n'y a qu'une instruction, on peut éviter les accolades.
*Avec qu'une instruction, pas besoin d'accolades :
#include
int main(void){
déclaration1;
déclaration2;
if(condition)instruction;
else instruction;
}
* Exemples de if avec comparaison (==)
#include
int main(void){
int var1=10;
if(var1==10){
printf("var1 est équivalent à %d\n", var1);
}
}
var1 est équivalent à 10
* sans accolades car qu'une instruction :
#include
int main(void){
int var1=1;
if(var1==10) printf("var1 est équivalent à %d\n", var1);
else printf("var1 est équivalent à %d\n et non à 1\n", var1);
}
var1 est équivalent à 1
et non à 1
===Imbrication de if, else if, else===
*__Exemple : imbrication de if et if else sans accolades avec int__
#include
int main(void){
int taille=10;
if(taille==10)printf("\tMoyen\n");
else if(taille>10)printf("\tGrand\n");
else printf("\tPetit\n");
}
* Exemple 3 : idem avec char :
#include
int main(void)
{
// afficher voyelle si 'x' == voyelle ou afficher consonne si 'x' == consonne
char var='x';
if(var=='a')printf("Voyelle\n");
else if(var=='e')printf("Voyelle\n");
else if(var=='i')printf("Voyelle\n");
else if(var=='o')printf("Voyelle\n");
else if(var=='u')printf("Voyelle\n");
else if(var=='y')printf("Voyelle\n");
else printf("Consonne\n");
}
* __Imbrication de if et else avec accolades car plusieurs instructions__ :
#include
int main(void)
{
int taille=10;
if(taille==10){
printf("\tMoyen\n");
printf("\n");
}
else
{
if(taille>10){
printf("\tGrand\n");
printf("\n");
Moyen
}
else{
printf("\tPetit\n");
printf("\n");
}
}
}
Moyen
__**Rappel if else avec le "shell"**__:\\
if [ "$USER" = "smolski" ];
then
echo 'Salut chef !'
else
echo "Bonjour $USER."
fi
====Opérateurs relationnels ====
__**Autres opérateurs relationnels**__ :
* **!** inverse
* **!=** ne correspond pas
* **<** inférieur à
* **>** supérieur à
* **>=** supérieur ou égal
* **<=** inférieur ou égal
* **==** correspond à
===correspondance et non correspondance ===
* __0 = faux ; tout autre nombre = vrai__ :
#include
int main(void){
int var1=1;
if(1){
printf("IF\n");
}
else{
printf("ELSE\n");
}
}
IF
#include
int main(void){
int var1=1;
if(0){
printf("IF\n");
}
else{
printf("ELSE\n");
}
}
ELSE
* __L'inverse de faux (de 0)__ :
#include
int main(void){
int var1=1;
if(!0){
printf("IF\n");
}
else{
printf("ELSE\n");
}
}
IF
(inverse de 0, c'est 1 => vrai)
On peut définir des ordres de priorités dans les conditions, avec les parenthèses.\\
* __Inverse de l'inverse__ :
#include
int main(void){
int var1=1;
if( !(var1!=1) ){ // !(var1==1) <-> var1!=1
printf("IF\n");
}
else{
printf("ELSE\n");
}
}
IF
===supérieurs inférieur===
#include
int main(void){
int var=5;
if(var <=4 ) printf("%d est inf. à 4\n",var);
else printf("%d n'est pas inf. à 4\n", var);
}
* Avec deux variables :
#include
int main(void){
int var1=5;
if(var1 <=4 ) printf("var1 (%d) est inf. à 4\n",var1);
else if (var1 >= 4) printf("var1 (%d) est sup. ou ég. à 4\n", var1);
else if (var1 >= 5) printf("var1 (%d) est sup. ou ég. à 5\n", var1);
int var2=6;
if (var2 < 6) printf("var2 (%d) est inf. à 6\n",var2);
else if (var2 <= 6) printf("var2 (%d) est inf. ou ég. à 6\n", var2);
}
=====while, for, do while, ++ =====
====Boucle while====
=== incrémentation===
#include
int main(void)
{
//faire prendre à i les valeurs de 1 à 9
int i=1;
while(i<10)
{
printf("%d\n",i);
i++; //i=i+1
}
}
__**Rappel syntaxe du shell:**__
while condition;
do
commande;
done
===Attention aux boucles infinies ===
#include
int main(void)
{
int i=1;
while(1) //condition 1 -> condition vraie : exécution de printf infinie
{
printf("%d\n",i);
i=i+1;
}
}
====Boucle for ====
* Syntaxe:
#include
int main(void)
{
int i; //déclaration
for(affectation;condition;incrémentation)
{
printf
}
}
* Exemple :
#include
int main(void)
{
int i; //déclaration
for(i=0;i<10;i++)
{
printf("%d\n",i);
}
}
__**Rappel : syntaxe du shell**__
for i in "les fleurs" "le lapin" "le chou" "la salade" "le staff DF";
do
echo "J'aime $i."
done
====do while ====
*Syntaxe :
#include
int main(void)
{
int i;
do{
printf("%d\n",i);
i++;
}while(i<10);
}
===Spécificité de do while ===
la boucle "do while" exécute toujours au moins une fois l'instruction
*Comparaison avec autres types de boucle :
#include
int main(void)
{
int i; //déclaration
for(i=0;i<0;i++)
{
printf("%d\n",i);
}
i=0; // remise à zéro de i
printf("\n"); //imprimer un retour à la ligne
do{
printf("%d\n",i);
i++;
}while(i<0);
}
gcc -o main.x main.c; ./main.x;
0
=====Conditions logiques =====
===1 (ou autres chiffres) : vrai ===
#include
int main(void)
{
char lettre='a';
if(lettre=='a') printf("IF\n");
}
IF
* De même :
#include
int main(void)
{
if(1) printf("IF\n");
}
IF
===0 faux===
#include
int main(void)
{
if(0) printf("IF\n");
else printf("else\n");
}
else
===Table de vérité===
__OU logique (au moins l'un des deux est vrai) :__
0||0 -> 0
0||1 -> 1
1||0 -> 1
1||1 -> 1
__ET logique (l'un et l'autre est vrai) :__
0&&0 -> 0
0&&1 -> 0
1&&0 -> 0
1&&1 -> 1
===condition logique sur variables===
* OU
#include
int main(void)
{
char lettre='a';
if(lettre=='a'||lettre=='b') printf("VRAI\n");
}
VRAI
* Autre exemple :
#include
int main(void)
{
char lettre='x';
if(lettre=='a'||lettre=='e'||lettre=='i'||lettre=='o'||lettre=='u'||lettre=='y'){
printf("Voyelle\n");
}
else{
printf("Consonne\n");
}
}
Consonne
*ET (il faut deux variables) :
#include
int main(void)
{
char lettre='a';
char lettre2='b';
if(lettre=='a'&&lettre2=='b') printf("VRAI\n");
}
Consonne
VRAI
=====switch ; break et default=====
===Syntaxe ===
switch(nom-variable){
cas1;
cas2;
...;
}
===Exemples ===
#include
int main(void){
char lettre='a';
switch(lettre){
case 'a': printf(Voyelle\n);
case 'z': printf(Consonne\n);
}
}
Voyelle
Consonne
> "case" n'est pas une condition.
>La ligne du "case" définit seulement l'endroit où va commencer l'exécution.
>Dans le cas du "a", il commence à "a" et va jusqu'à "z".
#include
int main(void){
char lettre='z';
switch(lettre){
case 'a': printf(Voyelle\n);
case 'z': printf(Consonne\n);
}
}
Consonne
====Avec break====
#include
int main(void){
char lettre='a';
switch(lettre){
case 'a': printf(Voyelle\n);break;
case 'z': printf(Consonne\n);
}
}
Voyelle
====Avec break et default ====
#include
int main(void){
char lettre='x';
switch(lettre){
case 'a': printf("Voyelle\n");break;
case 'z': printf("Consonne\n");
default : printf("Autre chose\n");
}
}
Autre chose
* Autre exemple :
#include
int main(void)
{
char lettre='x';
switch(lettre){
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y': printf("Voyelle\n");break;
default: printf("Consonne\n");
}
}
Consonne
* Autre syntaxe :
#include
int main(void)
{
char lettre='x';
switch(lettre){
case 'a':case 'e':case 'i':case 'o':case 'u':
case 'y': printf("Voyelle\n");break;
default: printf("Consonne\n");
}
}
witch et plus rapide que if.\\
* commande time pour comparer:\\
gcc if.c; time ./a.out
Puis :
gcc switch.c; time ./a.out
====break et continue ====
__**break permet de quitter n'importe quel programme !**__
#include
int main(void){
while(1){
printf("1\n");
break;
printf("2\n");
}
}
__**continue permet de repartir au début de la boucle !**__
* Autre boucle infinie :
#include
int main(void){
while(1){
printf("1\n");
continue;
printf("2\n");
}
}
====scanf====
Même usage que la commande Linux read.
===Syntaxe ===
scanf("%type",&nom-variable);
===Exemple ===
#include
int main(void)
{
char lettre; //déclaration, (on enlève l'initialisation; char lettre='y')
printf("entre une lettre, svp :");
scanf("%c",&lettre);
switch(lettre){
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y': printf("Voyelle\n");break;
default: printf("Consonne\n");
}
}
=====Fonctions =====
====Fonction "main" et fonction utilisateur ====
* Reprenons le code de base :
#include
int main(void)
{
printf("Bonjour\n");
}
* On peut utiliser une fonction pour afficher :
Une fonction se déclare entre le "#include" et le "int main(void){
#include
void FONCTION(){
instruction
}
int main(void)
{
FONCTION();
}
>Ce qui est à gauche d'une fonction, c'est ce que retourne une fonction.
>On met ''void'' quand on veut qu'elle ne retourne rien; c'est-à-dire qu'il n'y aura pas d'argument à la fonction.
===exemple ===
#include
void bonjour(){
printf("Bonjour\n");
}
int main(void)
{
bonjour();
}
Bonjour
> On peut aussi inscrire : **''void bonjour(void){''**.
#include
> ce qui commence par un "#" sont des instructions pour le compilateur
> "include" : inclure -> inclure le fichier "stdio.h"
> c'est un fichier qui contient des commandes
> une commande comme printf se trouve dans le fichier "stdio.h"
====Passer des éléments à une fonction ====
===explications===
* Sans fonction, inverser les valeurs de deux variables :
#include
//void inverser(void){
//}
int main(void)
{
int a=1;
int b=2;
printf("a:%d\nb:%d\n",a,b);
//inverser();
int c=a;
a=b;
b=c;
printf("a:%d\nb:%d\n",a,b);
}
a:1
b:2
a:2
b:1
===L'appel de la fonction exécute la fonction avec les valeurs de la dernière fonction ===
Les valeurs des variables déclarées dans la fonction "inverser", ne sont pas enregistrées en mémoire, tant que la fonction "main" n'a pas appelé la fonction "inverser".\\
__Rappel__ : **la fonction "main" est toujours exécutée en premier**.
#include
void inverser(int x, int y){
printf("\t\tx:%d\ty:%d\n",x,y);
int z=x;
x=3;
y=4;
printf("x:%d\ny:%d\n",x,y);
}
int main(void)
{
int a=1;
int b=2;
printf("\t\ta:%d\tb:%d\n",a,b);
inverser(a,b);
printf("\ta:%d\n\tb:%d\n",a,b);
}
a:1 b:2 //exécution de ligne n°13
x:1 y:2 //exécution de ligne n°3
x:3 //exécution de ligne n°7
y:4 //idem
a:1 //exécution de ligne n°15
b:2 //idem
>La fonction "inverser" a créé deux emplacements "int" en mémoire ("x" et "y").
>Lors de l'exécution de la ligne n°3, la fonction "inverser" "récupère" les valeurs des emplacements "int" de la fonction "main", dans l'ordre d'enregistrement.
>Lors de l'exécution de la ligne n°15 la fonction "main" utilise les valeurs des emplacements "int" de la fonction "inverser".
>Cette "récupération", n'en est pas exactement une.
>__Rappel__ : dans une même fonction, quand on réaffecte une même variable, par une nouvelle valeur, l'ancienne valeur est écrasée, et c'est la dernier valeur qui est conservée en mémoire. Pour une même variable, chaque nouvelle affectation écrase en mémoire l'ancienne valeur, ainsi une même variable peut changer de valeur au cours du programme ("une variable varie").
>Au niveau des fonctions, quand il y en a plusieurs, ce ne sont pas les noms des variables de chacune des fonctions qui sont conservés en mémoire, mais c'est le TYPE de variable et le nombre de variables de ce TYPE qui sont pointés en mémoire.
>À la fin de l'exécution d'une fonction, toutes les variables de cette fonction sont écrasés, pour l'exécution de la fonction suivante. Mais lors cet écrasement, les variables de la nouvelle fonction de même TYPE que celles de la fonction écrasée sont enregistrés au même endroit : "la valeur d'un type de variable", joue le rôle de pointeur, d'une fonction à l'autre.
=== Créer une fonction "inverser"===
* x et y de la fonction "inverser" utilisent les valeurs de a et b de la fonction main :
void inverser(int x, int y){
printf("\t\tx:%d\ty:%d\n",x,y);
}
int main(void)
{
int a=1;
int b=2;
printf("\t\ta:%d\tb:%d\n",a,b);
int c=a;
a=b;
b=c;
inverser(a,b);
}
a:1 b:2
x:2 y:1
* Il suffit donc de donner aux variables "int" de la fonction "inverser", les mêmes noms que ceux des variables "int" du "main" dont elle récupère les valeurs :
void inverser(int a, int b){
printf("\t\ta:%d\tb:%d\n",a,b);
}
int main(void)
{
int a=1;
int b=2;
printf("\t\ta:%d\tb:%d\n",a,b);
int c=a;
a=b;
b=c;
inverser(a,b);
}
a:1 b:2
a:2 b:1
>Bien considérer que "a" et "b" de la fonction "inverser", ne sont pas les "mêmes" variables dans la mémoire vive; il y a un emplacement mémoire pour chacune des variables "a" et "b", de chacune des fonctions "inverser" et "main".
* Ce qui revient au même (en plus propre) que :
void inverser(int a, int b){
printf("\t\ta:%d\tb:%d\n",a,b);
int c=a;
a=b;
b=c;
printf("\t\ta:%d\tb:%d\n",a,b);
}
int main(void)
{
int a=1;
int b=2;
inverser(a,b);
}
a:1 b:2
a:2 b:1
=====Les pointeurs =====
====Définitions====
__**Un pointeur est un objet Lvalue**__((left value : tout objet pouvant être placé à gauche d'un opérateur d'affectation.)) dont la valeur est égale à l'adresse d'un autre objet.\\ On déclare un pointeur par l'instruction : **''type *nom-du-pointeur;''**, où "type" est le type de l'objet pointé.\\
Cette déclaration déclare un **identificateur**, nom-du-pointeur, associé à un objet dont la **valeur est l'adresse d'un autre objet de type "type"**.\\
L'**identificateur nom-du-pointeur** est donc en quelque sorte un **identificateur d'adresse**. Comme pour n'importe quelle Lvalue\\
__Une **Lvalue** est caractérisée par__ :
* **son adresse**, c'est-à-dire l'adresse-mémoire à partir de laquelle l'objet est stocké ;
* **sa valeur**, c'est-à-dire ce qui est stocké à cette adresse; sa valeur est modifiable.
Si le compilateur a placé la variable **''i''** à l'adresse 4831836000 en mémoire, et la variable **''j''** à l'adresse 4831836004, on a :
^objet ^adresse ^valeur ^
|i | 4831836000 | 3 |
|j | 4831836004 | 3 |
* Deux variables différentes ont des adresses différentes.\\
L'affectation **''i = j;''** n'opère que sur les **valeurs** des variables.\\
Les variables i et j étant de type **''int''**, elles sont stockées sur 4 octets.\\
Ainsi la valeur de i est stockée sur les octets d'adresse 4831836000 à 4831836003.\\
* Pour **un pointeur sur un objet de type char**, la valeur donne l'adresse de l'octet où cet objet est stocké.
* **L'opérateur ''&''** permet d'accéder à l'adresse d'une variable.\\
Toutefois **''&i''** n'est pas une "Lvalue" mais une "constante" : on ne peut pas faire figurer **''&i''** à gauche d'un opérateur d'affectation.\\
Pour pouvoir manipuler des adresses, on doit donc recourir un nouveau type d'objets, les **pointeurs**.
* **L'opérateur unaire d'indirection ''*''** permet d'accéder directement __à la valeur de l'objet pointé__.\\
Ainsi, si **''p''** est un pointeur vers un entier **''i''**, **''*p''** désigne la **''valeur de i''**.
===Exemple===
#include
main()
{
int i = 3;
int *p;
p = &i;
printf("*p = %d \n",*p);
}
*p = 3
On se trouve dans la configuration :
^objet ^adresse ^valeur ^
|i | 4831836000 | 3 |
|p | 4831836004 | 4831836000 |
|*p | 4831836000 | 3 |
Pour aller plus loin, voir [[https://www.rocq.inria.fr/secret/Anne.Canteaut/COURS_C/chapitre3.html]]
====Créer une fonction "inverser" avec des pointeurs ====
#include
void inverser(int *x, int *y){
int c;
c=*x; //"c" correspond à ce qui est pointé par "x" (valeur de "a": 1)
*x=*y; //ce qui est pointé par "x" ("a") correspond à ce qui est pointé par "y" ("b" :2)
*y=c; // ce qui est pointé par "y" ("b") correspond à "c" (1)
}
int main(void)
{
int a=1;
int b=2;
printf("\t\ta:%d\tb:%d\n",a,b);
inverser(&a,&b); // la première variable pointée (*) dans la fonction "inverser"
// prend la valeur de la première variable adressée (&), ici a qui vaut 1
// la deuxière variable pointée, prend la valeur de la deuxième variable adressés, b=2
printf("\t\ta:%d\tb:%d\n",a,b);
}
a:1 b:2
a:2 b:1
__**Et le scanf !**__\\
* Il y a aussi un "et commercial" (&) dans le scanf.\\ C'est aussi un pointeur.
#include
int main(void)
{
char lettre; //déclaration, (on enlève l'initialisation; char lettre='y')
printf("entre une lettre, svp :");
scanf("%c",&lettre);
switch(lettre){
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y': printf("Voyelle\n");break;
default: printf("Consonne\n");
}
}
* **''&lettre''** : Ce qu'on entre est enregistré à l'adresse de la variable "lettre" qui n'a pas été affectée d'une valeur.\\
====tableau bis ====
Un tableau est pointeur qui pointe vers le premier élément du tableau.
===tableau int===
#include
int main(void){
int tab[10];
tab[0]=10;
tab[1]=20;
tab[2]=30;
printf("%d\t%d\t%d\n",tab[0],tab[1],tab[2]);
printf("%d\n",*(tab));
printf("%d\n",*(tab+1));
printf("%d\n",*(tab+2));
printf("%d\n",*(tab+3));
printf("\n");
*(tab+2)=60;
printf("%d\n",tab[2]);
printf("\n");
tab[2]=55;
printf("%d\n",*(tab+2));
printf("%d\n",tab[2]);
}
10 20 30
10
20
30
0
60
55
>**''*tab''** : ce qui est pointé par tab
>**''tab[0]''** : premier élément du tableau
>**'' *(tab+2)''** et **''tab[2]''** ont la même valeur, on peut modifier la valeur par le biais de **''tab[2]''** ou de **'' *(tab+2)''**.
>**''*(tab+1)''** : premier élément du tableau + 4 octets (entier sur 4 octets), c'est-à-dire valeur du deuxième élément du tableau (le premier est ''tab[0]'' ou ''*(tab+0)'' )
>**''*(tab+2)''** : premier élément du tableau + 8 octets, c'est-à-dire valeur du troisième élément du tableau.
> etc.
===tableau char===
#include
int main(void){
char tab[27];
tab[0]='a';
tab[1]='b';
tab[3]='c';
tab[4]='d';
tab[5]='e';
tab[6]='f';
tab[7]='g';
tab[8]='h';
tab[9]='i';
tab[10]='j';
tab[11]='k';
tab[12]='l';
tab[13]='m';
tab[14]='n';
tab[15]='o';
tab[16]='p';
tab[17]='q';
tab[18]='r';
tab[19]='s';
tab[20]='t';
tab[21]='u';
tab[22]='v';
tab[23]='w';
tab[24]='x';
tab[26]='y';
tab[27]='z';
printf("%c\t %c\t %c\t %c\t %c\t %c\n",tab[0],tab[5],tab[9],tab[15],tab[21],tab[26]);
*(tab+0)='A';
tab[5]='E';
printf("%c\t %c\n",tab[0],*(tab+5));
}
a e i o u y
A E
* Idem en mieux (pour mémoire dure) :
#include
int main(void){
char tab[27]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
printf("%c\t %c\t %c\t %c\t %c\t %c\n",tab[0],tab[5],tab[9],tab[15],tab[21],tab[26]);
*(tab+0)='A';
tab[5]='E';
printf("%c\t %c\n",tab[0],*(tab+5));
}
=====fonction bis =====
====bibliothèque stdio.h ====
===fonction int et commande sizeof ===
Un entier à une taille en octet.
#include
int main(void){
printf("%d\n",sizeof(int));
}
4
**Cela permet de comprendre l'utilisation de [[http://www.table-ascii.com/|la table ASCII]].**\\
On pourrait faire :
#include
int main(void){
printf("%d\n",sizeof(char));
}
1
>1 octet = 8 bit
>8 bits permettent de coder 255 caractères différents.
>char peut donc "contenir la table ASCII qui va pour le code décimal des caractères alphanumériques (+des caractères spéciaux) qui va de 0 à 255.
#include
int main(void){
int lettre=97;
printf("%c\n",lettre);
}
a
===Pourquoi la fonction "main" renvoie-t-elle à un "int" ? ===
Surtout qu'elle peut contenir des "char" !
Rappel : "void" : quand la fonction ne retourne rien.
#include
int somme(int x,int y){
int result;
result=x+y;
return result;
}
int main(void){
int addition;
addition=somme(2,3);
printf("%d\n",addition);
}
5
* ou en raccourci :
#include
int somme(int x,int y){
int result;
result=x+y;
return result;
}
void main(void){
int addition;
int var1=2;
int var2=3;
addition=somme(var1,var2);
printf("%d\n",addition);
}
>On affecte la variable "addition" de la fonction "somme" car elle a un "return".
> On met **''int main(void){''** car il possible de faire renvoyer des information par la fonction "main".
> Quand elle ne renvoie rien on peut aussi mettre **''void main(void){''**.
>**C'est au système d'exploitation que le "int" renvoie des informations**.
===Se servir du "int" dans la fonction "main"===
#include
int somme(int x,int y){
int result;
result=x+y;
return result;
}
int main(void){
int addition;
int var1=2;
int var2=3;
addition=somme(var1,var2);
printf("%d\n",addition);
return 0;
}
gcc -o fct.x fct.c; ./fct.x; echo $?
5
0
> 0 est le code de retour.
====Bibliothèque string.h====
===fonction strcpy ===
Elle permet d'utiliser la fonction **''strcpy''**.
Cette fonction "strcpy" permet la manipulation des chaînes de caractères.
strcpy(nom-de-la-variable-declaree,"nlle-valeur");
#include
#include
int main(void){
char nom[5]="toto";
strcpy(nom,"tata");
printf("%s\n",nom);
}
tata
=> Voir le fichier "string.h" pour voir quelle autre fonction il contient.
===fonction strcat===
Elle permet de rajouter à la suite.\\
"cat", comme "concaténer" !
#include
#include
int main(void){
char nom[15]="bonjour";
strcat(nom," toto");
printf("%s\n",nom);
}
bonjour toto
===for dans chaîne de caractères===
#include
#include
int main(void){
char nom[25]="Hello";
strcat(nom," Toto, are you ok ?");
int i;
for(i=0;i!=25;i++){
printf("nom[%d]=%c\n",i,nom[i]);
}
printf("\n");
}
nom[0]=H
nom[1]=e
nom[2]=l
nom[3]=l
nom[4]=o
nom[5]=
nom[6]=T
nom[7]=o
nom[8]=t
nom[9]=o
nom[10]=,
nom[11]=
nom[12]=a
nom[13]=r
nom[14]=e
nom[15]=
nom[16]=y
nom[17]=o
nom[18]=u
nom[19]=
nom[20]=o
nom[21]=k
nom[22]=
nom[23]=?
nom[24]=
> L'espace réservé peut-être plus large que les éléments.
===Fonction strcmp===
Elle permet de comparer.
#include
#include
int main(void){
char nom[10]="Hello b";
printf("%d\n",strcmp(nom,"Hello"));
}
32
=====Les structures =====
Elles permettent d'utiliser plusieurs types de variable dans le "main".
====Syntaxe ====
===Création d'une structure===
* **Dans le "struct"** : \\ On crée une structure constituée de plusieurs types de variable afin de pouvoir tous les utiliser dans un seul "main".\\ __Pour ce faire__,\\ - on utilise la commande **''struct''**,\\ - on nomme la structure qu'on crée,\\ - enfin entre les accolades ouvrante et fermante, on annonce chacun des types de variables qui compose la structure.\\ Ne pas oublier le __point-virgule__ après l'accolade fermante de **''struct''**.\\
* **Dans le "main"**:\\ on __associe__ à chaque variable déclarée, un __type de variable permis__ par la création de la structure.\\ **''var.type''** : Le point permet "d'associer" à "var", un type de variable annoncé dans le **''struct''**.\\ C'est **''var.type''** qu'on affecte __d'une valeur__ : **''var.type=valeur''**.\\ C'est donc **''var.type''** qui permet d'__appeler la valeur__ qu'on lui a affecté : **''("%type",var.type); ''**.
#include
#include
struct nom-structure{
type-chaine;
type-caractère[n];
type-entier;
};
int main(void){
struct nom-structure var
strcpy(var.type-chaine,"chaine de caractère");
var.type-caractère='c';
var.type-entier=n;
printf("%s",var.type-chaine)
printf("%c",var.type-caractère)
printf("%d",var.type-entier)
}
====Exemple ====
#include
#include
struct earthborn{
char sex;
char name[20];
int age;
};
int main(void){
struct earthborn person1;
person1.age=78;
person1.sex='M';
strcpy(person1.name,"Paul Dupont");
printf("age:%d\t sex:%c\t name:%s\n",person1.age,person1.sex,person1.name);
struct earthborn person2;
person2.age=84;
person2.sex='F';
strcpy(person2.name,"Agath Montsoirie");
printf("age:%d\t sex:%c\t name:%s\n",person2.age,person2.sex,person2.name);
}
age:78 sex:M name:Paul Dupont
age:84 sex:F name:Agath Montsoirie