Partage
  • Partager sur Facebook
  • Partager sur Twitter

Foire Aux Questions — langage C

Votre question y est peut-être...

10 mars 2007 à 18:14:45

Ami zéro prépare toi. Cette FAQ est un puissant condensé de savoir accumulé au fil des âges et des topics. Elle est le fruit de difficiles et longues recherches, de fouilles dans des messages oubliés de tous sur ce forum. Elle compte parmis ses rédacteurs originels d'illustres personnages tel que rz0 et bluestorm.

Pour contribuer à cette FAQ, merci de ne pas poster directement ici mais d'aller sur le sujet qui lui est dédié et de faire tes propositions là-bas. Ceci est valide pour les corrections d'erreurs dans les questions déjà existantes comme pour la proposition de nouvelles questions.

Oui ami zéro, tout a été mis en œuvre pour t'en mettre plein les rétines, alors si un jour tu croise au détour d'un sujet, quelqu'un posant une question dont la réponse se trouve ici, n'hésite pas à le rediriger !


Liste des questions :

-
Edité par GuilOooo 5 octobre 2013 à 20:14:11

  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:32:35

[3][1] Pourquoi ne pas utiliser `char' pour stocker des entiers négatifs ? Que faut-il utiliser à la place ?

`char' est un type qui peut ou pas contenir des entiers négatifs selon votre compilateur et votre système.
Il vaut mieux utiliser à la place le type `signed char' qui est assuré de pouvoir contenir des entiers négatifs et positifs.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:35:22

[2][1] Pourquoi ne pas utiliser system("pause") ?

La fonction ``system'' lance un autre programme à travers une ligne de commande.
``PAUSE'' étant un programme spécifique à MS Windows, cette ligne se trouve invalide sur la plupart des systèmes.

De plus, la plupart des systèmes disposant d'une vraie console n'ont pas besoin et n'apprécient pas les pauses en fin de programme ; la console étant un environnement persistant et qui ne se ferme pas comme sous Windows.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:37:29

[2][2] Comment faire une pause de façon portable (sur tous les systèmes) ?

À la place de system("pause"), il est possible d'utiliser la fonction ``getchar'' qui s'appelle ainsi :

#include <stdio.h>

getchar();


Celle-ci lit un caractère au clavier et renvoie le caractère tapé. Vous pouvez donc vous en servir pour demander à l'utilisateur de taper « entrée ». :)
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:38:37

[2][3] Comment effacer la console ?

En C purement standard et portable, on ne peut pas.
Il faut utiliser des commandes ou des fonctions dans des bibliothèques tierces.
Évitez ce genre d'idées pour l'heure, il n'est généralement pas besoin de ça et l'utilisateur n'apprécie pas que l'on lui vide sa console dans la majorité des cas.

Si vous devez vraiment le faire, la bibliothèque conio (sous Windows) et ncurses (sous Unix) peut vous aider.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:41:17

[2][4] Comment afficher du texte à un endroit précis ? Comment effacer
certaines parties de la console ?


De même que la [2][3] (juste au dessus)
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:42:26

[1][1] Pourquoi ``scanf'' est mal ?

Lorsque ``scanf'' lit correctement les entrées, tout se passe à peu près sans peine.
Lorsque l'utilisateur n'entre pas la valeur voulue, ``scanf'' se contente d'arrêter de lire et de tout laisser en plant de sorte que si vous réessayez d'utiliser ``scanf'' à la suite, il tentera de relire ce qu'il n'a pas su lire et laissera à nouveau tout en désordre.
Il faut nettoyer ce que la fonction laisse derrière elle.

Voici un tuto vous expliquant comment vous passer de ``scanf'', et un autre tutoriel pour apprendre à bien s'en servir.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:42:54

[1][2] Pourquoi ``fflush'' ne doit pas être utilisé sur ``stdin'' ?

Tout simplement parce que ce comportement n'est pas défini par le standard, ce qui signifie que tout peut arriver.
C'est donc une très mauvaise idée car le résultat est imprévisible.

Ceci est valide pour n'importe quel flux ou fichier ouvert en lecture, ou sur un fichier en lecture/écriture dont la dernière opération était une lecture. Avec la participation de Pouet_forever.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:46:08

[1][3] Comment enlever les restes de scanf ?

Il faut utiliser une fonction de lecture telle que ``getchar'' en boucle jusqu'à lire le caractère de retour à la ligne `\n'.

void cleanscan(void)
{
   int c;
   do
    {
      c = getchar();
    }
    while (c != '\n' && c != EOF);
}


Vous pouvez aussi utiliser ce code

/* cette ligne enlève tout sauf le caractère `/n' */
scanf("%*[^\n]");
/* c'est cette ligne qui s'en charge */
getchar();
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:47:11

[1][4] Comment récupérer des entiers avec "scanf"/"printf" ? des flottants ?

Il existe un format (une chaîne à donner à ``scanf'') par type de variable que vous souhaitez récupérer.
N'utiliser QUE "%ld" et "%lf" n'apportera que des bogues à vos programmes.

C'est un peu compliqué mais en gros, les entrée marquées "c99 seulement" ne sont pas applicables à VC++, BC++ et la plupart des compilateurs/libc.

Les entiers :



* %hhd signed char (c99 seulement)
* %hhu unsigned char (c99 seulement)
* %d int
* %u unsigned int
* %ld long int
* %lu unsigned long int

Les flottants :



* %f float ou double (printf)
* %f float (scanf)
* %lf double (printf c99 seulement)
* %lf double (scanf)
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 18:48:37

[4][5] Que signifient << et >> ?

Il s'agit d'opérateurs qui permettent de déplacer les bits à l'intérieur d'une variable.
(Voir ce tuto pour comprendre ce qu'est réellement une variable. Puis cet article si vous avez du mal avec le binaire.)

L'opérateur <<x effectue X décalage(s) des bits vers la gauche.
L'opérateur >>x effectue X décalage(s) des bits vers la droite.
L'opérateur <<=x effectue X décalage(s) des bits vers la gauche et stocke le résultat dans l'opérande.
L'opérateur >>=x effectue X décalage(s) des bits vers la droite et stocke le résultat dans l'opérande.

Le code suivant :
unsigned char a, b, c, d;

a = 4; /* Ce qui donne 00000100 en binaire */
b = 6; /* Ce qui donne 00000110 en binaire */

c = a <<2; /* On décale 2 fois vers la gauche */
d = b >>1; /* On décale 1 fois vers la droite */

a >>=2; /* On décale 2 fois vers la droite */
b <<=6; /* On décale 6 fois vers la gauche */

printf("%ld\n", c);
printf("%ld\n", d);
printf("%ld\n", a);
printf("%ld\n", b);

Donnera donc :
16

3

1

128


Il est intéressant de noter que le dernier nombre est bien 128 et pas 129 car il s'agit d'un décalage des bits, pas d'une rotation.
Partant du principe que la taille d'un unsigned char ne dépasse pas 8 bits (ce qui est le cas dans cet exemple), si on avait décalé la variable b d'un cran supplémentaire, elle aurait été égale à 0.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:00:55

[4][2] Pourquoi les divisions ne renvoient que des entiers ?

Les divisions ne renvoient pas que des entiers !

Les divisions renvoient le même type de nombre que ceux qui sont divisés.

Le code suivant :
double a, b, c, d;

a = 5 / 2;
b = 5.0 / 2;
c = 5 / 2.0;
d = 5.0 / 2.0;

printf("%f\n", a);
printf("%f\n", b);
printf("%f\n", c);
printf("%f\n", d);


Donnera :
2.000000

2.500000

2.500000

2.500000
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:02:50

[3][2] Comment définir un caractère ?

Un caractère se déclare/définit avec les types `char' ou `int'.

Le code suivant :
char cara1 = 'a';
int cara2 = 'a';
char cara3 = 97; /* 97 correspond à la lettre a en ASCII */
int cara4 = 97;

printf("%c\n", cara1);
printf("%c\n", cara2);
printf("%c\n", cara3);
printf("%c\n", cara4);

Donnera :
a

a

a

a
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:05:28

[3][3] Comment récupérer la valeur ASCII d'un caractère ?

Deux solutions s'offrent à vous :

- Soit vous allez directement regarder dans la table de correspondance.

- Soit vous utilisez le code suivant :

unsigned char c = 'é'; /* Ici on veut récupérer la valeur de é */

printf("%ld", (long int) c);


Prenez garde à utiliser un unsigned char. Si vous utilisez un char tout court et que vous voulez connaître la valeur d'un caractère contenu dans la "partie étendue" de la table ASCII étendue, il y a de fortes chances que vous obteniez une valeur négative (évidement fausse).

L'exemple ci dessus donnera :
233
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:06:48

[3][4] Comment définir des chaînes de caractères ?

Une chaîne de caractères est un tableau de caractères, dont la dernière case contient la valeur '\0'.

/* La chaîne suivante pourra contenir 19 caractères la dernière case étant réservée au '\0'. */
char s[20];

Il existe différentes manière de remplir une chaîne de caractères lors de sa création.

Le code suivant :
char chaine1[7];

/* On initialise la chaîne 2 dès sa déclaration */
char chaine2[7] = "tagada";

/* On remplit "manuelement" les cases du tableau composant la chaîne 1 */ 
chaine1[0] = 't';
chaine1[1] = 'a';
chaine1[2] = 'g';
chaine1[3] = 'a';
chaine1[4] = 'd';
chaine1[5] = 'a';
chaine1[6] = '\0';

printf("%s\n", chaine1);
printf("%s\n", chaine2);

Donnera :
tagada

tagada
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:09:36

[3][5] Comment comparer des chaînes de caractères ?

On ne peut comparer directement des chaînes de caractères avec l'opérateur `=='. Il faut utiliser ``strcmp'' qui renvoie :

* 0 si les chaînes sont égales
* -1 si la première chaîne est inférieur à la seconde
* 1 si la première chaîne est supérieur à la seconde

Supérieur ou inférieur se réfèrent à l'ordre alphabétique.
Un chaîne commençant par z sera supérieur à une chaîne commençant par i.
Rien à voir donc avec la longueur de ces chaînes.


Le code suivant :
char chaine1[29] = "La tarte au citron c'est bon";
char chaine2[29] = "La tarte au citron c'est bon";
char chaine3[35] = "La tarte au citron c'est delicieux";
char chaine4[27] = "J'adore la tarte au citron";

printf("%s\n", chaine1);
printf("%s\n", chaine2);
printf("%s\n", chaine3);
printf("%s\n", chaine4);

printf("%d\n", strcmp(chaine1, chaine2));
printf("%d\n", strcmp(chaine1, chaine3));
printf("%d\n", strcmp(chaine1, chaine4));


Donnera :
La tarte au citron c'est bon

La tarte au citron c'est bon

La tarte au citron c'est delicieux

J'adore la tarte au citron

0

-1

1


La fonction strcmp est déclarée dans le fichier d'en-tête string.h. Pensez bien à l'inclure si vous l'utilisez !
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:10:51

[3][6] Comment récupérer un caractère avec ``scanf'' ? une chaîne ?

Ce sont les formats "%c" et "%s", respectivement.
Une chaîne de caractères etant un tableau, il n'y a pas besoin de placer un `&' devant le nom de la variable.

À noter que cette méthode n'est pas propre du tout pour les chaînes car si l'utilisateur entre un mot plus long que la taille de votre chaîne... c'est la fin.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:14:59

[3][7] Comment affecter une valeur à une chaîne de caractères ?

À proprement parler, cela n'est pas possible ; pour faire quelque chose de similaire, il faut copier le contenu d'une chaîne dans une autre.
C'est une copie de tableau.

Le code suivant :
/* Ceci n'est possible qu'à la déclaration d'une chaîne, pour l'initialiser. */
char chaine1[29] = "La tarte au citron c'est bon";
char chaine2[35] = "La tarte au citron c'est delicieux";
char chaine3[35] = "La tarte au citron c'est succulent";

printf("%s\n", chaine1);
printf("%s\n", chaine2);
printf("%s\n", chaine3);

/* Cette fonction permet la copie d'une chaîne dans une autre */
/* Le premier argument est la cible et le second la source */
strcpy(chaine2, chaine1);

/* Cette fonction permet la copie d'un certain nombre de caractères d'une chaîne à l'autre */
/* Le dernier argument représente le nombre de caractères à copier */
strncpy(chaine3, chaine1, 27);

printf("%s\n", chaine1);
printf("%s\n", chaine2);
printf("%s\n", chaine3);


Donnera :
La tarte au citron c'est bon

La tarte au citron c'est delicieux

La tarte au citron c'est succulent

La tarte au citron c'est bon

La tarte au citron c'est bon

La tarte au citron c'est bocculent


Les fonctions strcpy et strncpy est déclarée dans le fichier d'en-tête string.h. Pensez bien à l'inclure si vous l'utilisez !
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:18:10

[4][3] Comment obtenir un nombre au hasard ?

Les fonctions liées aux nombres pseudo-aléatoires sont déclarées dans l'en-tête <stdlib.h>.

La première étape est d'initialiser le générateur de nombres pseudo-aléatoires. Il doit être initialisé avec un nombre, et une seule fois. Si ce nombre est le même à chaque exécution du programme, les suites qu'il donnera seront également les mêmes.

C'est pourquoi il faut qu'à chaque exécution du programme un nombre différent soit utilisé pour amorcer le générateur.

Habituellement on utilise le temps pour résoudre ce problème :

#include <stdlib.h>
#include <time.h>

srand(time(NULL));


La fonction ``time" renvoyant le timestamp, hormis si on lance le programme plusieurs fois dans la même seconde, le nombre renvoyé par ``time" n'a que très peu de chances d'être le même plusieurs fois de suite.

Ensuite, il faut utiliser la fonction ``rand'' qui renvoie un nombre entre 0 et ``RAND_MAX''.

Le code suivant:
printf("%d\n", rand());


Affichera... un nombre au hasard compris entre 0 et RAND_MAX.
Pour connaitre la valeur de RAND_MAX, vous pouvez regarder dans le fichier "stdlib.h".

Voir ce tutoriel pour de plus amples détails.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:21:55

[4][4] Pourquoi la fonction ``rand'' me renvoie toujours les mêmes nombres ?

Vous avez probablement mal initialisé le générateur de nombres pseudo-aléatoires. Voir question [4][3].
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:23:58

[4][5] Comment obtenir un nombre aléatoire entre a et b ?

Il existe plusieurs méthodes.
La plus simple est la suivante :

/* Directement tiré du tuto de M@teo21 */
nombreMystere = (rand() % (MAX - MIN + 1)) + MIN;
/* Où MAX et MIN représentent a et b */


Cependant cette méthode n'est pas fiable à 100%.
Pour plus de précisions, consultez ce tuto.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:25:06

[7][1] Comment créer un MMORPG ?

Autant vous prévenir tout de suite...

Si vous vous demandez comment créer un MMORPG juste par curiosité, très bien, lisez ce qui suit et vous en aurez une vague idée.
Si vous lisez cette réponse avec la véritable intention d'en faire un, posez vous les questions suivantes :

  • Sais-je programmer correctement dans le langage que j'ai choisit ?
  • Ais-je de bonnes connaissances d'un moteur 3D ? physique ?
  • Ais-je une expérience des gros projets en programmation ?
  • Ais-je une bonne expérience de la programmation réseaux ?
  • Pourquoi diantre faut il plusieurs années à des équipes de professionnels payés qui ne font que ça de leurs journées pour mettre au point un MMORPG ?


Maintenant voilà quelques liens à visiter dans l'ordre pour comprendre comment ça marche :
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:27:56

[7][2] Comment faire une interface graphique ?

En effet, nativement le langage C propose des fonctions pour manipuler "simplement" la console, mais rien en ce qui concerne les GUI.

Pour cela il vous faudra passer par une bibliothèque.

La plus connue est sans doute GTK+, et bonne nouvelle pour vous, il y a un très bon tuto sur GTK+ ici même.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:29:53

[8][1] Quelle forme de la fonction ``main'' utiliser ?

Il existe deux formes valides de partout :

int main(void);
int main(int argc, char *argv[]);

Contentez-vous de celles-ci, les autres formes ont parfois la même signification que celle-ci mais tant que vous ne comprenez pas précisément ce que vous écrivez, ne modifiez pas ces déclarations.

La forme "void main(void)" n'est pas valide.

Pour de plus amples détails, vous pouvez consulter ce tutoriel.
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:32:50

[8][2] L'instruction `goto' existe-t-elle ? Quand l'utiliser ?

`goto' existe et n'est pas conseillé pour l'utilisation générale.
La règle est en principe que si l'on peut faire sans `goto' et sans rendre le code complètement obscure, tordu, ou trop volumineux, on fait sans.

Citation : Wikipedia

En 1966, le théorème de Böhm et Jacopini a démontré que tout programme comportant des goto pouvait être transformé en programme n'utilisant que des branchements conditionnels ou des boucles.

  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2007 à 19:34:07

[8][3] Comment lancer un autre programme ?

On doit utiliser ``system'' en lui donnant une commande comme on l'aurait entrée dans une console.

system("start mini_1.exe"); //sous DOS/Windows
system("./mini_1"); //sous Unixoïde

Bon c'est sur c'est pas portable, dans le sens où ça compile partout mais ça s'exécute pas forcément bien... Mais à coups de #ifdef ça doit être possible de s'en sortir.
  • Partager sur Facebook
  • Partager sur Twitter
13 mars 2007 à 21:09:17

[5][5] Quelle est la différence entre #include <header> et #include "header" ?

A la base ces deux directives de préprocesseur ont la même fonction : inclure un fichier.

Quand le nom de ce fichier est mit entre <>, cela signifie que le préprocesseur va chercher le fichier dans les répertoires du compilateur prévus à cet effet (appelés répertoires d'inclusion).

Au contraire, quand le nom de ce fichier est mit entre "", cela signifie que le préprocesseur va d'abord chercher le fichier dans le répertoire courant puis éventuellement s'il ne trouve pas, dans les répertoires d'inclusion.
  • Partager sur Facebook
  • Partager sur Twitter
22 avril 2007 à 17:24:27

[5][3] Pourquoi mon programme (développé avec Visual C++ 2005/2008) ne peut-il s'exécuter sur une autre machine que la mienne ?
Par défaut, Visual C++ 2005/2008 linke dynamiquement l'exécutable contre la C Runtime Library (la bibliothèque C de Visual Studio). Il en résulte que le programme obtenu a besoins des DLL de Visual Studio pour fonctionner.

Vous pouvez :

a) installer les DLL de Visual Studio 2005 (ou pour Visual 2008) sur l'ordinateur où votre programme doit être déployé ;

b) configurer votre projet pour que votre exécutable soit linké statiquement contre la C Runtime Library (Project properties -> Configuration -> C/C++ -> Code generation -> Runtime Library -> sélectionner "Multithread (/MT)" au lien de "Multithread DLL (/MD)").

À noter que la solution b) ci-dessus n'est, semble-t-il, pas envisageable si vous compilez un programme utilisant la bibliothèque SDL, vraisemblablement parce que cette dernière a été elle-même linkée dynamiquement avec la C Runtime Library.


Edit: Je n'aime pas trop l'anglicisme "linker" (de l'anglais "to link"), mais je vois pas d'équivalent commode en français ("lier" ne me semble pas trop adapté), donc pour l'instant je laisse comme ça... Si quelqu'un a une idée, qu'il n'hésite pas !
  • Partager sur Facebook
  • Partager sur Twitter
22 avril 2007 à 17:54:15

[1][5] Quand je fais un scanf pour récupérer un nombre, si l'utilisateur tape une lettre, j'ai plein de problèmes. Que faire ?

Vous pouvez consulter lire ce tutoriel qui traite de scanf et de sa bonne utilisation.

Alternativement, vous pouvez vous passer de scanf, par exemple en utilisant fgets pour les entrées. Vous pouvez également consulter cet autre tutorial sur le même sujet.

PS : M@teo21 a lui même écrit quelque chose à ce sujet, c'est une annexe du cours de C. Lire l'annexe du cours de C sur les entrées sécurisées.
  • Partager sur Facebook
  • Partager sur Twitter
J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
Anonyme
23 avril 2007 à 10:43:44

[5][4] Quelle est la différence entre une bibliothèque et une librairie ?
En informatique, une Bibliothèque logicielle est un ensemble de fonctions regroupées pour réaliser un groupe de tâches du même domaine.

Une librairie est un local avec une porte, des fenêtres et des livres à vendre sur des étagères.

Ne confondez pas les deux!

Library, en anglais, est un "faux-ami", qui veux dire bibliothèque. L'erreur vient de là.

Citation : M@teo21 - Le tuto

A noter : le mot anglais est "library" et il se traduit par "bibliothèque". "Librairie" est donc un faux-ami.
En théorie, on devrait donc dire bibliothèque et non librairie. Mais pour ma part, j'ai pris l'habitude d'écrire librairie (et je ne suis pas le seul ;) ) donc je continuerai à utiliser ce terme. Retenez quand même que la traduction exacte est plutôt "bibliothèque".
  • Partager sur Facebook
  • Partager sur Twitter