Partage

Exercice, calculer la moyenne d'un tableau

Le 9 mai 2013 à 18:47:51

Bonjour à tous, voilà, je me suis lancé dans l'exercice proposé dans le tuto sur le C qui est de créer une fonction pour calculer la moyenne des valeurs d'un tableau et j'ai donc réalisé ce code : 
#include <stdio.h>
#include <stdlib.h>

void affichage(int tableau[], int tailletableau);
double moyenne(int *ptableau, int tailletableau);

int main(int argc, char *argv[])
{
    int tableau[5] = {50,60,70,80,90};
    affichage(tableau, 5);
    moyenne(tableau, 5);
    printf("La moyennes des valeurs est : %d\n", moyenne1);

    return 0;
}

void affichage(int tableau[], int tailletableau)
{
    int i;
    for(i=0; i < tailletableau; i++)
    {
        printf("%d\n", tableau[i]);
    }
    printf("\n");
}

double moyenne(int *ptableau, int tailletableau)
{
    int i;
    int p = i + 1;
    double moyenne1 = ptableau[0];
    for(i=0; i < tailletableau; i++)
    {
        moyenne1 = moyenne1 + ptableau[p];
    }
    moyenne1 = moyenne1 / tailletableau;

    return moyenne1;
}
Mais petit problème, le compilateur ne reconnais pas la variable "moyenne1" malgré la valeur retournée en fin de fonction et lorsque je place donc le printf dans la fonction il m'indique une valeur aléatoire comprise en - l'infini et le néant, enfin bref j'ai l'impression qu'il ne réalise pas le calcule des valeurs du tableau mais plutôt leurs adresses

-
Edité par Doctormiller le 9 mai 2013 à 18:48:56

Publicité
Le 9 mai 2013 à 18:47:51
Le 9 mai 2013 à 18:52:53

Yo !

La variable moyenne1est déclarée dans la fonction moyenne, et est détruite à la fin de celle-ci. Elle n'est donc pas déclarer dans le main ! Sinon, tu peux afficher la moyenne de ton tableau comme ceci :

printf("La moyennes des valeurs est : %d\n", moyenne(tableau, 5));

Bonne continuation !

Edit : Ya aussi un petit problème au niveau de la division, on en parle ici. ;)

-
Edité par paraze le 9 mai 2013 à 18:53:58

Vive progdupeu.pl – Règles du forum C – Divers conseils pour mieux programmer en C (et plus si affinité)
Le 9 mai 2013 à 18:56:55

Doctormiller a écrit:

le compilateur ne reconnais pas la variable "moyenne1"

Normal, elle n'est pas déclarée !

Donc il te faut la déclarer puis lui affecter le résultat retourné par la fonction.

Pour affecter le résultat d'une fonction à une variable on procède de la manière suivante :

Resultat = LaFonction(eventuel_parametre);
Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 9 mai 2013 à 19:06:43

Ok, je pensais qu'une variable retourné dans une fonction était alors défini dans la fonction main() mais effectivement je me suis trompé, autrement pour j'ai lu le tuto et je ne vois toujours pas où se situe ma seconde faute :l

Le 9 mai 2013 à 19:18:12

Regarde le passage sur les divisions des nombres flottants (à virgule). ;)

Vive progdupeu.pl – Règles du forum C – Divers conseils pour mieux programmer en C (et plus si affinité)
Le 9 mai 2013 à 19:34:56

Je comprend pas tout mais c'est au niveau des conversions de type ?

Le 9 mai 2013 à 19:40:45

Initialisation des nombres flottants

Je tiens à retenir votre attention sur la manière d’initialiser les variables flottantes (soit donc de type float ou double). En fait, ces variables sont faites pour contenir des nombres à virgule. À l’initialisation, il ne faut donc pas se contenter de donner sa valeur, il faut aussi mettre la « virgule ». Sauf que l’on ne met pas une virgule : on met un point.

const double pi = 3.14;

Cela vient du fait que le C est une invention américaine, et que les anglophones utilisent le point à la place de la virgule, on met un point là où nous autres francophones mettons une virgule.

Et vous devez impérativement mettre ce point, même si vous voulez stocker un nombre entier dans un float ou un double. Par exemple, vous ne devez pas écrire double a = 5; mais double a = 5.; (certains préfère double a = 5.0;, cela revient au même). Si vous ne le faites pas, vous risquez d’avoir quelques problèmes.

Voici un petit tableau récapitulatif afin de bien comprendre :

Type Initialisation
char 0
short 0
int 0
long 0
float 0.
double 0.
long double 0.

Division

La division en informatique est différente de celle en mathématiques. Si je vous dis 15/4, vous en déduisez que le quotient est 3,75. Pourtant, le résultat de celle-ci est 3 en langage C.

int division = 15 / 4;

Suite à la lecture du chapitre suivant, vous pourrez vérifier cette affirmation en affichant la valeur de cette opération, mais vous n’en êtes pas encore là, et je vous défends de vous y rendre avant la fin de ce chapitre.

Pour l’ordinateur, le résultat de 15 / 4 est bien 3. Pourquoi ? Parce qu’on lui a demandé de faire une division d’entiers (appelée division euclidienne), donc il répond par des entiers. Si l’on veut afficher le résultat complet (à nos yeux), il faut l’indiquer à l’ordinateur. Comment faire ? Essayez de trouver la solution tout seul.

Un indice ? Pensez aux flottants.

La solution :

double division = 15. / 4.;   /* même si pour nous, c’est la même chose que 15 / 4 */

Même si pour nous c’est intuitif, pour l’ordinateur il faut bien préciser si ce sont des entiers ou des flottants.


Sur ce. :D

Vive progdupeu.pl – Règles du forum C – Divers conseils pour mieux programmer en C (et plus si affinité)
Le 9 mai 2013 à 19:47:54

Oui ok, du coup mon double et divisé par un int, mais je ne peut pas redéfinir la variable avec un simple point ? Si ?

Le 9 mai 2013 à 20:04:48

Les conversions de type

La conversion de type est une opération qui consiste à changer le type d’une variable en un autre. Je peux ainsi convertir une variable de type float en type int, par exemple. Il existe deux types de conversions : les conversions explicites et les conversions implicites.

Les conversions explicites

Ce sont des conversions voulues et demandées par le programmeur. Elles se déclarent en suivant ce modèle :

(<Type>) <Expression>

Voici par exemple un code où l’on demande explicitement la conversion d’un double en int.

int a;
const double pi = 3.14;

a = (int) pi;

La valeur de pi reste inchangée, elle vaudra toujours 3.14 dans la suite du programme. Par contre, a vaut maintenant 3, puisque le flottant a été converti en entier. Expliciter une conversion peut nous servir quand on veut forcer le résultat d’une opération par exemple. Imaginons que nous voulons faire une division, mais que les deux opérandes soient de type int.

int a, b;
double c;

a = 5;
b = 9;

c = a / b;

Vu qu’on fait une division euclidienne, le résultat sera tronqué. Si on veut avoir un résultat avec la partie décimale, il suffit de faire une conversion explicite d’un des deux opérandes en double :

c = (double) a / b;
/* ou */
c = a / (double) b;

Les conversions implicites

Ce sont des conversions que fait le compilateur tout seul, sans que l’on ait demandé quoi que ce soit. En général, ça ne gêne pas le programmeur, mais ça peut parfois être problématique si la conversion n’était pas voulue. Par exemple, si l’on reprend le code précédent, il y aura toujours une conversion.

int a;
const double pi = 3.14;

/* Il y a conversion implicite de double en int, mais rien 
n’est précisé, c’est le compilateur qui fait ça de lui-même. */
a = pi;

Cependant, les conversions amènent parfois à des pertes d’information si l’on n’y prend pas garde.

Perte d’information

Une perte d’information survient quand on convertit le type d’une variable en un autre type plus petit et que celui-ci ne peut pas contenir la valeur reçue. Si, par exemple, je convertis un double de 100 chiffres en un short, il y a perte d’information, car le type short ne peut pas contenir 100 chiffres. La règle à retenir est la suivante :

Si on convertit un type T vers un type S plus petit, il y a perte d’information.
Règle des conversions

Les conversions, et surtout les conversions implicites qui peuvent être vicieuses, doivent être manipulées avec précaution, au risque de tomber sur des valeurs fausses en cas de perte d’information. Nous découvrirons d’ici quelques chapitres comment connaitre la taille d’un type T pour éviter ces pertes d’information.


^^

Vive progdupeu.pl – Règles du forum C – Divers conseils pour mieux programmer en C (et plus si affinité)
Le 9 mai 2013 à 21:43:03

paraze a écrit:

Par exemple, vous ne devez pas écrire double a = 5; mais double a = 5.; (certains préfère double a = 5.0;, cela revient au même). Si vous ne le faites pas, vous risquez d’avoir quelques problèmes.

Hum, des problèmes? Je ne vois pas lesquels. Ne serait-ce pas une invention?

paraze a écrit:

La conversion de type est une opération qui consiste à changer le type d’une variable en un autre.

Non, le type d'une variable est défini une fois pour toute à la déclaration.

La conversion de type est une opération qui consiste à produire une valeur du type demandé à partir d'une autre valeur. Ça n'a rien à voir avec les variables.

Le 9 mai 2013 à 21:49:10

@Marc Mongenet : Pour le premier point, on parlait surtout du fait que pour faire des divisions entre flottant ça risquait de coincer un peu, de ne pas donner le résultat attendu; c'est vrai qu'on devrait un peu nuancer cette partie-là. Le second point a déjà été corrigé, mais en Bêta-Test, la version en ligne est donc incorrecte (c'est pourquoi on est un peu dégoutté du fait qu'on ne puisse pas mettre à jour notre tutoriel, surtout que plusieurs chapitres / ajouts / corrections étaient sur le point de passer en ligne). Bref, j'aurai dû corrigé ce problème là à la main, mais j'avais oublié que l'erreur était encore présente.

Vive progdupeu.pl – Règles du forum C – Divers conseils pour mieux programmer en C (et plus si affinité)
Le 10 mai 2013 à 11:52:37

Du coup j'ai changé mon code en ça : 

#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED

void affichage(int tableau[], int tailletableau);
double moyenne(int *ptableau, int tailletableau);

void affichage(int tableau[], int tailletableau)
{
    int i;
    for(i=0; i < tailletableau; i++)
    {
        printf("%d\n", tableau[i]);
    }
    printf("\n");
}

double moyenne(int *ptableau, int tailletableau)
{
    int i;
    int p = i + 1;
    double moyenne1 = (double) ptableau[0];
    for(i=0; i < tailletableau; i++)
    {
        moyenne1 += (double) ptableau[p];
    }
    moyenne1 /= (double) tailletableau;

    return moyenne1;
}

#endif // MAIN_H_INCLUDED
que j'ai d'ailleurs mit dans un .h mais toujours le même problème hélas :/ j'utilise sans doute très mal le "(double)"
Le 10 mai 2013 à 11:58:00

Dans un fichier header, .h on ne met que des déclaration pas de définition !
Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 12:02:08

    int i;
    int p = i + 1;

Attention ici, tu utilise la variable i sans l'avoir préalablement utilisée !


 

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 12:14:30

Lucien63 a écrit:

Dans un fichier header, .h on ne met que des déclaration pas de définition !


C'est à dire ? x)
Le 10 mai 2013 à 12:19:51

Ça :

void affichage(int tableau[], int tailletableau);

C'est une déclaration de fonction.

et ça :

void affichage(int tableau[], int tailletableau)
{
    int i;
    for(i=0; i < tailletableau; i++)
    {
        printf("%d\n", tableau[i]);
    }
    printf("\n");
}

C'est la définition de la même fonction.


 

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 12:49:21

Ok

du coup j'ai séparé mon code comme ça, main.c : 

#include <stdio.h>
#include <stdlib.h>
#include "main.h"

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

    int tableau[5] = {50,60,70,80,90};
    affichage(tableau, 5);
    moyenne(tableau, 5);
    printf("La moyennes des valeurs est : %d\n", moyenne(tableau, 5));

    return 0;
}

void affichage(int tableau[], int tailletableau)
{
    int i;
    for(i=0; i < tailletableau; i++)
    {
        printf("%d\n", tableau[i]);
    }
    printf("\n");
}

double moyenne(int *ptableau, int tailletableau)
{
    int i;
    double moyenne1 = (double) ptableau[0];
    for(i=0; i < tailletableau; i++)
    {
        moyenne1 += (double) ptableau[i+1];
    }
    moyenne1 /= (double) tailletableau;

    return moyenne1;
}

Et voici le main.h : 

#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED

void affichage(int tableau[], int tailletableau);
double moyenne(int *ptableau, int tailletableau);

#endif // MAIN_H_INCLUDED

Mais du coup le compilateur me dis que les fonctions ont déjà été définis et ne compile plus :l

Le 10 mai 2013 à 13:19:21

Voici un petit tableau récapitulatif afin de bien comprendre :
Type | Initialisation
------------- | -------------
char | '\0'
short | 0
int | 0
long | 0l
float | 0.f
double | 0.
long double | 0.lf

Bref, le Sdz ne me permet pas de bien formater le tout mais l'idée est là ...

-
Edité par @che le 10 mai 2013 à 13:22:35

Étudiant - Codeur en C                                                                                                                                                                  Copying is an act of love.    -   
Le 10 mai 2013 à 13:30:32

Doctormiller a écrit:

Mais du coup le compilateur me dis que les fonctions ont déjà été définis et ne compile plus :l

Pas possible ! tu as bien enregistré le nouveau fichier main.h ?

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 13:39:08

Lucien63 a écrit:

Doctormiller a écrit:

Mais du coup le compilateur me dis que les fonctions ont déjà été définis et ne compile plus :l

Pas possible ! tu as bien enregistré le nouveau fichier main.h ?

Oui, j'ai relancé code block en enregistrant bien tout et maintenant ça marche. Du coup j’initialise ma variable moyenne1 puis je lui attribut la valeur de ptableau[0] et je compile le tout et j'obtiens 0 maintenant :l

Le code de ma fonction :

double moyenne(int *ptableau, int tailletableau)
{
    int i;
    double moyenne1 = 0.;
    moyenne1 = (double) ptableau[0];
    for(i=0; i < tailletableau; i++)
    {
        moyenne1 += (double) ptableau[i+1];
    }
    moyenne1 /= (double) tailletableau;

    return moyenne1;
}




Le 10 mai 2013 à 13:41:49

Dans la fonction qui calcule la moyenne, ce que tu calcules dans la boucle for est une somme d'éléments de tableau, et non une moyenne.

Il serait donc judicieux d'appeler la variable de calcul somme, et pas moyenne.  C'est important, d'appeler les choses par leur nom.

C'est quand le calcul de la somme est terminé, qu'on retourne la valeur de la moyenne, qui est le quotient de la somme par le nombre d'éléments

      return somme/tailletableau;

 Par ailleurs

- tu as un bug d'indice au dernier tour de la boucle, quand i vaut tailletableau-1,

- tu fais des complications inutiles en mélangeant notations indicées et pointeurs

- tes conversions de types sont toutes inutiles.  Il en fallait une au niveau de la division quand tu divisais une somme (dans un int) par le nombre d'éléments, int aussi. Là ce n'est plus le cas.

-
Edité par michelbillaud le 10 mai 2013 à 13:50:06

Le 10 mai 2013 à 14:05:57

Ok, donc voilà mon code à peu près propre :

double moyenne(int ptableau[], int tailletableau)
{
    int i;
    int somme = 0;
    double moyenne1 = 0.;
    somme = ptableau[0];
    for(i=0; i < tailletableau; i++)
    {
        somme += ptableau[i+1];
    }

    return somme/tailletableau;
}

Mais j'obtiens toujours 0

Le 10 mai 2013 à 14:12:33

Attention ptableau[i+1] au dernier tour de boucle est equivalent à ptableau[5] or cette case du tableau ce trouve en dehors de ton tableau.

Les indice de tableau vont de 0 à N-1

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 14:25:53

Ok, du coup il suffit de remplacer ptableau[i+1] par ptableau[i] ?
Le 10 mai 2013 à 14:44:56

A un détail prés, Oui !

(Le détail c'est que tu affectes déjà la valeur de la case d'indice 0 à somme avant d'executer la boucle.)

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 14:47:46

Attention aussi quand tu fait :

return somme/tailletableau;

somme et taille sont des entiers et tu retournes un double.

L'opération sera exécutée avant la convertion en double !

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 14:55:44

J'ai modifier mon code comme ça :

double moyenne(int ptableau[], int tailletableau)
{
    int i;
    int somme = ptableau[0];
    double moyenne1 = 0.;
    for(i=0; i < tailletableau; i++)
    {
        somme += ptableau[i];
    }

    return (double) somme/ (double) tailletableau;
}

mais toujours un résultat égal à 0

Le 10 mai 2013 à 15:07:02

Affichage à 0 bizard ?

Mais oui :

    printf("La moyennes des valeurs est : %d\n", moyenne(tableau, 5));


Pour afficher un double c'est %f et non pas %d

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 15:09:31

Autrement dans le code de la fonction moyenne, il subsiste deux petite erreurs :

moyenne1 ne sert à rien vu que tu ne l'utilise pas !

Et tu additionne deux fois la case ptableau[0] !

Je peux à nouveau éditer mes messages ! J'ai du pour cela changer de navigateur ! Les temps ont bien changés !
Le 10 mai 2013 à 15:20:57

Oui j'ai corrigé et le code marche impeccable ! Merci beaucoup, une solution pour réduire le nombre de chiffre significatifs après la virgule ? Je veux en mettre seulement 2

Exercice, calculer la moyenne d'un tableau

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown