C

Exemples de code C pouvant être réutilisé librement tant que l'auteur est cité :)

Allouer dynamiquement un tableau à deux dimensions avec uniquement deux malloc

Ce qu'il ne faut pas faire

Beaucoup de gens font un truc du genre :

int **createTable(int nbLin, int nbCol){
int **tab;
 
/* Allocation de la 1er dimension */
    tab = (int **)malloc ( sizeof(int *)  *  nbLin);
/* Allocation 2e dimension */
    for (int i = 0 ; i < nbLin ; i++){
        tab[i] = (int *)malloc (sizeof(int) * nbCol);
    }

Ce qui demande nbLin+1 malloc (c'est moche). Il faut savoir que l'allocation mémoire est considérée comme une action lente.

Ce qu'il faudrait faire

Une autre méthode consiste à allouer la première dimension comme dans l'exemple précédent, et a allouer d'un seul bloc, tout le reste.

#include <stdlib.h>
#include <stdio.h>
 
int **createTable(int nbLin, int nbCol){
	int **tableau = (int **)malloc(sizeof(int*)*nbLin);
	int *tableau2 = (int *)malloc(sizeof(int)*nbCol*nbLin);
	for(int i = 0 ; i < nbLin ; i++){
		tableau[i] = &tableau2[i*nbCol];
	}
	return tableau;
}
 
void freeTable(int **tableau){
	free(tableau[0]);
	free(tableau);
}

Pourquoi ?

Voici un tableau du type int tab[5][6]

Un tableau a deux dimensions ça marche comment ? (à pied)
Cela équivaut à créer une premiere dimension (en rouge à gauche), et chaque case de cette première dimension va pointer vers un tableau (vers la première case du tableau) de dimension inférieure. Il est donc possible de faire des tableaux de dimension n > 3.

Merci à ar0x qui m'a fait découvrir cette possibilité :)

Fichier attachéTaille
Icône image tab2dim.png7.95 Ko

Allouer dynamiquement un tableau à deux dimensions avec uniquement un malloc

En faite je reprend le même principe que pour deux malloc, mais en allouant le tout en une seule fois !!!
Puis ensuite, il s'agit de jouer avec les pointeurs !!!

En terme de complexité c'est toujours la même o(lignes), sans compter le temps d'allocation de la mémoire !!!
Et puis pour la libération des ressources, il y a juste un seul free à faire ^^

#include "stdlib.h"
 
int** allocation(int lignes, int colones)
{
    int** tableau;
    int* data;
    int i;
 
    if(lignes <= 0 || colones <= 0)
    {
        return NULL;
    }
 
    tableau = (int**) malloc(lignes*colones*sizeof(int) + lignes*sizeof(int*));
    if(tableau == NULL)
    {
        return NULL;
    }
 
    for(i=0,data=(int*)(tableau+lignes); i<lignes; i++,data+=colones)
    {
        tableau[i] = data;
    }
 
    return tableau;
}
 
void desallocation(int** memoire)
{
    free(memoire);
}
Fichier attachéTaille
Icône texte brut malloc.c.txt965 octets

Allouer dynamiquement un tableau à n dimensions avec uniquement un malloc

Voici le code de la fonction array_alloc qui perment d'allouer un tableau de dimention n.
Le premier argument qu'elle prend c'est le nombre de dimention du tableau.
Le deuxième c'est un tableau contenant la taille de chaque dimention.
Le dernier argument désigne la taille du type avec lequel on rempliera la tableau.

#define PTR_SIZE sizeof (void*)
 
void* array_alloc(int n, int tab[], size_t elemSize) {
	int i, j;
	int pro;
	int sum;
	size_t dataSize;
	size_t blocSize = 0;
	void* ptrAlloc;
 
	void *ptrBase, *ptrP;
 
	if (tab == NULL || n == 0 || elemSize == 0) {
		return NULL;
	}
	if (n == 1) {
		return malloc(tab[0] * elemSize);
	}
	sum = 0;
	pro = 1;
	for (i = 0; i < n - 1; i++) {
		pro *= tab[i];
		sum += pro;
	}
 
	blocSize = sum * PTR_SIZE + pro * elemSize * tab[i];
 
	if ((ptrAlloc = malloc(blocSize)) == NULL) {
		return NULL;
	}
	ptrBase = ptrP = ptrAlloc;
	for (i = 0, pro = 1; i < n - 1; i++) {
		pro *= tab[i];
		ptrBase += pro * PTR_SIZE;
		dataSize = (i == n - 2) ? elemSize : PTR_SIZE;
		for (j = 0; ptrP < ptrBase; ptrP += PTR_SIZE, j++){
			*((void**) ptrP) = ptrBase + tab[i + 1] * j * dataSize;
		}
	}
	return ptrAlloc;
}

Allouer statiquement un tableau de taille variable

En fait il est tout a fait possible d'allouer statiquement un tableau dont la taille n'est connue qu'a l'exécution. Pour cela, il faut faire du c99 !!! -std=c99

Et on peut tout simplement écrire :

int taille = 5;
int tableau[taille];

Et pour les tableau à plusieurs dimensions, on peut faire:

void utilisatonTableau(int x, int y) {
    int tableau[x][y];
}

Ceci évite les problèmes d'allocation, mais ne permet pas de l'utiliser en dehors du domaine de validité de la variable le déclarant.

Calcul rapide de puissance de 2

Ce qu'il ne faut pas faire

Encore une fois, il y a la méthode > (private joke inside) qui consiste à faire une boucle du genre :

int puissance2(int puissance){
	unsigned int resultat = 1;
	for (int i = 0 ; i<puissance ; i++){
		resultat *= 2;
	}
	return resultat;
}

Temps d'execution: o(puissance)

C'est moche... Pourquoi c'est moche ? Parce que le programme effectue pour calculer 2^n, n multiplication. Temps moyen par multiplication : 5 à 6 cycles d'horloges, soit n*6 ça peut faire beaucoup).

Ce qu'il faudrait faire

Petit rappel sur la numération binaire :
binaire => décimal
0 =>0
1 =>1
10 => 2
11 => 3
100 => 4
1000 => 8
10000 => 16

Il suffit donc pour calculer une puissance de 2 de faire des décalage a gauche comme suit :

unsigned int puissance2(int puissance){
	return 1 << puissance;
}

Temps d'exécution : o(1)

Domaine: 

Chargement d'interface gtk avec la libglade (obsolète)

(obsolète) : il faut maintenant utiliser gtkBuilder qui est directement inclue dans gtk

Le code

Petit bout de code illustrant comment charger une interface gtk depuis un fichier .glade

#include <gtk/gtk.h>
#include <glade/glade.h>
 
int main (int argc, char *argv[]){
  GladeXML  *main_window;
  GtkWidget *bouton;
 
  gtk_init (&argc, &argv);
 
  /* charge l'interface depuis le fichier test.glade */
  main_window = glade_xml_new ("test.glade", NULL, NULL);
 
 /* charge le widget nommé bouton depuis l'interface principale */
    bouton = glade_xml_get_widget (main_window, "bouton");
 
    g_signal_connect (G_OBJECT (boutton), "clicked", G_CALLBACK (click01), NULL);
    g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), NULL);
 
  /* lance l'interface */
  gtk_main ();
 
  return 0;
}

Compile ?

Comme souvent pour les librairies utilisées, il faut des options de partout. Et quand il existe plusieurs versions de la librairie c'est encore plus long. Un petit utilitaire permet de faire tout ça tout bien j'ai nommé "pkg-config".

Il se contente d'aller chercher les informations dans le fichier .pc qui va bien (encore faut il qu'il y en ait un, ce qui est le cas pour gtk et libglade).

Pour compiller :

gcc -Wall `pkg-config  --cflags gtk+-2.0 libglade-2.0` -c fichier.c 

Pour linker

gcc -Wall `pkg-config  --cflags --libs gtk+-2.0 libglade-2.0`  fichier.o -o prog 

Clés RSA, chiffrement et déchiffrement avec openssl

Petit code pour chiffrer et déchiffrer des fichiers en RSA avec openssl

Le code génère une paire de clef 4096 bits (qui sont écrites en pem dans le répertoire courant), chiffre un fichier, et le déchiffre (histoire de montrer que ça fonctionne pour de vrai)

gcc -lcrypto -std=gnu99

#include <openssl/rsa.h>
#include <glib.h>
#include <openssl/pem.h>
 
 
gboolean encRSA (RSA *rsa, FILE *fpClr, FILE *fpEnc) {
 
  unsigned char *buffRead, *buffWrite;
  int size;
  gboolean ret = FALSE;
 
  buffRead    = g_malloc(sizeof(unsigned char)*RSA_size(rsa));
  buffWrite   = g_malloc(sizeof(unsigned char)*RSA_size(rsa));
 
 
  while ((size = fread(buffRead, 1, RSA_size(rsa)-11, fpClr)) > 0) {
    size = RSA_private_encrypt (size, buffRead, buffWrite, rsa, RSA_PKCS1_PADDING);
    fwrite (buffWrite, 1, size, fpEnc);
  }
 
 
  ret = TRUE;
 
  return ret;
}
 
gboolean decRSA (RSA *rsa, FILE *fpEnc, FILE *fpClr) {
 
  unsigned char *buffRead, *buffWrite;
  int size;
  gboolean ret = FALSE;
 
  buffRead    = g_malloc(sizeof(unsigned char)*RSA_size(rsa));
  buffWrite   = g_malloc(sizeof(unsigned char)*RSA_size(rsa));
 
 
  while ((size = fread(buffRead, 1, RSA_size(rsa), fpEnc)) > 0) {
    size = RSA_public_decrypt (size, buffRead, buffWrite, rsa, RSA_PKCS1_PADDING);
    fwrite (buffWrite, 1, size, fpClr);
  }
 
 
  ret = TRUE;
 
  return ret;
}
 
int main(int argc, char *argv[]){
  FILE *fpPriv, *fpPub;
  FILE *fpLicenceClr, *fpLicenceEnc, *fpLicenceDbg;
 
  RSA *rsaPub = NULL;
  RSA *rsaPriv = NULL;
 
  if (argc != 6){
    fprintf(stderr, "USAGE : %s filePubKey filePrivKey clearLicence cypheredLience testClrLience\n", argv[0]);
 
    return -1;
  }
 
  if((fpPub = fopen(argv[1], "r")) == NULL){
    fprintf(stderr, "Could not open %s\n", argv[1]);
    return -1;
  }
 
  if((fpPriv = fopen(argv[2], "r")) == NULL){
    fprintf(stderr, "Could not open %s\n", argv[2]);
    return -1;
  }
 
  if((fpLicenceClr = fopen(argv[3], "r")) == NULL){
    fprintf(stderr, "Could not open %s\n", argv[3]);
    return -1;
  }
 
  if((fpLicenceEnc = fopen(argv[4], "w")) == NULL){
    fprintf(stderr, "Could not open %s\n", argv[4]);
    return -1;
  }
 
 
  if((fpLicenceDbg = fopen(argv[5], "w")) == NULL){
    fprintf(stderr, "Could not open %s\n", argv[5]);
    return -1;
  }
 
  PEM_read_RSAPrivateKey (fpPriv, &rsaPriv, 0, NULL);
  PEM_read_RSAPublicKey  (fpPub, &rsaPub, 0, NULL);
 
  printf(">>%p %p\n", rsaPub, rsaPriv);
 
  encRSA (rsaPriv, fpLicenceClr, fpLicenceEnc);  
 
  fclose(fpLicenceEnc);
  if((fpLicenceEnc = fopen(argv[4], "r")) == NULL){
    fprintf(stderr, "Could not open %s\n", argv[4]);
    return -1;
  }
 
  decRSA (rsaPub, fpLicenceEnc, fpLicenceDbg);  
 
 
  fclose(fpPub);
  fclose(fpPriv);
  fclose(fpLicenceClr);
  fclose(fpLicenceEnc);
  fclose(fpLicenceDbg);
 
 
 
  return 0;
}
Domaine: 

Comment protéger ses ".h" de l'inclusion multiple

Faire du travail propre

Quand les projets grossissent un peu, une inclusion multiple est très vite arrivée.
schema inclusion multiple
Le fichier "plop.h" est inclut plusieurs fois dans "test.c" ce qui pose des problème de redéfinition de symboles.

Comme c'est le préprocesseur qui plante, c'est aussi avec lui que nous allons résoudre le problème. Nous allons faire un test sur une constante, si celle ci n'est pas définie nous pouvons inclure le code et définir la constante en question. Il suffit de mettre le corps du fichier ".h" dans

#ifndef __FICHIER_H__ /* si la constante __FICHIER_H__ n'est pas defini entrer dans l'espace */
#define __FICHIER_H__ /* definit la constante __FICHIER_H__ */
 
/* corps du fichier .h */
 
#endif /* __FICHIER_H__ */

Se la couler douce sous Visual Studio (c)

Attention ce qui suit est uniquement valable pour Visual Studio (c). Car ces instructions préprocesseur sont spécifiques aux compilateurs Microsofts (c)

Il suffit de mettre a la première ligne du fichier ".h" le code suivant

#pragma once
 
/* corps du fichier .h */

C'est plus court, mais c'est pas portable!!!

Convertir string en nombre

Convertir une chaîne de caractères en int (nombre)

Fichiers entête à inclure :

#include <stdlib.h>
#include <errno.h>
 int string2int (char *eugeni){
   errno  = 0;
   int t = strtol (eugeni, NULL, 10);
   if (errno == ERANGE || errno != 0) {
     perror ("strtol");
     exit (EXIT_FAILURE);
   }
   return t;
 }
 

Convertir chaine de caractères en double

 double string2double(char *eugeni){
   errno  = 0;
   double t = strtod(eugeni, NULL);
   if (errno == ERANGE || errno != 0) {
     perror("strtod");
     Err(__FILE__, __LINE__, Le nombre nen nest pas un);
     exit(EXIT_FAILURE);
   }
   return t;
 }
 

Convertir chaine de caractères en longlongint

 long long int string2longlongint(char *eugeni){
   errno  = 0;
   long long int t = strtoll(eugeni, NULL,10);
   if (errno == ERANGE || errno != 0) {
     perror("strtoll");
     Err(__FILE__, __LINE__, Le nombre nen nest pas un);
     exit(EXIT_FAILURE);
   }
   return t;
 }

Crypter un fichier avec une clée symétrique

Voilà le but est simple on utilise un XOR pour crypter un fichier bit par bit. La méthode décrite est très simple à casser, en effet la clée du XOR étant sur 1 octect pour être sur de pouvoir le fichier quelque soit sa taille il existe seulement 255 combinaisons pour retrouver le texte (bien que le l'octet égal à 11111111b = 255d soit initule car on réalise simplement une inversion de bits).
Petit rappel sur la table de vérité du XOR :

0 0 0
0 1 1
1 0 1
1 1 0

le programme n'utilise que stdio et stdlib, un man permet d'obtenir des informations sur le fonctionnement des fonctions. A savoir l'opérateur XOR s'écrit ^ en C.

A compiler avec :
gcc -W -Wall -o crypt cryptXor.c pas de -ansi parceque sa sert à rien (en plus ca fera bloquer le compilateur).

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void chiffrer(unsigned char, FILE *,FILE *);
  5.  
  6. int main(int argc, char **argv){
  7. FILE *In, *Out;
  8. unsigned char clee;
  9. int toto;
  10.  
  11. // Validation des arguments de la ligne de commande
  12.  
  13. if(argc !=3){
  14. printf("Usage : %s <source> <destination>\n", *argv);
  15. return 0;
  16. }
  17.  
  18. // Ouverture du fichier en lecture binaire
  19.  
  20. if( (In = fopen(argv[1], "rb+")) == NULL ){ // affectation de In
  21. printf("%s introuvable\n",argv[1]);
  22. return -1;
  23. }
  24.  
  25. // Ouverture en écriture binaire du fichier de destination
  26.  
  27. if( (Out = fopen(argv[2], "rb+")) == NULL ){ // affectation de Out
  28. printf("%s impossible à créer\n",argv[2]);
  29. fclose(In);
  30. return -1;
  31. }
  32.  
  33. // Saisie de la clée (sur 1 octet)
  34. printf("\nEntrez une clée de chiffrement sur 1 octet\n");
  35. scanf("%d",&toto);
  36. if(0 > toto || toto > 255){
  37. printf("Clée incorecte. Attention la clée ne doit pas dépasser 255!\n");
  38. fclose(In);
  39. fclose(Out);
  40. return -1;
  41. }
  42. clee = (unsigned char)toto;
  43. // Chiffrement du fichier
  44.  
  45. chiffrer(clee, In, Out);
  46. fclose(In);
  47. fclose(Out);
  48. printf("Terminé\n");
  49.  
  50. return 0;
  51. }//void main(int, char **)
  52.  
  53. void chiffrer(unsigned char k, FILE *entre, FILE *sort){
  54. unsigned char octet;
  55.  
  56. while( fread(&octet,1,1,entre) ){
  57. octet ^= k;
  58. fwrite(&octet,1,1,sort);
  59. }
  60.  
  61. }// fin chiffrer(unsigned char, FILE *, FILE *)

Effectuer des requêtes sur un serveur mysql

#include "mysql.h"
 
MYSQL *mysqlOpenDB(char *server, char *db, char *user, char *pwd){
	MYSQL *myH;
 
	if(NULL == (myH = mysql_init(NULL))){
		fprintf(stderr, "erreur lors de l'ouverture : %s\n", mysql_error(myH));
	}
 
	if(mysql_real_connect(myH, server, user, pwd, db, 0, NULL, 0) == NULL){
		fprintf(stderr, "erreur lors de la connexion : %s\n", mysql_error(myH));
	}
 
	return myH;
 
}
 
void mysqlExecReq (MYSQL *myH, char *req){
	if(mysql_query(myH, req) != 0){
		fprintf(stderr, "Echec de la requete : %s\n", mysql_error(myH));
		mysql_close(myH);
	}
 
}
 
void mysqlCloseDB(MYSQL *db){
	mysql_close(db);
}

Ligne de compilation

gcc -Wall -lmysqlclient plop.c -o prog

Gestion des signaux

Ce code permet de gérer les signaux de manière simple. Entre autre il permet d'intercepter les Ctrl+C, Segfault, ou autre. Il intercepte tous les signaux sauf le -SIGKILL (-9) qui ne peux etre intercepté.

Le programme

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
 
void signalement(int sig){
    printf("Signal : %d\n" , sig);
}
 
int main(){
    int Nb_Sig;
    printf("Nb max signaux : %d\n", SIGRTMAX); 
    for (Nb_Sig = 1; Nb_Sig < SIGRTMAX ; Nb_Sig ++){
        signal(Nb_Sig,signalement);
    }
    while(1) {
        sleep(1);
    }
}

Pour tester le programme

trax@clubnix $ gcc -Wall signal.c -o prog
trax@clubnix $ ./prog

Puis faire un Ctrl+C ou taper la commande

kill -X pid_de_prog
  • X : le numéro du signal à tester (tout sauf 1 et 9)
  • pid_de_prog : obtenu en tapant la commande
    pgrep -lu votre_login |grep prog 

IMPORTANT :
pour fermer le programme, faire un kill -9 PID_Programme.
Pour trouver le PID "pgrep -lu votre_login", ceci affichera la liste de vos programme.

Macro de debugage et constante preprocesseur

Bien sur il y a gdb mais utiliser la sortie standard peut être utile

Mettre un commentaire différent c'est sympa mais ça peut être lourd à mettre en place

Il existe des constantes préprocesseurs qui peuvent être bien utile :

#define BUG printf("Dans le fichier %s dans la fonction %s à la ligne %d\n",__FILE__, __FUNCTION__, __LINE__)
#define DATE printf("Compile le %s %s\n", __DATE__, __TIME__)
 
#include <stdio.h>
 
 
void plop(){
        BUG;
        printf("%s %s %d\n", __FILE__ ,__FUNCTION__, __LINE__);
}
 
int main(){
        DATE;
 
        plop();
        return 0;
}

Manipuler des tableaux

Voici un tout petit code source qui permet de manipuler des tableaux en C.
Le code est simplissime, cela permet d'avoir une mini bibliothèque/aide mémoire pas loin.
Un bon exercice consisterait à reprendre ce code et y ajouter des nouveaux tris...

tableaux.h :

  1. #ifndef TABLEAUX_H
  2. #define TABLEAUX_H
  3. #define TAILLE 10
  4. void afficheTab(long[], int);
  5. long sommeTab(long[] , int);
  6. double moyenneTab(long[], int);
  7. void copieTab(long[], long[], int);
  8. void clearMaxTab(long[], int taille, long valMax);
  9. void ordonnerTab(long[], int);
  10. void swap(long *, long *);
  11. #endif

tableaux.c

  1. #include <stdio.h>
  2. #include "tableaux.h"
  3.  
  4. int main(){
  5. long tab[TAILLE];
  6. long x = 0.0;
  7. int i;
  8. for(i=0; i<10 ; i++) tab[i]=x++;
  9.  
  10. printf("somme = %ld\r\n",sommeTab(tab, TAILLE));
  11. printf("moyenne = %lf\r\n",moyenneTab(tab,TAILLE));
  12.  
  13. long newtab[TAILLE];
  14. copieTab(tab, newtab, TAILLE);
  15. /*afficheTab(newtab, TAILLE);*/
  16.  
  17. clearMaxTab(tab, TAILLE, 2);
  18. /*afficheTab(tab, TAILLE);*/
  19.  
  20. long newtab2[TAILLE];
  21. for(i=0; i<TAILLE; i++){
  22. printf("\nveuillez entrer un nombre entier :");
  23. scanf("%ld",newtab2+i);
  24. }
  25. ordonnerTab(newtab2, TAILLE);
  26. afficheTab(newtab2, TAILLE);
  27.  
  28.  
  29. return 0;
  30. }
  31.  
  32. /*
  33. * Affiche le contenu d'un tableau sous forme décimale
  34. */
  35. void afficheTab(long tab[], int taille){
  36. int i;
  37. for(i=0; i<taille; i++) printf("tab[geshifilter-questionmarkphp]d] = %ld\r\n&quot;,i,tab[i]);&#10;}&#10;&#10;/*&#10;* Fait la somme de tous les éléments d&#039;un tableau&#10;*/&#10;long sommeTab(long tab[], int taille){&#10; long somme=0;&#10; int i=0;&#10; for(i=0 ; i&lt;taille ; i++) somme+= tab[i];&#10; return somme;&#10;}&#10;&#10;/*&#10;* Fait la moyenne algébrique de tous les éléments d&#039;un tableau&#10;*/&#10;double moyenneTab(long tab[], int taille){&#10; double somme = (double)sommeTab(tab, taille);&#10; return somme/(double)taille;&#10;}&#10;&#10;/*&#10;* Copie le contenu de tab1 dans tab2&#10;* tab2 et tab1 doivent être de taille inférieure à taille1 donnée en paramètre &#10;*/&#10;void copieTab(long tab1[], long tab2[], int taille1){&#10; int i;&#10; for(i=0; i&lt;taille1; i++) tab2[i]=tab1[i];&#10;}&#10;&#10;/*&#10;* Efface tous les éléments du tableau dont la valeur est &lt;= valMax passée en paramètre&#10;*/&#10;void clearMaxTab(long tab[], int taille, long valMax){&#10; int i;&#10; for(i=0; i&lt;taille; i++)&#10; if(tab[i]&gt;valMax) tab[i]=0;&#10;}&#10;&#10;/*&#10;* Range les éléments d&#039;un tableau par ordre croissant&#10;*/&#10;void ordonnerTab(long tab[], int taille){&#10; int j=0;&#10; int i;&#10; while(j&lt;taille){&#10; for(i=0; i&lt;taille; i++)&#10; if ( tab[i] &lt; tab[i+1] ) swap( (tab+i) , (tab+(i+1)) );&#10; j++;&#10; }&#10; &#10;}&#10;&#10;/*&#10;* Echange deux éleménts&#10;*/&#10;void swap(long *ptr1, long *ptr2){&#10; long temp;&#10; temp = *ptr1;&#10; *ptr1 = *ptr2;&#10; *ptr2 = temp;&#10;&#10;}&#10;&#10;

[/geshifilter-questionmarkphp]

Quick sort ou tris rapide

Une des nombreuses implémentations du quick sort (tris rapide).

#include <stdio.h>
void quick(int *, int p, int r);
void quick(int *tab,int debut, int fin){
	int pivot = debut;
	int g = debut;
	int d = fin;
	int tmp;
	do {
		if (tab[g] >= tab[d]){
			tmp = tab[g];
			tab[g] = tab[d];
			tab[d] = tmp;
			pivot = g + d - pivot;
		}
		if (pivot == g){
			d--;
		}else{
			g++;
		}
	}while(g<d);
	if (debut < (g-1)){
		quick(tab, debut, (g-1));
	}
	if (fin > (d + 1)){
		quick(tab, (d+1), fin);
	}
}

Récupérer les arguments de la ligne de commande avec getopt_long

Voici un extrait du code (actuel) de BIDON qui j'espère pourra illustrer un peu l'utilisation de la fonction getopt_long.
Pour les informations sur les informations sur cette fonction :
* man 3 getopt
* http://www.gnu.org/software/libtool/manual/libc/Getopt.html
* http://www.opengroup.org/onlinepubs/000095399/functions/getopt.html
* Le C en action (aux éditions O'Reilly)

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
 
/* The name of this program */
const char* program_name;
 
/* Print infos about program version and authors */
void print_versionInfo()
{
	printf("you are running version %.3lf\n", VERSION);
	printf("this program was developped by %s\n",AUTHORS);
	printf("you can find some information on bidon's project page at %s\n",WEBSITE);
	exit(EXIT_SUCCESS);
}
 
/* Print help an exit with exit code exit_msg */
void print_help(FILE *stream, int exit_msg)
{
	fprintf(stream,"usage : %s [ options ]\n",program_name);
	printf("valid options are :\n");
	fprintf(stream,
	"  -h  --help\t print this message\n"
	"  -s  --server server_name\t	the name of the server you want to connect to\n"
	"  -P  --port port_number\t this not a needed option, you may used it if you want to connecter on port\
#port_number instead of default 5222\n"
	"  -l  --login gid\t login into server_name with gid as your login. You need your full gid.\
i.e. if you are toto and your account is on jabber.clubnix.esiee.fr you need to do :\n \
%s -s jabber.clubnix.esiee.fr -l toto@jabber.clubnix.esiee.fr\n"
	"  -p --passwd password\t it is your password\n"
	"  -r --recipient recipient\t your messages will be sent to recipient"
	"  -v --version\t print version and exit"
	"  -S --SINGLE\t use this if you want to start a user to user chat.\
	by default the chat_mode is set to MUC to allow to connect to a Multi Users Channel\n"
	,program_name);
	exit(exit_msg);
}
 
int main( int argc, char **argv)
{
	int next_option;
	/* A string listing the valid short options letters */
	const char *short_options = "s:P::l:p:r:hvS";
 
	/* An array listing valid long options */
	static const struct option long_options[]=
	{
		{"server",required_argument,NULL,'s'},
		{"port",optional_argument,NULL,'P'},
		{"login",required_argument,NULL,'l'},
		{"passwd",required_argument,NULL,'p'},
		{"recipient",required_argument,NULL,'r'},
		{"help",no_argument,NULL,'h'},
		{"version",no_argument,NULL,'v'},
		{"Single", no_argument,NULL,'S'},
		{NULL, 0, NULL, 0} /* End of array need by getopt_long do not delete it*/
	};
 
	/* You can connect to a serveur in 2 modes :
	 * SINGLE start a conversation with an other user already connected to the server
	 * MUC Multi Users Channel to connect to a chat room
	 */
	typedef enum chat_mode chat_mode;
	enum chat_mode
	{
		SINGLE,	MUC
	};
 
	char *server_name;
	int port;
	char *login_name;
	char *passwd;
	char *recipient;
 
	/* By default chat_mode is set to MUC since we want
	  to managed a chat room */
	chat_mode mode = MUC;
 
	/* Remember the program name to incorporate it in messages. */
	program_name = argv[0];
 
	do
	{
		next_option = getopt_long(argc, argv, short_options, long_options, NULL );
 
		switch(next_option)
		{
			case 's':
			server_name = optarg;
			printf("you will be connected to %s\n",server_name);
			break;
			case 'P':
			if (NULL != optarg)
			{
				port = atoi(optarg);
				printf("you be connected on %s on port %d\n",server_name,port);
			}
			break;
			case 'l':
			login_name = optarg;
			printf("your will be logged as %s\n",login_name);
			break;
			case 'p':
			passwd = optarg;
			printf("use %s as password\n",passwd);
			break;
			case 'r':
			recipient = optarg;
			printf("your messages will be sent to %s\n",recipient);
			break;
			case 'S':
			mode = SINGLE;
			printf("entering in SINGLE chat mode\n");
			break;
			case 'h':
			print_help(stdout, EXIT_SUCCESS);
			break;
			case 'v':
			print_versionInfo();
			break;
			case '?': /* An invalide option has been used,
			print help an exit with code EXIT_FAILURE */
			print_help(stderr, EXIT_FAILURE);
			break;
		}
	}
	while(next_option !=-1);
 
 
	if (optind < argc)
	{
		printf ("this arguments are not reconized: ");
		while (optind < argc)
		printf ("%s ", argv[optind++]);
		printf ("\n");
	}
 
	exit(EXIT_SUCCESS);
}

Normalement avec ces informations vous devriez être en mesure de coder votre fonction getopt_long. Il ne reste plus qu'à parser les variables utilisées pour stocker les résultats de l'appel de main aux autres fonctions.

A noter : On peut aussi utiliser des librairies autres que celles fournies par le projet GNU, comme la Glib qui a l'avantage d'être disponible sur GNU/Linux *-BSD et MS Windows. Voici un article intéressant :
http://www.unixgarden.com/index.php/programmation/dissection-de-glib-l%E...

Régression Linéaire

Suite à un cours de math je me suis qu'il pourrait être intéressant d'implémenter un algorithme de regression linéaire histoire de mieux s'en rappeler (je suis sur qu'il existe pleins d'autres implémentations bien meilleurs). Celle-ci est volontairement non optimisée pour rester le plus lisible possible

Le code suivant charge un fichier sous la forme : "valX valY" (voir bas de page pour une code exemple). Le résultat peut être vérifié grâce gnuplot qui propose aussi une implémentation de cette algorithme.

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
 
int main(int argc, char *argv[]){
 
  FILE *fData;
  float x1, x2;
 
  double moyenneX = 0, moyenneY = 0;
  double moyenneX2 = 0;
  double moyenneXY = 0;
  double a, b;
  int count = 0;
 
  assert (argc == 2);
 
  if ((fData = fopen (argv[1],"r")) == NULL){
	goto err;
  }
 
 
  while (fscanf (fData, "%e %e", &x1, &x2) == 2){
	moyenneX += x1;
	moyenneY += x2;
	moyenneX2 += x1*x1;
	moyenneXY += x1*x2;
	count++;
  }
  moyenneX /= count;
  moyenneY /= count;
  moyenneX2 /= count;
  moyenneXY /= count;
 
  a = (moyenneXY - moyenneX*moyenneY)/(moyenneX2 - moyenneX*moyenneX);
  b = moyenneY - a*moyenneX;
  printf ("a = %e\n", a);
  printf ("b = %e\n",b);
 
  fclose (fData);
 
 
  goto fin;
 err :
  fprintf (stderr, "Erreur\n");
 fin :
  return 0;
}

Code pour générer un fichier de données exemple :

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
int main(int argc, char *argv[]){
  int m;
  FILE *fp;
  assert (argc == 2);
  if ((fp = fopen (argv[1], "w")) != NULL){ 
	for (int i = 0 ; i < 10000 ; i++){
	  m = (rand()%2 == 0)?1:-1;
	  fprintf (fp, "%d %d\n", i, i*2+m*rand()%150);
	} 
  }else{
	fprintf (stderr , "Cannot open file %s\n", argv[1]);
  }
	  return 0;
}
Domaine: 

Saisie de mot de passe masquée

Ce petit bout de code (en grande partie provenant du livre "C en action" d'O'Reilly), permet de saisir un mot de passe en console sans afficher les caractères tapés.
Ce code existe également en syntaxe C++

#define _GNU_SOURCE
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <termios.h>
 
char* get_pwd(){
	char *cr = NULL;
	unsigned int len; 
	struct termios t;
 
	tcgetattr (0, &t);
	t.c_lflag &= !ECHO;
	tcsetattr(0, TCSANOW, &t);
	getline(&cr, &len, stdin);
	cr[strlen(cr)-1] = 0;
	tcgetattr(0, &t);
	t.c_lflag |= ECHO;
	tcsetattr (0, TCSANOW, &t);
	return cr;
}
 
int main(){
	char *mdp;
	mdp = get_pwd();
	printf("ton mot de passe est : %s\n", mdp);
	free(mdp);
	return 0;
}

Test Unitaire (simple)

Vous voulez faire des tests unitaire mais Cunit/JUnit/ les modules intégré a votre IDE vous semble lourd pour de simple test?
Pas de panique! premièrement qu'est-ce que c'est que ces tests unitaire dont j'entend tout le temps parler?

il peut être utile de savoir si votre fonction marche vraiment et souvent vous faites des tests unitaire sans le savoir, prenons notre bonne vielle fonction swap:

badSwap(int a, int b){
        int c = a;
        a = b;
        b = c;
}

pour voir si vous avez pas fait de bêtise, souvent vous faites un rapide test avec des valeurs bidon:

void test_badSwap(){
        int a = 42;
        int b = 1337;
        badSwap(a,b);
        printf("a: %d,  b: %d\n", a, b);
}

la vous voyez que la fonction marche pas et la corriger en conséquence, mais une fois la fonction débugué ces tests passe a l'oubliette!

Pourquoi ne pas tous les garder dans un coin (branch test par exemple) et les exécuter lorsque votre boss passe derrière vous pour montrer que vous faites de bon travail ; )

rendont ça un peu plus convivial (avec des couleurs °.°) grâce a une petite macro:

#define makeTest(test)	if(test()){ \
				puts("\e[1;32m"#test" pass\e[m"); \
			}else{ \
				puts("\e[1;31m"#test" fail\e[m"); \
			}

reste plus qu'a réécrire le test et a le lancer

int test_badSwap(){
        int a = 42;
        int b = 1337;
        badSwap(a,b);
        return (a == 1337) && (b == 42); // la fonction de test doit renvoyer 1 si le test réussi, 0 sinon
}
 
int main(){
        makeTest(test_badSwap);
        return 0;
}

voila! plus de raison de ne pas faire de test unitaire maintenant ; )

bonus: une fonction swap qui marche

#include <stdio.h>
#define makeTest(test)	if(test()){puts("\e[1;32m"#test" pass\e[m");} \
			else{puts("\e[1;31m"#test" fail\e[m");}
void badSwap(int a, int b){
	int c = a;
	a = b;
	b = c;
}
 
void goodSwap(int *a, int *b){
	int c = *a;
	*a = *b;
	*b = c;
}
 
int test_badSwap(){
	int a = 42;
	int b = 1337;
	badSwap(a,b);
 return (a == 1337) && (b == 42);
}
 
int test_goodSwap(){
	int a = 9;
	int b = 666;
	goodSwap(&a,&b);
 return (a == 666) && (b == 9);
}
 
int main(){
	makeTest(test_badSwap);
	makeTest(test_goodSwap);
        return 0;
}

Test de Rabbin Miller (nombre premier)

Petit code effectuant le test de Rabbin-Miller utilisant la librairie de calcul gmp

static int rabbin(int a_, mpz_t p){
 
	mpz_t temp;
	mpz_t r;
	mpz_t a;
	mpz_t q;
	mpz_t pm;
	mpz_t i;
 
	int moinsUn = 0;
 
	mpz_init(temp);
 
	mpz_init_set(r,p);
	mpz_init_set(pm,p);
	mpz_sub_ui(pm,pm,1);
	mpz_init_set_ui(a,a_);
	mpz_init_set_ui(q,0);
 
 
	mpz_sub_ui(r,r,1);
	do{
		mpz_cdiv_q_2exp(r,r,1);
		mpz_mod_ui(temp, r, 2);
		mpz_add_ui(q,q,1);
	}while (mpz_cmp_ui(temp,0) == 0);
	/**
	 * Nous avons q = r2^{pp}
	*/
 
	mpz_powm (a, a, r, p);
 
	if(mpz_cmp_ui(a, 1) == 0){
		return 0; /* le nombre est considere comme premier */
	}
 
	mpz_init_set_ui(i,0);
	while(mpz_cmp(i, q) < 0){
		mpz_powm_ui(a,a,2,p);
 
		if(mpz_cmp(a, pm) == 0){
			moinsUn = 1;
		}else if(mpz_cmp_ui(a, 1) == 0){
			if(moinsUn == 1 || i == i){
				return 0; /* le nombre est considere comme premier */
			}else{
				return -1; /* compose */
			}
		}
		mpz_add_ui(i,i,1);
	}
 
	return -1;
 
}
Domaine: 

Tester si un nombre est premier

Calcul de nombres premiers

Petit test de primalité d'un unsigned long long int (sur x86 archi 32bits cela donne un nombre entre 0 et 18446744073709551616). Un exemple de code sera posté, utilisant la librairie gmp pour des nombres plus grands.

Nous utilisons ici la méthode dite "naïve" qui conciste à calculer les modulos successifs de tous les nombres impairs de 3 à la racine du nombre en question, après avoir testé si le nombre est divisible par 2.

#include <stdio.h>
#include <math.h>
 
unsigned long long int primeTest(unsigned long long int nb){
    unsigned long long int racine = (unsigned long long int)(sqrt(nb))+1;
    unsigned long long int i;
    if(nb == 1){
            return 1;
    }
    if((nb % 2) == 0) {
        return 2;
    }
    for (i = 3 ; i < racine ; i+=2){
        if((nb %i) == 0){
            return i;
        }
    }
    return 0;
}
 
int main(void){
    unsigned long long int nb = 3151468321657; 
    unsigned long long int diviseur;
    if((diviseur = primeTest(nb)) == 0){
        printf("Le nombre %lld est premier\n",nb);
    }else{
            printf("Le nombre %lld est divisible par %lld\n", nb, diviseur);
    }
    return 0;
}

A compiler avec la librairie math (-lm) par exemple :

gcc -Wall -lm test.c -o prog -std=gnu99
Domaine: 

Tri par tas ou Heapsort

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
#define TRUE 1
#define FALSE 0
 
void initTableau(int *tab, int taille){
	int i;
	for(i = 0; i < taille; i++)
		tab[i] = random();
}
 
void swap(int *a, int *b){
	int x = *a;
	*a = *b;
	*b = x;
}
 
char domine( int *tab, int taille, int j ){
 
	if( 2*(j+1)-1 >= taille) /* tab[j] est seul */
		return TRUE;
 
	else if(2*(j+1)-1 == taille-1 && tab[j] >= tab[2*(j+1)-1]) /* tab[j] a 1 descendant et domine */
			return TRUE;
 
	else if(tab[j] >= tab[2*(j+1)-1] && tab[j] >= tab[2*(j+1)]) /* tab[j] a 2 descendants et domine */
			return TRUE;
 
	return FALSE; /* Dans le cas ou tab[j] n'est pas seul et ne domine pas */
}
 
void retablirTas( int *tab, int j, int taille ){
 
	while(!domine(tab, taille, j)){/* I(j) et j domine => tab[0...taille-1] est un tas.*/
 
		if( 2*(j+1) == taille){ /* degre 1 && I(2(j+1)-1) */
			swap(&tab[j], &tab[ 2*(j+1)-1 ]);
			j = 2*(j+1)-1;
		}
 
		else{ /* degre 2 */
			if( tab[ 2*(j+1)-1 ] >= tab[ 2*(j+1) ] ){ /* I(2(j+1)-1) */
				swap( &tab[ 2*(j+1)-1 ], &tab[j] );
				j = 2*(j+1)-1; /* I(j) */
			}
 
			else{ /*I(2*(j+1)) */
				swap(&tab[ 2*(j+1) ], &tab[j]);
				j = 2*(j+1); /* I(j) */
			}
		}
	}
}
 
void faireTas(int *tab, int taille){
	int k;
	for(k = taille-1; k >= 0; k--)
		retablirTas(tab, k, taille);
}
 
int main(){
	int *tab;
	int taille;
	int f;
 
	/* Mesure du temps d'execution*/
	clock_t start, end;
	double elapsed;
 
	printf("Entrer la taille du tableau :\t");
	scanf("%d", &taille);
	f = taille;
 
	if ( ( tab = (int *)malloc( (sizeof(int)*taille)) ) == NULL)
		exit(EXIT_FAILURE);
 
	initTableau(tab,taille);
 
	start = clock(); /* lancement de la mesure */
 
	faireTas(tab, taille);
 
	/* I(f) = tab[0 ... f-1] est un tas
	&& ensemble des elements de tab[0 ... f-1] inferieur ou egal 
	a ensemble des elements tab[f ... taille-1]
	&& tab[f ... taille-1] est trie croissant
	*/
 
	while ( f > 1){ /* I(k) && (k>1)*/
                swap(&tab[0], &tab[f-1]);
                retablirTas(tab, 0, f-1); /* I(k-1) */
                f--;
        }
 
	end = clock(); /* arret de la mesure */
	elapsed =(double)(end-start)/CLOCKS_PER_SEC;
	printf("Temps de calcul : %lf\n",elapsed);
 
	exit(EXIT_SUCCESS);
}

calcul d'une racine carrée

/**
* \file square_root.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
/**
* \def EPSI est la précision recherchée
*/
 
#define EPSI 1.e-6
 
/**
* \brief Algorithme de Newton pour calculer une racine carrée.
* Utilise une boucle do while pour calculer la racine. Deux conditions de sortie de boucle :
* 1 L'erreur comise est <= à EPSI
* 2 Le nombre max d'itérations est atteind.
* NB : Aucun renseignement n'est donné quant à la condition de sortie réalisée ;
* la fonction n'indique pas si e <= EPSI en fin de boucle.
* A est supposé > 0 sinon les calculs n'auraient aucun sens.
*
* \param A Nombre dont on cherche la racine
* \param U sert a stocker le résultat U=0.5*A pour des calculs relativements rapides
* \param V sert a stocker le resultat, contient l'itération suivante
* \param e erreur relative tant que e <= EPSI on continue les calculs
* \param n nombre maximum d'itératons
* \param i compteur de boucle
*/
int main(){
 
	double A,U,V,e;
	int n,i=0;
	printf("A :\t");
	scanf("%lf",&A);
	printf("\nn :\t");
	scanf("%d",&n);
	U=A*0.5;
 
	do{
		V = 0.5*(U+A/U);
		e = fabs((V-U)/V);
		U = V;
		i++;
	}while(e>=EPSI && i<n);
 
	printf("%lf",U);
	return 0;
}
Domaine: 

calcul somme MD5

#include <stdio.h>
#include <string.h>
#include <openssl/md5.h>
 
void mdpCheckSum(const unsigned char *mdp, unsigned char *hash){
    char check[16];
    MD5((const unsigned char *)mdp, strlen((char *)mdp),(unsigned char *)check);
    for (int i = 0; i < 16; ++i){
        sprintf((char *)hash + (i * 2), "%02x", (unsigned char)check[i]);
    }
}
 
int main(){
    unsigned char hash[33];
    const unsigned char *mdp = "plop";
    mdpCheckSum(mdp, hash);
    printf("MD5 de %s : %s\n",mdp, hash);
}
Domaine: 

dumper une stack trace en cas de segfault

Petit bout de code qui bien pratique, imprimer une trace d'exécution en cas de segfault (pour avoir les numéro de lignes utiliser addr2line)

void sigSevHandler(int sig) {
  void *array[10];
  size_t size;
 
  size = backtrace(array, 10);
 
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, 2);
  exit(1);
}
 
 
 
void setStacktraceDumpOnSegfault(){
    signal(SIGSEGV, sigSevHandler);
}
Domaine: 

scanf (légèrement) plus sécurisé

int main() {
  char string[42];
  scanf("%42s%*[^\n]",string);
  /* %42s --> on ne récupère que 42 caractère */
  /* %*   --> on récupère une nouvelle string qu'on ne stockera pas dans une variable */
  /*[^\n] --> tous les caractères sauf le retour à la ligne final */
  return 0;
}