#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

typedef struct {
	unsigned int div, reste;
} Division;

Division divise1(unsigned int n, unsigned int d) {
	Division ds = {n / d, n % d};
	return ds;
}

void divise2(unsigned int n, unsigned int d, unsigned int* div, unsigned int* reste) {
	*div = n / d;
	*reste = n % d;
}

unsigned int divise3(unsigned int n, unsigned int d, unsigned int* reste) {
	*reste = n % d;
	return n / d;
}

void exemple() {
	unsigned int d, r;
	Division ds;
	ds = divise1(345, 17);
	divise2(345, 17, &d, &r);
	d = divise3(345, 17, &r);
}

void echanger(int* p, int* q) {
	int tmp = *p;
	*p = *q;
	*q = tmp;
}

void exemple2() {
	int a = 12, b = 45;
	echanger(&a, &b);
}

// enum car employées en tant que dimensions de tableaux
enum {NB_EPREUVES = 10, NB_ETUDIANTS = 4};
// une note par épreuve
typedef float Notes[NB_EPREUVES];
// les coefficients par épreuve
const Notes COEFFICIENTS = {1., 2., 1., 2., 1., 2., 1., 2., 1., 2.};
// des constantes 
const int NOTE_MIN = 0, NOTE_MAX = 20;
// une note par épreuve par étudiant
typedef Notes TableauDeNotes[NB_ETUDIANTS];

// paramètre d'entrée
// autres prototypes possibles :
//      void afficher(const float n[]);
//      void afficher(const float n[NB_EPREUVES]); // à éviter
//      void afficher(const float n[10]); // à proscrire
//      void afficher(const float* n);
void afficher(const Notes n) {
	int i;
	printf("[");
	for(i = 0; i < NB_EPREUVES; ++i)
		printf("%s%4.1f", i == 0 ? "" : ", ", n[i]);
	printf("]\n");
}

// paramètre d'entrée (mais avec retour de valeur)
// autres prototypes possibles :
//      float moyenneEtudiant(const float n[], const float c[]);
//      float moyenneEtudiant(const float* n, const float* c);
float moyenneEtudiant(const Notes n, const Notes c) {
	int i;
	float cn, cc;
	cn = cc = 0.0;
	for(i = 0; i < NB_EPREUVES; ++i) {
		cn += n[i] * c[i];
		cc += c[i];
	}
	return cn / cc;
}
		
// paramètre d'entrée/sortie
// autres prototypes possibles :
//      void changer(float n[], int e, float v);
//      void changer(float* n, int e, float v);
void changer(Notes n, int e, float v) {
	assert(0 <= e && e < NB_EPREUVES);
	assert(NOTE_MIN <= v && v <= NOTE_MAX);
	n[e] = v;
}

// paramètre de sortie
// autres prototypes possibles :
//      void noter(float n[]);
//      void noter(float* n);
void noter(Notes n) {
	int i;
	for(i = 0; i < NB_EPREUVES; ++i)
		n[i] = (float)(NOTE_MIN + (rand() % (NOTE_MAX - NOTE_MIN + 1)));
}

// paramètre d'entrée et paramètre de sortie
// autres prototypes possibles (sauf l'avant dernier) :
//      void moyenneParEpreuve(const Notes n[], float m[]);
//      void moyenneParEpreuve(const Notes* n, float m[]);
//      void moyenneParEpreuve(const float* n[], float m[]);
//      void moyenneParEpreuve(const float** n, float m[]);
//      void moyenneParEpreuve(const float n[][], float m[]); // ne compile pas mais
//      void moyenneParEpreuve(const float n[][10], float m[]); // compile (à éviter)
// sans compter les variations sur le 2nd paramètre !!!
void moyenneParEpreuve(const TableauDeNotes n, Notes m) {
	int i, j;
	for (i = 0; i < NB_EPREUVES;++i)
		m[i] = n[0][i];
	for (j = 1; j < NB_ETUDIANTS; ++j)
		for (i = 0; i < NB_EPREUVES;++i)
			m[i] += n[j][i];
	for (i = 0; i < NB_EPREUVES;++i)
		m[i] /= NB_ETUDIANTS;
}

int main() {
	int i;
	TableauDeNotes TableauDeNotes;
	Notes moyenne;

	srand((unsigned int)time(NULL));

	for (i = 0; i < NB_ETUDIANTS; ++i) {
		noter(TableauDeNotes[i]);
		afficher(TableauDeNotes[i]);
		printf("la moyenne ponderee de cet etudiant est %4.1f\n\n", moyenneEtudiant(TableauDeNotes[i], COEFFICIENTS));
	}
	moyenneParEpreuve(TableauDeNotes, moyenne);
	printf("les moyennes par epreuve sont :\n");
	afficher(moyenne);
	printf("la moyenne ponderee des moyennes par epreuve est %4.1f\n\n", moyenneEtudiant(moyenne, COEFFICIENTS));
	system("pause");
	system("cls");
	return 0;
}
