Si vous avez des suggestions en vue d'améliorer ce site web, veuillez utiliser la rubrique Contact pour m'envoyer un email.

 

 

  

Question 1

Question:

Un des étudiants a posé la question suivante:

J'essaie d'écrire un programme en C pour l'exercice suivant:

 

1- Ecrire une AP Carre vérifiant si un nombre entier naturel est un carré parfait, en utilisant seulement les opérateurs de base, et renvoie sa racine dans le cas favorable. ( Indication : X est un carré parfait s’il existe un entier i tel que X = i * i.)

2- Ecrire un algorithme qui, parmi N entiers naturels, calcule la somme et le produit des racines carrées des entiers carrés parfaits. Ensuite il vérifie si la somme et le produit sont des carrés parfaits.

 

Voici le programme que j'ai ecris mais ce programme ne compile pas.

 

 

#include <stdio.h>

#include <stdlib.h>

 

void carre(int x; int rac; int car)

{

       int i;

 

       i = 0;

       while (i <= (x Div 2))

       {

                if (x == (i * i))

              {

                       car = 1;

                       rac = i;

              }

              else

              {

                       car = 0;

                       i++;

               }

       }

 

        return car;

}

 

int    main() 

{

        int  n, i, s, x, p, car, rac;

 

       do

       {

               printf("Donner un Entier Positif n\n");

               scanf("%d", &n);

       } while (n>0 && n<100);

 

        printf("Donner la suite des nombres\n");

        scanf("%d", &x);

 

        s = 0; p = 0;

        for (i=0; i<=n; i++)

        {

                carre(x, rac, car);

                if (car = 1)

                {

                        s = s + rac;

                        p = p * rac;

                 }

        }

 

       printf("La Somme des Racines Carrees est %d\n", s);

       printf("Le Produit des Racines Carrees est %d\n", p);

 

        carre(s, rac, car);

        if (car = 1)

        {

                 printf("La somme est un carre parfait\n");

        }

        else

        {

                printf("La somme n'est pas un carre parfait\n");

        }

 

        carre(p, rac, car);

        if (car = 1)

        {

               printf("Le produit est un carre parfait\n");

        }

        else

        {

              printf("Le produit n'est pas un carre parfait\n");

        }

 

        return 0;

}

 

Reponse:

 

Erreurs de Compilation

1) Ligne: void carre(int x; int rac; int car)

Les paramètres dans une fonction doivent être separées par une virgule , et non pas par un point virgule ;

Correction: void carre(int x, int rac, int car)

 

2) Ligne: while (i <= (x Div 2))

Il n'ya pas d'opérateur Div en C. L'opérateur est le symbole slash "/" utilisé pour la division entière et aussi la division réel. Si le divident et le diviseur sont tous les 2 des entiers c'est la division entière qui est effectuée; sinon c'est la division réel qui est effectuée.

Si x est un entier et on ecrit x/2 alors x/2 est un entier.

Si x est un réel alors x/2 sera un réel.

Correction: while (i <= (x / 2))

 

3) Ligne: if (car = 1)

Pour tester égaliter en C on utilise symbole ==

Correction: if (car == 1)

 

4) Ligne: return car;

La fonction carre est écrite comme: void carre(int x; int rac; int car)

void veut dire qu'elle ne retourne rien. Donc il faut enlever return car.

Correction enlever la ligne  return car; (ou bien ecrire return;)

 

Le programme suivant compile mais ne marche pas:

#include <stdio.h>

#include <stdlib.h>

 

void carre(int x, int rac, int car)

{

        int i;

 

        i = 0;

        while (i <= (x / 2))

        {

                if (x == (i * i))

                {

                        car = 1;

                        rac = i;

                }

                else

                {

                        car = 0;

                        i++;

                }

        }

}

 

int main() 

{

        int  n, i, s, x, p, car, rac;

 

       do

       {

               printf("Donner un Entier Positif n\n");

               scanf("%d", &n);

        } while (n>0 && n<100);

 

        printf("Donner la suite des nombres\n");

        scanf("%d", &x);

 

        s = 0; p = 0;

        for (i=0; i<=n; i++)

        {

                carre(x, rac, car);

                if (car == 1)

                {

                        s = s + rac;

                       p = p * rac;

                 }

       }

 

        printf("La Somme des Racines Carrees est %d\n", s);

        printf("Le Produit des Racines Carrees est %d\n", p);

 

        carre(s, rac, car);

        if (car == 1)

        {

                printf("La somme est un carre parfait\n");

         }

        else

        {

                printf("La somme n'est pas un carre parfait\n");

        }

 

        carre(p, rac, car);

        if (car == 1)

        {

               printf("Le produit est un carre parfait\n");

        }

        else

        {

                  printf("Le produit n'est pas un carre parfait\n");

         }

 

          return 0;

}

 

Erreurs à l'execution:

Erreurs à corriger pour que le programme marche

1) Ligne: while (n>0 && n<100);

On veut un n>0

Correction: while (n<=0);

 

2) Ligne: for (i=0; i<=n; i++)

On boucle n+1 avec ca

Correction: for (i=0; i<n; i++)

            (ou bien for (i=1; i<=n; i++))

3) Lignes: 

        printf("Donner la suite des nombres\n");

        scanf("%d", &x);

il faut mettre ces 2 lignes à l'interieur de la boucle for()

 

 

4) p = 0;

Correction: il faut initialiser p à 1 car sinon p sera toujours égale a 0 (dans la multiplication).

 

5) TRES IMPORTANT DE COMPRENDRE CE QUI SUIT

La fonction Carre est une AP qui rend 2 résultats qui sont car et rac. Donc rac et car seront en sortie.

Cela veut dire que car et rac seront modifiées par la fonction carre, donc on doit faire une passation par adresse. 

Si on écrit: void carre(int x, int rac, int car) cela veut dire que rac et car seront passés par valeur, donc les paramètres  réels ne seront pas modifiés lors de l'appel de la fonction carre.

Pour faire une passation par adresse des paramètres on écrit:

void carre(int x, int *rac, int *car) et rac et car seront des pointeurs (des adresses) et lors de l'appel de la fonction carre on écrit carre(x, &rac, &car) dans le main().

 

6) Dans la fonction carre() on a une boucle infinie car lorsque if (x == (i * i)) le i n'est pas incrementée et la condition du while (i <= (x / 2)) sera dans ce cas toujours Vrai.

Donc il faut incrementer le i dans le cas aussi ou (x == (i * i)). Aussi *car = 0 doit etre a l'exterieur du while

Donc la fonction devient:

void carre(int x, int *rac, int *car)

{

        int i;

 

        i = 0;

        *car = 0;

        while (i <= (x / 2))

        {

                if (x == (i * i))

                {

                        *car = 1;

                        *rac = i;

                }

 

               i++;

        }

}

 

Une solution plus simple serait comme:

void    carre(int x, int *rac, int *car)

{

       int i;

 

        i = 0;

        *car = 0;

        while (i * i < x )

        {

                i++;

        }

        if (x == i * i)

        {

               *car = 1;

              *rac = i;

        }

}

 

ICI bas le programme qui marche:

#include <stdio.h>

#include <stdlib.h>

 

void    carre(int x, int *rac, int *car)

{

       int i;

 

        i = 0;

        *car = 0;

        while (i * i < x )

        {

                i++;

        }

        if (x == i * i)

        {

               *car = 1;

              *rac = i;

        }

}

 

 

int     main()

{

        int  n, i, s, x, p, car, rac;

 

        do

        {

                printf("Donner un Entier Positif n\n");

                scanf("%d", &n);

        } while (n<=0);

 

        s = 0; p = 1;

        for (i=0; i<n; i++)

        {

                printf("Donner la suite des nombres (x entier naturel)\n");

                scanf("%d", &x);

    

                carre(x, &rac, &car);

                if (car == 1)

               {

                       s = s + rac;

                       p = p * rac;

                }

        }

 

        printf("La Somme des Racines Carrees est %d\n", s);

        printf("Le Produit des Racines Carrees est %d\n", p);

 

        carre(s, &rac, &car);

        if (car == 1)

        {

                  printf("La somme est un carre parfait\n");

         }

         else

         {

                  printf("La somme n'est pas un carre parfait\n");

         }

 

         carre(p, &rac, &car);

        if (car == 1)

        {

                 printf("Le produit est un carre parfait\n");

        }

        else

        {

                printf("Le produit n'est pas un carre parfait\n");

        }

 

        return 0;

 

 

Question 2 

Question

Un des étudiants a posé la question suivante:

Lorsqu'un scanf est rencontré dans un programme, le programme attend indéfiniment jusqu'a ce que l'utilisateur rentre des données au clavier.

On veut ecrire un programme où l'utilisateur a 10 secondes pour entrer un texte. Si l'utilisateur entre un texte avant 10 s le texte entre sera affiché sinon un message indiquant un timeout sera affiché.

 

Reponse

Sous Windows on peut utilise la fonction kbhit() qui retourne une valeur non nulle dans le cas où l'utilisateur a appuyé sur une touche du clavier.

 

La solution est la suivante:

#include <stdio.h>

#include <stdlib.h>

#include <conio.h>

#include <time.h>

 

const int time_limit = 10;

 

int main(int argc, char const *argv[])

{

    char buf[100];

    time_t secs, end_secs;

    double diff;

    int flag = 0;

 

    printf("Vous avez %d secondes pour entrer votre texte ...\n", time_limit);

 

    /* fonction time: retourne le temps courant en secondes */

    secs = time(NULL);

    end_secs = secs + time_limit;

 

    /* fonction difftime: calcule difference entre 2 temps */

    diff = difftime(end_secs, secs);

 

    while (diff > 0)

    {

        /* fonction _kbhit: retourne valeur #0 si une touche du clavier est appuye */

        if(_kbhit())

        {

            flag = 1;

            break;

        }

        else

        {

             secs = time(NULL);

             diff = difftime(end_secs, secs);

        }

    }

 

    if (flag == 1)

    {

        /* Lire texte si touches du clavier appuye */

        scanf("%[^\n]s", buf);

        printf("Texte: %s\n", buf);

    }

    else

    {

        /* Aucune touche du clavier appuyee: afficher Timeout */

        printf("TIMEOUT !!!!\n");

    }

 

    system("pause");

    return 0;

}

 

 

Sous Linux 

Sous linux on peut utiliser la fonction poll().  La fonction poll() examine pendant un certain temps fourni les file descriptors fournis (dans notre cas stdin) des évenements (lecture/ecriture/autres évenements). Cette fonction retourne le nombre de file descriptors pour lesquels un des évenements specifiés est survenu. Dans le cas ou aucun des évenements pour aucun des file descriptors n'est survenu et que le temps specifié s'est ecoulé la fonction retourne la valeur 0.

 

La solution est la suivante:

#include <unistd.h>

#include <poll.h>

#include <stdio.h>

 

const int time_limit = 10000;/* time out en ms */

 

int main()

{

    struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };

    char buff[10];

    printf("Vous avez %d secondes pour entrer votre texte ...\n",      time_limit/1000);

 

    if( poll(&mypoll, 1, time_limit) )

    {

        scanf("%9s", buff);

        printf("Texte : %s\n", buff);

    }

    else

    {

        printf("Timeout !!!");

    }

 

    return 0;

}

 

Une autre solution sous linux serait d'utiliser la fonction select().

 

 

 

Question 3 

Question

Un des étudiants a pose la question suivante:

On a un probleme lorsque un scanf  est placé avant le gets. le programme saute le gets (gets pour lire une chaine avec un espace) 

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

 

int main(int argc, char *argv[]) {

char c[10],s[10];

scanf("%s",s);

gets(c);

printf("s='%s'\t c=%s",s,c);

return 0;

}

 

Reponse

Le problème est que scanf() ne lit pas le caractère saut de ligne '\n' comme dernier caractère et lorsque gets() s'execute elle trouve le saut de ligne '\n' laissé par scanf et suppose qu'il y'a une ligne vide puisque gets lit jusqu'a trouver un saut de ligne.

Une solution est de 'consommer' le saut de ligne laissé par scanf:

int main(int argc, char *argv[]) {

  char c[10],s[10];

  scanf("%s",s);

  while (getchar() != '\n') ;

  gets(c);

  printf("s='%s'\t c=%s",s,c);

  return 0;

}

 

Autre chose importante à remarquer est que en C utiliser gets() peut être dangeureux car gets() ne specifie pas le nombre de caractères maximum a lire et si le nombre de caractères donné est plus grand que la chaine declarée on peut arriver à une situation de buffer overflow où la mémoire peut être corrompue. Pour cela il vaut mieux utilise fgets() au lieu de gets() et le programme précédent devient (stdin est stream input):

int main(int argc, char *argv[]) {

  char c[10],s[10];

  scanf("%s",s);

  while (getchar() != '\n');

  fgets(c, sizeof(c), stdin);

  printf("s='%s'\t c=%s",s,c);

  return 0;

}

 

 

 

Question 4

Question

Un des étudiants a pose la question suivante:

lors de la création d'un fichier comment tester si le fichier existe deja et dans ce cas eviter de le recréer.

 

Reponse

La fonction access() qui fait partie de unistd.h peut être utilisé dans ce cas. Cett fonction aura comme paramètres le nom du fichier et la constante F_OK pour tester si le fichier existe. Elle retourne 0 dans le cas où le fichier existe.

Ainsi par exemple la fonction creeFichEnt() ci-dessous crée un fichier d'entiers uniquement dans le cas où le fichier n'existe pas.

 

int creerFichEnt(char nomFichier[])

{

     FILE *pFile;

     int i, ent, nbr;

 

     if (access(nomFichier, F_OK) == 0)

     {

           return   1;

     }

 

     pFile = fopen(nomFichier, "wb");

     if (pFile == NULL)

     {

        return   -1;

     }

 

     do

     {

           printf("Donner Nombre d'entiers a creer dans fichier %s\n", nomFichier);

           scanf("%d", &nbr);

     } while (nbr < 1);

 

     for (i=0; i < nbr; i++)

     {

            printf("Entrer Entier %d ...\n", i + 1);

            scanf("%d", &ent);

            fwrite(&ent, sizeof(int), 1, pFile);

     }

 

     fclose(pFile);

     return    1;

}

 

.

 

 

 

Question 5 

Question

Un des étudiants a pose la question suivante:

Comment lire une chaine de caractères contenant des espaces (blancs) en C.

 

Reponse

scanf() lit une chaine de caractères jusqu'a rencontrer un espace (blanc) 

ou bien jusqu'a rencontrer le caractère newline.

Donc si l'utilisateur entre la chaine "abcdef  ghijk  lmnop" alors la chaine 

ch va contenir la chaine "abcdef"

 

int main()

{

    char  ch[100];

 

    printf("Entrer votre chaine de caracteres ...\n");

    scanf("%s", ch);

    printf("Chaine de caracteres lue:\n");

    printf("%s", ch);

    printf("\n*******************************************\n");

    return 0;

}

 

L'execution de ce programme donne le resultat suivant:

 

Entrer votre chaine de caracteres ...

abcdef  ghijk  lmnop

Chaine de caracteres lue:

abcdef

*******************************************

================================================================

Pour avoir scanf qu'elle lit une chaine de caractères contenant des 

espaces on peut utiliser le format %[^\n]s  qui veut dire lire une chaine de caractères jusqu'a  rencontrer newline.

Donc si l'utilisateur entre la chaine "abcdef  ghijk  lmnop" alors  la chaine ch va contenir la chaine "abcdef  ghijk  lmnop"

 

int main()

{

    char  ch[100];

 

    printf("Entrer votre chaine de caracteres ...\n");

    scanf("%[^\n]s", ch);

    printf("Chaine de caracteres lue:\n");

    printf("%s", ch);

    printf("\n*******************************************\n");

    return 0;

}

 

L'execution du programme ci-dessus donne le resultat suivant:

 

Entrer votre chaine de caracteres ...

abcdef  ghijk  lmnop

Chaine de caracteres lue:

abcdef  ghijk  lmnop

*******************************************

 

================================================================

 

Une autre manière plus securitaire et qui lit une chaine de caractères  avec des espaces est d'utiliser la fonction fgets().  Voir question 3.

 

int main()

{

    char  ch[100];

 

    printf("Entrer votre chaine de caracteres ...\n");

    fgets(ch, sizeof(ch), stdin);

    printf("Chaine de caracteres lue:\n");

    printf("%s", ch);

    printf("\n*******************************************\n");

    return 0;

}

 

 

L'execution du programme ci-dessus donne le resultat suivant:

 

Entrer votre chaine de caracteres ...

abcdef  ghijk  lmnop

Chaine de caracteres lue:

abcdef  ghijk  lmnop

 

******************************************* 

 

 

 

 

 

 

Question 6