2010-08-16 14 views
8

Ostrzeżenie: Proszę traktować mnie jak żółtodzioba, którym jestem. To mój pierwszy "prawdziwy" program C. Więc jeśli nie rozumiem niektórych rzeczy, to dlatego.Jak obsłużyć ten wskaźnik w getaddrinfo?

Próbuję utworzyć serwer czatu zgodnie z przykładem z Przewodnika po programowaniu sieci w programie Beej. To było zalecane, więc proszę bardzo.

Chcę mieć funkcję akceptować wskaźnik do struktury, modyfikować właściwości w tym wskaźniku i skonfigurować odbiornik na przekazanym porcie. W poniższym kodzie otrzymuję błąd segmentacji i naprawdę nie mogę zrozumieć dlaczego. Obwinia mnie, że jestem zielony. (Rozwój w NetBeans 6.8 na Ubuntu, jeśli to konieczne):

#define PORT "4400" 

typedef struct { 
    int port; 
    fd_set *connections; 
    int connections_count; 
    int listener; 
    struct addrinfo address; 
    struct addrinfo socket_hints; 
} Server; 

typedef struct { 
    struct sockaddr_storage address; // User's address 
    int fs_id;     // ID to the socket they belong to 
    char *name;     // Pointer to the user's name 
    struct User *nextUser;  // Next user in the list 
} User; 

void initialize_server(Server *passed_server, char *port) { 
    struct addrinfo *temp; 
    int result; 

    // Set up the server hints 
    memset(&passed_server->socket_hints, 0, sizeof(struct addrinfo)); 
    passed_server->socket_hints.ai_family = AF_UNSPEC; 
    passed_server->socket_hints.ai_socktype = SOCK_STREAM; 
    passed_server->socket_hints.ai_flags = AI_PASSIVE; 

    result = getaddrinfo(NULL, port, &passed_server->socket_hints, &temp); 
    printf("Result: %d\n", result); 
} 

int main(int argc, char** argv) { 
    // Set up socket stuff 
    Server *server; // Set up the server 
    memset(server, 0, sizeof(Server)); 

    fd_set read_sockets; // Master socket holder and sockets to read 
    int new_connection; // Holds the socket ID of the new connection 
    socklen_t address_length; // Used to hold the length of the address from the user 
    struct addrinfo; 

    // Useful sets 
    char buffer[1024]; 
    int bytes_recieved; 
    int yes = 1; // For SETOPT 

    // Set up server info on defined port 
    initialize_server(server, PORT); 
    FD_ZERO(&read_sockets); 

    return (EXIT_SUCCESS); 
} 

Jeśli potrzebujesz pełnego kodu (myślę pisał wszystko zasadniczą), można znaleźć poniżej link. Z góry dziękuję za pomoc lub próbę!

http://pastebin.org/529545

+1

+1 za doskonały pierwszy wpis. Witamy w StackOverflow. Jedyne, co mogę o tym myśleć, może to poprawić: Jeśli uruchomisz ten kod za pomocą debuggera, powiedz gdb, z informacją o debugowaniu, to powinieneś powiedzieć, w którym wierszu jest ten kod, który może być dobrym punktem wyjścia dla debugowanie. – Thanatos

+0

Dziękuję. Zajrzę do tego. – Codeacula

+1

Zaledwie kilka wskazówek. Możesz próbować rozwijać się na emacs 23. Również, gdy pojawi się kikut sterty, który zwykle jest spowodowany przez adresowanie nieprawidłowej pamięci. Spróbuj użyć gdb i śledzenia wstecznego (bt). Zaprowadzi cię do linii, która zawiodła. A także zainstaluj valgrind, który jest bardzo dobry do śledzenia błędów pamięci. np. valgrind --leak-check = yes ./your_app. Nadzieja, która pomaga. – ant2009

Odpowiedz

6

Linia:

Server *server; 

faktycznie nie przydzielać żadnego miejsca dla struktury serwera, tylko wskaźnik do jednego, który jest ustawiony na wartość losową.

Wygląda zmianą czego potrzebujesz to:

Server *server = malloc (sizeof (Server)); 

które faktycznie przydziela trochę pamięci, aby użyć.

Pomyśl o różnicy w następujący sposób:

Server *server;    | Server *server = malloc (sizeof (Server)); 
     +----------+   |   +---------+  +-----------+ 
server | ???????? | --> ??? | server | pointer | --> | structure | 
     +----------+   |   +---------+  +-----------+ 
+0

Ale czy to nie jest wezwanie? paczkę (serwer, 0, sizeof (serwer)); – Codeacula

+1

Nie, to prawie na pewno ten, który spowodował błąd. Wszystkie 'memset' ma za zadanie wypełnić pamięć określoną wartością, nadal musisz mieć ważny adresowalny blok pamięci - skutecznie przekazujesz mu losowy adres, od którego zaczyna się wypełnianie. Kiedy używam malloc, wracam do programu 'Wynik: 0'. – paxdiablo

+0

Dzięki, że absolutnie to zrobiliście! Pomógł mi też zrozumieć, czym jest wskaźnik. – Codeacula

2
int main(int argc, char** argv) { 
// Set up socket stuff 
Server *server; // Set up the server 
memset(server, 0, sizeof(Server)); 

To jest błędne. Tutaj pytasz: memset, aby wyzerować pamięć wskazywaną przez server. Wywołanie memset jest poprawne, nie jest to wskaźnik server. Ta linia:

Server *server; 

Przydziela pamięć dla i daje wskaźnik, ale nie przeznaczyć dowolną pamięć dla wskazywanego obiektu, a nie daje wskaźnik wartości początkowej. Tak więc po tej linii wskaźnik wskazuje tylko losowe miejsce w pamięci. (Prawdopodobnie korzysta z tego, co zostało w pamięci RAM) Nie przypisaliśmy jeszcze ważnej wartości, więc nie można przekazać go do memset.

Teraz musimy nadać mu prawidłową wartość. Można było albo:

1) Przypisywanie Server na stosie, po prostu mówiąc:

Server server; 
memset(&server, 0, sizeof(server)); 

2) Przypisywanie Server dynamicznie, używając malloc:

Server *server = malloc(sizeof(*server)); 
// Check for NULL, which means malloc failed. 

(również pamiętać, że użycie sizeof - użycie nazwy zmiennej zamiast typu umożliwi zmianę parametru sizeof, jeśli kiedykolwiek zmienisz typ zmiennej.)

Być może zechcesz znaleźć i zapoznać się z podstawowym samouczkiem dotyczącym wskaźników. To dość klasyczny błąd kogoś, kto właśnie spotkał się ze wskaźnikami po raz pierwszy, więc nie czuj się źle.

+0

Bardzo docenione, Thanatos. Właśnie ukończyłem naukę w szkole, ale przykład był gotowy. Uczę się najlepiej, popełniając własne błędy. Całkowicie zapomniałem o malloc. Miałem pamięć do umysłu, najpierw przeglądając inne posty, aby uzyskać odpowiedź. Zrobiłbym to, gdybym mógł. Dziękuję również za ciepłe powitanie. – Codeacula

Powiązane problemy