View Full Version : Problema con i puntatori di C
Ragazzi, con sti puntatori sto diventando scemo!
Pensavo di avere capito bene la questione ma a quanto pare non è così!
Vi prego di rispondere alla mia domanda perchè davvero non so più che fare!!!
Se io ho:
struct sockaddr_in server;
e faccio un cast di questo tipp
(struct sockaddr*)&server
Quello che faccio è convertire l'indirizzo di server in un puntatore a sockaddr giusto?
Ma se io faccio così:
struct sockaddr_in *server;
e faccio un cast in questo modo:
(struct sockaddr*)server
non è la stessa cosa?
Nel primo caso faccio un cast sull'indirizzo dellla struttura server e nel secondo lo faccio sul contenuto del puntatore alla struttura che è acora l'indirizzo della struttura server!
Vi prego ditemi cosa mi sfugge perchè il mio compilatore non la pensa come me!!!
...e io non so più a che santo rivolgermi!!! :cry:
ilsensine
22-12-2004, 13:43
Originariamente inviato da Swalke
e faccio un cast in questo modo:
(struct sockaddr*)server
non è la stessa cosa?
No: nel primo caso, casti il _puntatore_ "&server", che punta alla variabile (fisicamente presente) "server". Nel secondo caso casti un puntatore che se non è stato inizializzato per puntare a un oggetto allocato in qualche maniera, punta probabilmente in qualche baratro.
Si, ma io la struttura puntata da *server l'ho inizializzata e poi assegnata a al puntatore *server!
...non ho postato l'assegnazione e l'inizializzazione per snellire il messaggio!
ilsensine
22-12-2004, 14:05
Originariamente inviato da Swalke
...non ho postato l'assegnazione e l'inizializzazione per snellire il messaggio!
Credo che dovresti postare qualcosa di pseudocompilabile per riprodurre il problema; il cast così come lo hai scritto non è scorretto.
...ilsensine. forse il problema è quello che dici tu ma io ho le idee un po' confuse e non capisco alcune cose!
Ti posto i codici dei programmi... ...ho cercato di ridurli all'osso e di commentarli a dovere... ...ma da quello che mi è parso tu ne capisci molto e non avrai difficoltà!
Faccio prima alcune premesse per farti perdere meno tempo possibile:
Nel primo post avevo rappresentato il cast su una variabile e un puntatore server.
OKKIO che nel programma che ti posto la stessa cosa è fatta su una variabile client... ...lo dico per non che ti si confondano le idee sulla mia domanda!
Il problema è che ho due programmi, un client e un server.
Il server si mette in ascolto, il client lo contatta e il server gli scrive un messaggio, tutto qui.
Ti posto tre codici:
IL 1° è il codice del server funzionante
IL 2° è il codice del server non funzionante. Le uniche differenze dal 1° stanno nella riga 18 dove server è un puntatore, nella 56 dove mi cambia il cast e nalla 67 (ma questa è in influente)
IL 3° è il client. Questo è giusto e l'ho messo solo perchè così vedi cosa avviene!
OKKIO che tutti i codici vengono compilati correttamente, l'errore lo hai in esecuzione!
Se usi il server corretto tutto funge, invece se usi il server sbagliato, quando fai partire il client, questo sttampa un messaggio ricevuto dal server che è una serie di caratteri sballati, poi termina e uccide il server!!!
Ultime 2 cose: ricordati di passare "localhost" quando fai partire il client e ricordati di fare una kill sul server corretto quando hai finito perchè resta in esecuzione!!!
Eccoti i codici:
SERVER FUNZIONANTE:
#include <unistd.h>
#include <stdio.h> /*per potere utilizzare la printf*/
#include <errno.h> /*contiene la definizione dei nomi simbolici dei codici di errore*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> /* netbd.h è necessario per struct hostent e herror */
#define PORT 3550 /* porta che verrà aperta */
#define BACKLOG 2 /* numero di connessioni permesse */
int main()
{
int controller; //conterrà l'esito di una chiamata a funzione
struct sockaddr_in server;
struct sockaddr_in client;
int addrlen; //(ci servirà nella funzione "accept")
int fd; //descrittore della socket del server
int fd2; //descrittore della socket impegnata con un client
fd=socket(AF_INET, SOCK_STREAM, 0); //inizializzo una socket di tipo SOCK_STREAM
bzero(&server, sizeof(server)); //inizializza a 0 la struttura server
//popoliamo i campi della struttura sockaddr_in "server"
server.sin_family=AF_INET; //setto il protocolllo usato
server.sin_port=htons(PORT); //setto il numero di porta
server.sin_addr.s_addr=INADDR_ANY; //setto l'ip della macchina.
//INADDR_ANY da automaticamente l'indirizzo ip dell'host locale.
controller=bind(fd, (struct sockaddr *)&server, sizeof(server));
//server è una struttura sockaddr_in mentre "bind" accetta
//come secondo parametro un puntatore a una struttura sockaddr
//ecco il perchè de cast
if(controller==-1)
{
perror("Errore in Bind");
exit(255);
}
controller=listen(fd, BACKLOG); //il server si mette in attesa di chiamate
if(controller==-1)
{
perror("Errore in Listen");
exit(255);
}
printf("SERVER - Accetto delle richieste di connessione alla porta %d\n", PORT);
while(1) //ciclo infinito
{
addrlen=(sizeof(struct sockaddr_in));
fd2=accept(fd, (struct sockaddr *)&client, &addrlen);
//seleziona una richiesta di un client
//client è una struttura sockaddr_in mentre "accept" accetta
//come parametro un puntatore a una struttura sockaddr
//ecco il perchè de cast
if (fd2 == -1)
{
perror("Errore in Accept");
exit(255);
}
printf("SERVER - Connessione da parte di: %s\n", inet_ntoa(client.sin_addr));
//Con il Casting converto il puntatore al CAMPO sin_addr in un puntatore alla struttura in_addr
controller=write(fd2, "Benvenuto sul mio server.\n", 25); //scriviamo un messaggio al client fd2
if (controller == -1)
{
perror("Errore in Write");
exit(-1);
}
close (fd2);
}
exit(0);
}
SERVER CHE DA ERRORE (cambiano le righe 18 -56 - 67):
#include <unistd.h>
#include <stdio.h> /*per potere utilizzare la printf*/
#include <errno.h> /*contiene la definizione dei nomi simbolici dei codici di errore*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> /* netbd.h è necessario per struct hostent e herror */
#define PORT 3550 /* porta che verrà aperta */
#define BACKLOG 2 /* numero di connessioni permesse */
int main()
{
int controller; //conterrà l'esito di una chiamata a funzione
struct sockaddr_in server;
struct sockaddr_in *client;
int addrlen; //(ci servirà nella funzione "accept")
int fd; //descrittore della socket del server
int fd2; //descrittore della socket impegnata con un client
fd=socket(AF_INET, SOCK_STREAM, 0); //inizializzo una socket di tipo SOCK_STREAM
bzero(&server, sizeof(server)); //inizializza a 0 la struttura server
//popoliamo i campi della struttura sockaddr_in "server"
server.sin_family=AF_INET; //setto il protocolllo usato
server.sin_port=htons(PORT); //setto il numero di porta
server.sin_addr.s_addr=INADDR_ANY; //setto l'ip della macchina.
//INADDR_ANY da automaticamente l'indirizzo ip dell'host locale.
controller=bind(fd, (struct sockaddr *)&server, sizeof(server));
//server è una struttura sockaddr_in mentre "bind" accetta
//come secondo parametro un puntatore a una struttura sockaddr
//ecco il perchè de cast
if(controller==-1)
{
perror("Errore in Bind");
exit(255);
}
controller=listen(fd, BACKLOG); //il server si mette in attesa di chiamate
if(controller==-1)
{
perror("Errore in Listen");
exit(255);
}
printf("SERVER - Accetto delle richieste di connessione alla porta %d\n", PORT);
while(1) //ciclo infinito
{
addrlen=(sizeof(struct sockaddr_in));
fd2=accept(fd, (struct sockaddr *)client, &addrlen);
//seleziona una richiesta di un client
//client è una struttura sockaddr_in mentre "accept" accetta
//come parametro un puntatore a una struttura sockaddr
//ecco il perchè de cast
if (fd2 == -1)
{
perror("Errore in Accept");
exit(255);
}
printf("SERVER - Connessione da parte di: %s\n", inet_ntoa(*(struct in_addr *) client->sin_addr.s_addr));
//Con il Casting converto il puntatore al CAMPO sin_addr in un puntatore alla struttura in_addr
controller=write(fd2, "Benvenuto sul mio server.\n", 25); //scriviamo un messaggio al client fd2
if (controller == -1)
{
perror("Errore in Write");
exit(-1);
}
close (fd2);
}
exit(0);
}
CODICE DEL CLIENT:
#include <unistd.h>
#include <stdio.h> /*per potere utilizzare la printf*/
#include <errno.h> /*contiene la definizione dei nomi simbolici dei codici di errore*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> /* netbd.h è necessario per struct hostent e herror */
#define PORT 3550 /* porta che verrà aperta */
#define BACKLOG 2 /* numero di connessioni permesse */
int main(int argc, char *argv[])
{
int controller; //conterrà l'esito di una chiamata a funzione
struct hostent *myhost;
struct sockaddr_in server; //conterrà le info relative alla socket server
int fd; //descrittore della socket del server
int fd2; //descrittore della socket impegnata con un client
char buf[100];
if(argc != 2)
{
printf("Non è stato passato un ip al lancio del programma!\n");
exit(255);
}
myhost=gethostbyname(argv[1]); //gethostbyname ritorna un puntatore!
if(myhost==NULL)
{
herror("Errore nella gethostbyname");
exit(255);
}
fd=socket(AF_INET, SOCK_STREAM, 0); //inizializzo una socket di tipo SOCK_STREAM
bzero(&server, sizeof(server)); //inizializza a 0 la struttura server
server.sin_family=AF_INET; //setto il protocolllo usato
server.sin_port=htons(PORT); //setto il numero di porta
server.sin_addr=*((struct in_addr *)myhost->h_addr); //setto l'ip della macchina.
printf("CLIENT - Mi connetto alla porta %d di %s!\n", PORT, argv[1]);
controller=connect(fd, (struct sockaddr*)&server, sizeof(struct sockaddr));
if(controller==-1)
{
perror("Errore in Connect");
exit(255);
}
controller=read(fd, buf, 26); //scriviamo un messaggio al client fd2
if (controller == -1)
{
perror("Errore in Read");
exit(-1);
}
buf[26]='\0';
printf("CLIENT - Messaggio del server: %s\n", buf);
close(fd); /* chiude fd */
printf("CLIENT - Fine\n");
exit(0);
}
Attendo con ansia una tua risposta!
Forse è proprio come dicevi tu, ma non capisco il perchè!
La funzione accept dovrebbe inizializzare la struttura puntata da *client no?
Allora perchè il cast del server non funzionante non va bene!!!??
ilsensine
22-12-2004, 15:44
Originariamente inviato da Swalke
...ilsensine. forse il problema è quello che dici tu ma io ho le idee un po' confuse e non capisco alcune cose!
Sì è come dicevo. Puntatore non inizializzato:
SERVER CHE DA ERRORE (cambiano le righe 18 -56 - 67):
struct sockaddr_in *client;
(....)
while(1) //ciclo infinito
{
addrlen=(sizeof(struct sockaddr_in));
fd2=accept(fd, (struct sockaddr *)client, &addrlen); // BOOM!
ilsensine
22-12-2004, 15:45
La funzione accept dovrebbe inizializzare la struttura puntata da *client no?
Sì certo, peccato che non hai inizializzato il _puntatore_ "client" per farlo puntare ad alcuna struttura valida.
Scusa ma ancora ne capisco un po' poco!
...ma allora dimm un po...
Il cast di un puntatore non lo puoi mai fare se hai creato un puntatore che ancora non punta a nulla?
Non capisco perchè!
...con il cast di un puntatore come nel mio caso non stai semplicemente dicendo:
trasforma il mio puntatore da un punataore al tipo x a un puntatore al tipo y?
:muro:
...uff
ilsensine
22-12-2004, 16:43
Originariamente inviato da Swalke
Scusa ma ancora ne capisco un po' poco!
...ma allora dimm un po...
Il cast di un puntatore non lo puoi mai fare se hai creato un puntatore che ancora non punta a nulla?
Non capisco perchè!
Sì che puoi fare il cast, ma il problema non è il cast, ma ciò che contiene il puntatore. Se non lo inizializzi, contiene spazzatura -- o punta a una zona di memoria non mappata, o ad una zona di memoria casuale del tuo programma.
Per farti capire a cosa serve un puntatore, partiamo dall'esempio non funzionante e aggiungi queste dichiarazioni all'inizio di main:
struct sockaddr_in client_1;
struct sockaddr_in client_2;
Se ora prima della accept metti:
client = &client_1;
la accept "riempirà" la struttura client_1. Se invece metti
client = &client_2;
la accept "riempirà" client_2.
Domanda: se non metti nulla dentro "client" (quindi lo lasci "non inizializzato", o meglio "inizializzato a casaccio" :D ), la accept dove sta andando a scrivere? ;)
Ora ho capito!!!
Il tuo esempio è stato perfetto!!!
La risposta lla tua domanda non è semplice però!
Dove scrive la bind se ancora il puntatore non punta a nulla?
...di sicuro da qualche parte scrive perchè non m iritorna un -1!
...o sbaglio?
Inoltre come mai il compilatore non si accorge di un errore del genere?
...poi ho anche un'altra domandina ma la lascio per dopo...
SEI UN MITO!!!
ilsensine
22-12-2004, 16:57
Originariamente inviato da Swalke
Dove scrive la bind se ancora il puntatore non punta a nulla?
(vuoi dire la accept?)
Scrive nella locazione di memoria puntata dal puntatore. Se non ti ritorna errore e il programma non ti è andato in crash, stai sicuro di aver corrotto qualche parte della memoria del tuo programma.
Inoltre come mai il compilatore non si accorge di un errore del genere?
Perché non è un errore di sintassi. Il compilatore è un GIGO(*) :D
(*) Garbage In, Garbage Out
TUTTO OK!!!
Quella del GIGO mela sono segnata!!!
...e l'altra domanda non serve più!!!
Grazie mille ilsensine!!!
Il forum con te diventa praticamente un chat!!!
:D
...se mi vengono altri dubbi su sto programma mi faccio risentire!!!
Grazie ilsensine ho capitoa anche io.... sei stao mooolto utile...
Ciao
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.