2013-11-27 14 views
12

, więc wystąpił problem, gdzie mój kod powoduje błędy segmentacji, zanim którykolwiek z moich głównych faktycznie działa. Nigdy wcześniej tego nie robiłem i nie mam prawie ćwierć wartości kodowania, więc nie jestem pewien, czy coś jest nie tak. Wszystko się kompiluje, przynajmniej na moim komputerze, ale po uruchomieniu moja główna zasada nie jest nigdy osiągnięta.Usterka segmentacji przed głównym

Kontekst: Próbuję połączyć wierzchołki i krawędzie w macierzy sąsiedztwa, a następnie użyć algorytmu Prim do zbudowania MST, ale to na później. Zbudowałem plik nagłówkowy, który pierwotnie zawierał tylko wywołania typdef dla struktur i funkcji. Jednak zmieniłem definicje struktury na plik nagłówkowy, ponieważ otrzymywałem błędy pamięci; stąd dlaczego myślę, że jest problem ze strukturami.

graph.h:

//Leland Wong 00000897031 
//graph header file 



#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#include<math.h> 

#ifndef GRAPH_H 
#define GRAPH_H 

typedef struct vertex 
{ 
    double longitude; 
    double latitude; 
    char city[30]; 
    int index; 
    int visited; //0: not visited, 1: visited, 2: visited 
    struct edge* nexte; 
    struct vertex* nextv; 
    double projected; 
}VERTEX; 


typedef struct edge 
{ 
    struct vertex* start; 
    struct vertex* destination; 
    double distance; 
    struct edge* nexte; 
}EDGE; 


typedef struct graph 
{ 
    struct vertex* list[756]; 
    struct edge* matrix[756][756]; 
}GRAPH; 


/* 
typedef struct vertex VERTEX; 
typedef struct edge EDGE; 
typedef struct graph GRAPH; 
*/ 

double findDistance(VERTEX* v1, VERTEX* v2); //compute the distance between two locations 
EDGE* connect(VERTEX* v1, VERTEX* v2); //connects two vertices and returns the connecting EDGE 
GRAPH primMatrix(GRAPH *g); //connects all vertices using Prim's Algorithm in an adjacency matrix 
//void lPrimConnect(VERTEX v); //connects all vertices using Prim's Algorithm in an adjacency list 
EDGE* findSmallestEdge(VERTEX v, GRAPH *g); //finds the smallest EDGE connected to v 


#endif 

graph.c: zawiera implementacje wszystkich moich funkcji

//functions 

//computes the distance between v1 and v2 
double findDistance(VERTEX* v1, VERTEX* v2) 
{ 
    printf("findDistance"); 
    double long1 = v1->longitude; 
    double long2 = v2->longitude; 
    double lat1 = v1->latitude; 
    double lat2 = v2->latitude; 
    double distance = 0; 

    if(long1 < 0) 
     long1 += 360; 
    if(long2 < 0) 
     long2 += 360; 

    distance = powf((long1-long2), 2) + powf((lat1 - lat2), 2); 
    distance = sqrt(distance); 
    return distance; 
} 

//creates and returns an edge that connects v1 and v2 
EDGE* connect(VERTEX* v1, VERTEX* v2) 
{ 
    printf("connect"); 
    EDGE *new; 
    new->start = v1; 
    new->destination = v2; 
    new->distance = findDistance(v1, v2); 
    return new; 
} 


//finds smallest edge connected to v in GRAPH g 
EDGE* findSmallestEdge(VERTEX v, GRAPH *g) 
{ 
    printf("findSmallestEdge"); 
    EDGE *tempe; 
    int i, index; 
    index = v.index; 

    //set tempe equal to the first edge connected to v 
    tempe = g->matrix[index][0]; 
    //find smallest edge connected to v 
    for(i = 0; i < 756; i++) 
    { 
     if(g->matrix[index][i] -> distance < tempe->distance && g->list[index]->visited == 0) 
     { 
      tempe = g->matrix[index][i]; 
     } 
    } 
    return tempe; 
} 

//creates an MST out of GRAPH g using Prim's algorithm 
GRAPH primMatrix(GRAPH *g) 
{ 
    printf("primMatrix"); 
    GRAPH new; // = malloc(sizeof(GRAPH)); 
    EDGE *smallest; 
    EDGE *tempe; 
    int i, x; 
    i = 1; 
    x = 0; 

    new.list[0] = g->list[0]; //add root node to MST 
    g->list[0]->visited = 2; 
    smallest = findSmallestEdge(*new.list[0], g); 
    new.matrix[0][smallest->destination->index] = smallest; 
    //MST will contain all 756 nodes, so run this 755 times to ensure all nodes are reached 
    while(i < 756) 
    { 
     x = 0; 
     smallest = findSmallestEdge(*new.list[i], g); 
     //i = number of vertices already reached 
     while(x < i) 
     { 
      tempe = findSmallestEdge(*new.list[x], g); 
      if(tempe -> distance < smallest -> distance) 
      { 
       smallest = tempe; 
      } 
      x++; 
     } 
     new.list[i] = smallest -> destination; 
     smallest -> destination -> visited = 2; 
     new.matrix[smallest->start->index][smallest->destination->index] = smallest; 
     i++; 
    } 
    return new; 
} 

graphmatrixmain.c: Główny funkcję, która tworzy wykresy

#include "graph.h" 

int main(int argc, char* argv[]) 
{ 
    FILE *fp; 
    static GRAPH g; 
    char buffer[200]; 
    int i, j; 
    char city[30]; 
    char *long1; 
    char *lat1; 

    if(argc == 1) 
    { 
     printf("could not open file\n"); 
     return 0; 
    } 

    else 
     fp = fopen(argv[1], "r"); 

    //read in line of data from txt file, build a new vertex, and insert into list 
    while(fgets(buffer, 200, fp) != NULL) 
    { 
     VERTEX *new = malloc(sizeof(VERTEX)); 
     printf("%s", buffer); 
     sscanf(buffer, "%s %s %s", city, long1, lat1); 
     //sscanf(buffer, "%[^\t]\t%[^\t]\t%s", city, long1, lat1); 
     printf("scanned in data\n"); 
     new->longitude = atof(long1); 
     new->latitude = atof(lat1); 
     new->index = i; 
     g.list[i] = new; 
     printf("%s: (%lf, %lf)", new->city, new->longitude, new->latitude); 
     i++; 
    } 
    //create EDGE and make connects between every VERTEX in list 
    for(i = 0; i < 756; i++) 
    { 
     for(j = 0; j < 756; j++) 
     { 
      g.matrix[i][j] = connect(g.list[i], g.list[j]); 
      if(j == 0) 
      { 
       g.list[i]->nexte = g.matrix[i][j]; 
      } 
     } 
    } 
    return 0; 
} 

Jeśli jest to konieczne, jest to plik, w którym odczytuję: cities.txt it con Górach łącznie 756 wpisów, ale jeśli chodzi o kod jest zaniepokojony wielkość nie powinna być istotne

Shanghai 121.47 31.23 
Bombay 72.82 18.96 
Karachi 67.01 24.86 
Buenos Aires -58.37 -34.61 
Delhi 77.21 28.67 
Istanbul 29 41.1 
Manila 120.97 14.62 
Sao Paulo -46.63 -23.53 
Moscow 37.62 55.75 
+0

Należy skompilować ze wszystkimi ostrzeżeniami i informacjami dotyczącymi debugowania (np. 'Gcc -Wall -g'). Ulepsz źródło, dopóki nie otrzymasz ostrzeżeń. Następnie ** użyj debuggera **. I powiedz więcej o twoim systemie operacyjnym, kompilatorze, komendzie kompilacji itp ... –

+0

@dasblinkenlight faktycznie odpowiedział na to doskonale. kod aktualnie kompiluje się bez żadnych błędów za pomocą -Wszystko, w którym mam problem z moim błędem sscanf. Zaktualizowałem kod do jego obecnego stanu. Teraz zdaję sobie sprawę, że jest to błąd z moimi ogranicznikami. – aperson231

Odpowiedz

21

Byłem uruchomiony na problem gdzie jakoś mój kodu powodującego naruszenie ochrony pamięci, zanim którykolwiek z moim głównym rzeczywiście działa .

Zazwyczaj oznacza to, że struktury danych, które próbuje wprowadzić Twój main w obszarze automatycznego magazynowania, przepełniają stos. W twojej sytuacji wygląda na to, że GRAPH jest odpowiednim podejrzanym, aby to zrobić: ma on tablicę 2D z 571536 wskaźnikami, która może bardzo dobrze przepełnić stos zanim twoja main dostanie szansę na rozpoczęcie.

Jednym z rozwiązań tego problemu byłoby przeniesienie GRAPH do obszaru static: skoro przeznaczyć go w main, to będzie tylko jedna instancja nim tak, więc deklarowania statyczne powinno rozwiązać problem:

static GRAPH g; 

Możesz również chcieć przydzielić go w obszarze dynamicznym, używając malloc, ale w tym przypadku prawdopodobnie to nie ma znaczenia.

+0

Rozwiązaniem jest przydzielenie 'GRAPH' w sterty (używając' malloc' i przyjaciół). –

+0

dziękuję bardzo, to był dokładnie problem. Być może nie mam czasu, aby to zaimplementować, ale gdybym dynamicznie przydzielił pamięć, czy zgłosiłbym EDGE **, a następnie dodając elementy do macierzy wywołanie EDGE new = malloc (sizeof (EDGE))? – aperson231

+0

@ user3040577 Możesz zrobić to na kilka sposobów, ale najłatwiejszym jest "GRAPH" g = malloc (sizeof (GRAPH)); "Rozmiar wykresu zostałby naprawiony w tej sytuacji. Można również przydzielić dynamicznie "matrycę" - całkowicie lub częściowo. Aby częściowo go przydzielić, użyjesz 'struct edge ** matrix [756]' i przydzielisz poszczególne wiersze w razie potrzeby. Aby w pełni go przydzielić, użyjesz 'struct edge *** matrix', przydzielisz najwyższy poziom' malloc', a następnie przydzielisz wszystkie pojedyncze wiersze również 'malloc'. – dasblinkenlight

4

Twój problem nie jest "przed głównym", jak państwo, ale w pierwszych kilku liniach programu. Nie inicjujesz fp, więc może być wszędzie. Masz również błędy pamięci w pętli z new. Musisz skopiować wartość do nowo przydzielonej pamięci.

Nie można zobaczyć printf s w kodzie, ponieważ dane wyjściowe są buforowane, a kod ulega awarii przed opróżnieniem bufora. Jeśli umieścisz exit(0) tuż po twoim printf("error");, zobaczysz, że to działa.

+0

Wow, to był niesamowicie niechlujny błąd, dziękuję. – aperson231