Série 5 niveau 0: Formatted input/output with scanf and printf Exemple de programme avec verification des entrées (tableau circulaire) Exercice 0: Formatted input output with scanf/printf In Serie3_0, we have learnt how to use scanf and printf commands for simple input/output purposes with integers. In this serie we will cover the use of scanf and printf with formatted data. In the end of this exercise, you will be able to read/write basic data types such as characters, floating points etc. In addition, you will be able to set the width, and the precision of the values that you print-out. Note that this document intends to give you the basics. For a more detailed discussion, you should read the Les entrées-sorties conversationnelles chapter of the book. Formatted Output with printf (output_examples.c): printf is used to write formatted data to stdout. Its prototype is as follows printf(format, expression_list); where format is the text to be written to the stdout which may optionally contain format specifiers. It is either a constant character list entered between, or a pointer to a string (will be studied later in the semester). expression_list is a list of expressions separated by comma whose values replace the format specifiers. Let s have a look at the simple example: int a = 1, b = 2; int c = a + b; printf("%d + %d = %d", a, b, c); The code given above prints out 1 + 2 = 3 to stdout. In the printf call the argument "%d + %d = %d." corresponds to format and %d s corresponds to the format specifiers. The format specifiers are replaced by the values of the elements of the expression_list, a, b, c, successively. A format specifier starts with % and is followed by %[flags][width][.precision]specifier_character where flags, width and.precision are optional parameters and specifier_character is mandatory and the most significant component.
The specifier character allows us to output the corresponding argument in the expression_list in a specific type and interpretation. We will frequently use d for printing out an integer, f for printing out a floating point, c for printing out a character, and s for printing out a character string. Note that there are other specifier characters such as o for octal numbers, x for hexadecimal numbers, e for scientific notation, g for choosing automatically f or e and removing the useless non-significant zeros Several flags can be used to format the output. For instance, - is used to left-justify the output. The width parameter specifies the minimum number of characters to be printed. If the value to be printed has less characters than the width then the number is preceded by empty spaces. For instance, printf( %5d, 123456); prints out 123456 whereas printf( %5d, 123); prints out 123..precision specifies the number of digits to be printed after the decimal point of the floating points. For instance, printf("%.7f\n", 2.71828); prints out 2.7182800 and printf("%.2f\n", 2.71828); prints out 2.72. And finally, printf("%f\n", 2.71828); prints out 2.718280. Note that there are six digits after the point although the.precision has not been set. The reason is that six is the default value of the precision argument. Width and the precision arguments can be replaced by *. In this case, it means that the value of the corresponding argument is given in the expression_list. For example, printf ("%*d \n", 5, 25); prints out 25 and printf ("%.*f \n", 3, 2.71828); prints out 2.718. Note that it is possible to use * both for the width and the precision: printf ("%*.*f \n", 10, 3, 2.71828); prints out 2.718.
Formatted Input with scanf (input_examples.c): scanf is used to read formatted data from stdin. Its prototype is as follows scanf(format, address_list); where scanf reads the input from stdin, interprets it according to the format specifiers given in format and stores them into the variables in address_list. Note that scanf returns the number of the elements it can read successfully. Just like in printf, format parameter is either a constant character list entered between, or a pointer to a string. address_list is a list of the address of the variables separated by commas whose values are replaced by the user input. The address of a variable is obtained by preceding it with an ampersand &. Let s have a look at the following example: int a = 0, b = 0; scanf("%d %d", &a, &b); printf("%d + %d = %d", a, b, a + b); The code given above reads two integers from stdin and puts the input into the variables a and b, and prints out their sum to stdout. In the scanf call, i.e scanf("%d %d", &a, &b);, the argument "%d %d" corresponds to format and %d s corresponds to the format specifiers. The input integer values are assigned to the variables a and b respectively. Please note that the variable names are preceded by &, and we have to put them since scanf requires to pass the address of the variables, not their values. A format specifier for scanf has the following form %[*][width][length]specifier where the asterisk character, *, width and length are optional parameters whereas specifier is mandatory. The specifier is used to interpret the user input. The principle specifiers are the same as printf. Moreover, there are additional specifiers such as [. The asterisk character, * indicates that the corresponding data of the format specifier shall be ignored. In other words, the data is read from the input but no variable value is assigned with it. For instance, the following call scanf("%*d %d", &a); shall expect the user to enter two integers and the second one shall be assigned to the variable a.
The width argument is used to set the maximum number of characters to be read from the input data. For example, scanf("%3d %2d", &a, &b); reads a three-digit-integer and a two-digit-integer and assigns them to a and b respectively. If the user enters 123456789 as input, 123 is assigned to a and 45 is assigned to b. However, if 1 2 3 4 5 6 7 8 9 is entered 1 is assigned to a and 2 is assigned to b since the maximum number of characters is not exceeded for a. The length parameter is used to specify the size of the variable whose address is given. In contrast to printf, scanf does not automatically handle the type conversions. This is the reason why we need length parameter. The frequently used length parameters are l and h. The input type is interpreted as a combination of the length and the specifier. For instance lf is used to read a double and hd is used to read a short int. Please note that the types in C programming languages will be covered later in the course. Exercise 3 (niveau 0): Tableau circulaire à un indice But: écrire une boucle qui lit un entier au clavier et qui le range dans un tableau de 10 entiers en commençant par l élément d indice 0 et qui continue en remplissant les cases suivantes tant que l entier lu est positif. Le rangement doit reboucler au début du tableau pour ne pas déborder de l espace réservé pour le tableau. A la fin du programme on doit imprimer les 10 dernières valeurs lues de la plus récente à la plus ancienne sauf si le programme en a lu moins de 10 en tout, dans ce cas on affiche ce qui a été lu. Ce programme illustre aussi la lecture des données avec vérification sur la valeur renvoyée par scanf. Voici déjà le coeur du programme avec la déclaration du tableau: #define TAILLE 10 int tab[taille];
l'étape suivante ajoute plusieurs éléments essentiels : - inclut stdbool pour bénéficier du type bool et créer le booléen fin, initialisé à FAUX - déclare un compteur i et une variable n pour lire un entier - le do-while est la boucle principale qui range un entier dans tab à chaque passage - à l'intérieur le double while sert à traiter une éventuelle lecture incorrecte : - on détecte le problème car le nombre de code de format lu qui est renvoyé par scanf() n est pas celui attendu ; scanf() devrait lire un code %d avec succès. - la boucle avec getchar() sert à vider le buffer d entrée jusqu au premier \n. - le if-else sert à détecter la fin de la boucle principale si n est négatif - le bloc du else gère l'indice du tableau de façon à reboucler au début quand i dépasse la fin de tab #include <stdbool.h> #define TAILLE 10 int tab[taille]; int i=0, n; bool fin=false; do while(scanf("%d",&n)!=1) // recommence si problème while(getchar()!= '\n');//vide le buffer d'entrée if(n < 0) fin = true; else if(i==taille) i=0; // reboucle au début de tab tab[i]=n ; i++ ; while(!fin); La dernière étape s'occupe de l'affichage final et surtout du cas où moins de 10 valeurs ont été lues. En effet il faut savoir reconnaitre ce cas, c'est pourquoi un booléen supplémentaire est ajouté.
Faites des dessins de tab dans différents scénarios pour comprendre le mécanisme proposé: - le booléen moins_de_10 est initialisé à VRAI puis passe à FAUX sous certaines conditions dans la boucle do-while; vérifiez si c'est correct. - lorsqu'on quitte le do-while, il nous faut une autre boucle avec un compteur j initialisé avec la dernière valeur de i à laquelle il faut enlever 1. - en effet i indique une case "A remplir", éventuellement juste après le tableau. Il faut au moins afficher les valeurs de i-1 jusqu'à 0 - puis si moins_de_10 est FAUX et si i<taille, il faut compléter l'affichage avec les valeurs entre TAILLE-1 et i. #include <stdbool.h> #define TAILLE 10 int tab[taille]; int i=0,j, n; bool fin=false, moins_de_10 = true; do while(scanf("%d",&n)!=1) // recommence si problème while(getchar()!= '\n');//vide le buffer d'entrée if(n < 0) fin = true; else if(i==taille) i=0; // reboucle au début de tab tab[i]=n ; i++ ; if((moins_de_10) && (i==taille)) moins_de_10 = false; while(!fin); for(j=i-1; j>=0 ; j--) printf("%d\n",tab[j]); if(!moins_de_10 && i<taille) for(j=taille-1; j>= i ; j--) printf("%d\n",tab[j]);