Bonjour,

Je suis à réaliser une petite application en client/serveur (1/1) qui doit me permettre d'envoyer des informations concernant un bilan fonctionnel pour obtenir des ratios.

Partie gestion financière mise à part, j'ai un problème parce que je n'arrive pas à passer un tableau à une fonction puis à le récupérer.

A la base, j'avais fait mon code comme un gros paquet d'instruction... Un point d'entrée main et voilà

J'ai donc souhaité faire des fonctions afin de découper mon code en bloc lisibles et compréhensibles... Ce que j'essaie de faire mais j'ai énormément de mal avec la notion de pointeurs et références en C...

Voici mon code :
-- une archive se trouve à la fin du message

Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
/*************************************************
** Nom du fichier : client.h
** Deallyra
**
** Entête de l'application cliente de calcul des
**      différents ratios à partir du bilan fonctionnel.
**
*****************************************************/
 
/**
 * Fonction de vérification de passage d'une adresse IP à l'application via
 *      le paramètre argv.
 * Dans le cas où le paramètre fourni ne serait pas une IP, l'application se
 *      termine.
 *
 * Non utilisée, nom du serveur servant à la connexion
 *
 *@param char
 *@return void
 */
//void verifierCommandeLancement(char*);
 
/**
 * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel
 *@param int
 *@return int
 */
int bilan (int);
 
 
// @todo
/**
 * Fonction de création et connexion d'un socket entre deux stations
 *@param int
 *@return void
 */
void creationConnexionSocket (int);
 
 
/**
 * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel
 *@param long*
 *@return long*
 */
long* saisieBilan(long*);

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*************************************************
** Nom du fichier : client.c
** Deallyra
**
** Fichier corps de l'application cliente de calcul des
**      différents ratios à partir du bilan fonctionnel.
**
*****************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 
#include <linux/types.h>
#include <sys/socket.h>
*/
#include <netdb.h>
 
 
#include "client.h"
 
//Port d'écoute du serveur
#define PORT 20000
//Taille maximale pour l'envoi des données d'un socket
#define MAX_LENGTH 256
 
 
/**
 * Fonction de vérification de passage d'une adresse IP à l'application via
 *      le paramètre argv.
 * Dans le cas où le paramètre fourni ne serait pas une IP, l'application se
 *      termine.
 *
 * Non utilisée, nom du serveur servant à la connexion
 *
 *@param char
 *@return void
 */
/*void verifierCommandeLancement(char* adresseIP)
{
		 * /!\
		 * Il faudrait vérifier l'IP autrement qu'en la parsant.
		 * regexp possible en C ?
		 *
 
		//On indique la position du caractère par rapport à la "chaine" de l'IP.
		int i = 0;
		//Simulation d'un type booléen. 0=> False; 1=> True;
		int estUneAdresseIP = 1;
 
		//On vérifie les octets.
		while(estUneAdresseIP == 1 && i <= 14)
		{
			//On récupère un octet.
			int octet = adresseIP[i]*100+adresseIP[i+1]*10+adresseIP[i+2];
 
			//Est-il compris entre 0 et 255 ?
			if(octet <= 0 || octet >= 255)
			{
				estUneAdresseIP = 0;
			}
 
			i += 4;
		}
 
		//On vérifie les séparateurs (points) entre les octets.
		i = 3;
		while(estUneAdresseIP == 1 && i <= 11)
		{
			//Est-il compris entre 0 et 255 ?
			if(strcmp(adresseIP[i], ".") != 0)
			{
				estUneAdresseIP = 0;
			}
			i += 4;
		}
 
		//Si le paramètre fourni n'est pas correct, l'application se termine.
		if(estUneAdresseIP == 0)
		{
			perror( ">> Il faut fournir une adresse IP a l'application" );
			exit( 1 );
		}
}
*/
 
/**
 * Fonction de saisie des éléments du bilan fonctionnel
 *@param int
 *@return int
 */
long* saisieBilan(long* input)
{
 
	printf( "\n\tETABLISSEMENT DU BILAN FONCTIONNEL\n\n" );
	printf( "(Veuillez entrer les montants)\n" );
 
	//Saisie des différentes valeurs de l'actif et du passif
	printf( "\n- Actif -\n" );
	printf( "Emplois Stables: " ); scanf( "%ld", &input[0] );
	printf( "Actifs Circulants d'Exploitation: " ); scanf( "%ld", &input[1] );
	printf( "Actifs Circulants Hors Exploitation: " ); scanf( "%ld", &input[2] );
	printf( "Trésorerie de l'Actif: " ); scanf( "%ld", &input[3] );
	printf( "\n- Passif -\n" );
	printf( "Ressources Stables: " ); scanf( "%ld", &input[4] );
	printf( "Dettes d'Exploitation: " ); scanf( "%ld", &input[5] );
	printf( "Dettes Hors Exploitation: " ); scanf( "%ld", &input[6] );
	printf( "Trésorerie du Passif: " ); scanf( "%ld", &input[7] );
 
	return input;
}
 
/**
 * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel
 *@param int
 *@return int
 */
int bilan(int sock)
{
	//Variable recevant les données à envoyer au serveur.
	char data[MAX_LENGTH];
 
	//Tableau recevant les différentes saisies du Bilan Fonctionnel
	long input[8];
 
	//Appel à la fonction de saisie du bilan
	input = saisieBilan(input);
 
 
 
	//Envoi des données au serveur
 
	//Longueur de la donnée à envoyer || Sert de vérification également
	int dataLength = 0;
 
	//On "ré-initialise" la variable data à vide.
	strcpy( data, "" );
 
	//Pour chacune des données (du tableau) à envoyer
	int i = 0;
	while((i < 8) && (dataLength != -1) && (strcmp( data, "ERROR" ) != 0))
	{
		//On place la donnée dans la variable tampon data
		sprintf( data, "%ld", input[i] );
		//Si l'écriture dans le socket ne se passe pas bien
		if (write( sock, data, strlen( data ) ) == -1)
		{
			perror( ">> Erreur: la fonction write() a renvoye une erreur." );
			dataLength = -1;
		}
		//La donnée est transmise au serveur
		else
		{
			//On attend l'accusé de réception du serveur
			dataLength = read( sock, data, sizeof( char[MAX_LENGTH] ) );
			//Tant que l'on ne reçoit rien, on continue à attendre la réponse du serveur.			
			while (dataLength == 0)
			{
				dataLength = read( sock, data, sizeof( char[MAX_LENGTH] ) );
			}
 
			//Nous n'avons pas pu lire la réponse du serveur
			if (dataLength == -1)
			{
				perror( ">> Erreur: la fonction read() a renvoye une erreur." );
			}
		}
		i++;
	}
 
	//La fonction write() ou read() a envoyé une erreur.
	//Le traitement n'a pas été à terme
	if (dataLength != -1)
	{
		perror( ">> Erreur: le serveur a renvoye une erreur." );
		exit( 1 );
	}
	else
	{
		printf( "\n\tResultat des calculs\n\n" );
		//On lit la réponse du serveur
		while (read( sock, data, sizeof( char[MAX_LENGTH] ) ) > 0)
		{
			printf( "%s", data );
		}
		return 1;
	}
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*************************************************
** Nom du fichier : main.c
** Deallyra
**
** Entrée du programme de l'application cliente de calcul des
**      différents ratios à partir du bilan fonctionnel.
**
*****************************************************/
 
int main (int argc, char **argv)
{
	//Variable permettant de vérifier que le descripteur du soket est créé
	int connectSocket;
 
	//Structure permettant de préparer l'adressage de la machine distante (serveur)
	struct sockaddr_in connectInfos;
	//Structure permettant de récupérer des infos sur la machine distante (serveur)
	struct hostent *serverInfos;
 
	//Port d'écoute du serveur
	#define PORT 20000
	//Taille maximale pour l'envoi des données d'un socket
	#define MAX_LENGTH 256
 
	//Fonction non utilisée pour le moment
	//verifierCommandeLancement(char argv[0]);
 
	//Création du socket
		// socket(int domaine, int type, int protocole);
			//Domaine => Famille de protocole, IP dans notre cas
			//Type => TCP (SOCK_STREAM) ou UDP (SOCK_DGRAM)
			//Protocole => A zéro généralement
	if ((connectSocket = socket( AF_INET, SOCK_STREAM, 0 )) == -1)
	{
		perror( ">> Erreur: impossible de creer le socket." );
		exit( 1 );
	}
 
	//On récupère le nom du serveur, paramètre d'entrée de l'application
	serverName = argv[1];
 
	//Récupération des informations sur la machine distante (serveur)
	if ((serverInfos = gethostbyname(serverName)) == NULL)
	{
		perror( ">> Erreur: impossible de recuperer des informations sur le serveur." );
		exit( 1 );
	}
 
	//Famille du protocole et son port
	bcopy( (char *)serverInfos->h_addr, (char *)&connectInfos.sin_addr, serverInfos->h_length);
	connectInfos.sin_family = serverInfos->h_addrtype; // ou connectInfos.sin_family = AF_INET
	connectInfos.sin_port = htons( PORT );             // htons permet de faire les conversions necessaires a la portabilite du code
 
	//Connexion au serveur avant de faire les traitements
	if (connect( connectSocket, (struct sockaddr *)&connectInfos, sizeof( struct sockaddr_in ) ) == -1)
	{
		perror( ">> Erreur: impossible de connecter le socket au serveur." );
		exit( 1 );
	}
 
	//Etablissement du Bilan
	bilan( connectSocket );
 
	//On ferme le socket dont le descriptif est passé en paramètre
	close( connectSocket );
 
	return 0;
}
et voici le makefile
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CC=gcc
CFLAGS=-Wall -Wextra -O -Wstrict-prototypes -Wunreachable-code -g
LDFLAGS=
EXEC=chatTCP_client
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
 
all: $(EXEC)
 
chatTCP_client: $(OBJ)
	@$(CC) -o $@ $^ $(LDFLAGS)
 
main.o: client.h
 
%.o: %.c
	@$(CC) -o $@ -c $< $(CFLAGS)
 
.PHONY: clean mrproper
 
clean:
	rm -rf *.o
 
mrproper: clean
	rm -rf $(EXEC)
Et donc mon erreur est la suivante :
client.c: Dans la fonction «bilan» :
client.c:127: erreur: incompatible types in assignment
client.c:146: attention : déclaration implicite de la fonction « «write» »
client.c:155: attention : déclaration implicite de la fonction « «read» »
make: *** [client.o] Erreur 1
Ce qui concerne les lignes suivantes :

Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
/**
 * Fonction de saisie des éléments du bilan fonctionnel
 *@param int
 *@return int
 */
long* saisieBilan(long* input)
{
 
	printf( "\n\tETABLISSEMENT DU BILAN FONCTIONNEL\n\n" );
	printf( "(Veuillez entrer les montants)\n" );
 
	//Saisie des différentes valeurs de l'actif et du passif
	printf( "\n- Actif -\n" );
	printf( "Emplois Stables: " ); scanf( "%ld", &input[0] );
	printf( "Actifs Circulants d'Exploitation: " ); scanf( "%ld", &input[1] );
	printf( "Actifs Circulants Hors Exploitation: " ); scanf( "%ld", &input[2] );
	printf( "Trésorerie de l'Actif: " ); scanf( "%ld", &input[3] );
	printf( "\n- Passif -\n" );
	printf( "Ressources Stables: " ); scanf( "%ld", &input[4] );
	printf( "Dettes d'Exploitation: " ); scanf( "%ld", &input[5] );
	printf( "Dettes Hors Exploitation: " ); scanf( "%ld", &input[6] );
	printf( "Trésorerie du Passif: " ); scanf( "%ld", &input[7] );
 
	return input;
}
 
/**
 * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel
 *@param int
 *@return int
 */
int bilan(int sock)
{
	//Variable recevant les données à envoyer au serveur.
	char data[MAX_LENGTH];
 
	//Tableau recevant les différentes saisies du Bilan Fonctionnel
	long input[8];
 
	//Appel à la fonction de saisie du bilan
	input = saisieBilan(input);
(...)

J'aimerai bien que l'on m'apprenne à pécher et que je comprenne enfin comment marche ces "adorables" pointeurs... J'ai beau lire cours et tuto je ne comprends pas...

long* peut dire qu'on veut passer un tableau de long comme dire qu'on passe un pointeur vers un long... je la fais comment la différence ?

C'est assez nébuleux pour moi...

Merci à vous pour toute aide que vous pourrez m'aporter.

PS : voici une archive du code source