2011-01-16 7 views
-2

Ich habe eine Datei mit Format: [Name] [Nummer] [Anzahl] Nummer wird als Zeichenfolge genommen. und ich benutze es in einem strcmp. Problem ist, dass ich einen Segmentierungsfehler bekomme. Ich weiß, dass in den meisten Fällen, wenn strcmp einen Segmentierungsfehler meldet, dies bedeutet, dass einer der Parameter null ist oder sein "Ende" ('\ 0') nicht finden kann. Ich habe mit GDB und ich kann nicht sagen, ob dies die problem.Take ist ein Blick:Segmentierung. strcmp [C]

> (gdb) bt full 
> #0 0x08048729 in lookup (hashtable=0x804b008, hashval=27, 
>  number=0x804b740 "6900101001") 
>   list = 0xffffffff 
> #1 0x080487ac in add (hashtable=0x804b008, 
>  number=0x804b740 "9900101001", name=0x804b730 "Smithpolow", 
> time=6943) 
>   new_elem = 0xffffffff 
>   hashval = 27 
> #2 0x08048b25 in main (argc=1, argv=0xbffff4b4) 
>   number = 0x804b740 "9900101001" 
>   name = 0x804b730 "Smithpolow" 
>   time = 6943 
>   i = 2 

Code:

 typedef struct HashTable 
     { 
      int length; 
      struct List *head; 

     } HashTable; 

     //(resolving collisions using chaining) 
     typedef struct List 
     { 
      char *number; 
      char *name; 
      int time; 
      struct List *next; 
     } List; 

    int primes[]={17,29,51,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899}; 
    *int PrimesIndex=1;* **int PrimesIndex=0;** **//changed.** 


    HashTable *createHashTable(size) 
    { 
     HashTable *new_table = malloc(sizeof(*new_table)*size); 

     if (new_table == NULL) 
     { return NULL; 
     } 

     int i=0; 
     for(i; i<size; i++) 
     { new_table[i].length=0; 
      new_table[i].head=NULL; 
     } 
     return new_table; 
    } 

    int hash (HashTable *hashtable,char* number) 
    { 
     int hashval = 0; 
     int i = 0; 
     for (i = 0; i < 10; i++) 
     { hashval = (hashval << 5)|(hashval >> 27); 
      hashval += (int)number[i]; 
     } 

     return hashval % primes[PrimesIndex]; 
    } 

     List *lookup (HashTable *hashtable,int hashval,char number[10]) 
     { 
     printf("NUMBER:%s\n",number); 
      List *list=hashtable[hashval].head; 
     for(list; list!=NULL; list=list->next){ 
      if (strcmp(number,list->number)==0)  
      return list; 

     } 
     return NULL; 
     } 


     int add (HashTable* hashtable,char number[10],char* name,int time) 
     { 
      List *new_elem; 
      int hashval=hash (hashtable,number); 

      new_elem=hashtable[hashval].head; 
      if(hashtable[hashval].length>0) 
      {     
        if ((lookup (hashtable,hashval,number))!=NULL) {return 0;}  
      } 

      if (!(new_elem=malloc(sizeof(struct List)))){ return -1;} 

      //insert values for the new elem 
      new_elem->number=strdup(number);  
      new_elem->name=strdup(name); 
      new_elem->time=time; 

      hashtable[hashval].head=new_elem; 
      new_elem->next=NULL; 
      hashtable[hashval].length++; 

      /* rehash existing entries if necessary */ 
      if(hashTableSize(hashtable)>= 2*primes[PrimesIndex])  
      {  
       hashtable = expand(hashtable); 
       if (hashtable ==NULL){ 
        return 0; 
       } 

      } 

      return 1; 
     } 

HashTable* expand(HashTable* h) 
{ printf("EXPAND \n"); 
    HashTable* new; 
    List *temp; 
    int n; 
    List *node,*next; 
    PrimesIndex++; 
    int new_size= primes[PrimesIndex];  /* double the size,odd length */ 

    if (!(new=malloc((sizeof( List*))*new_size))) return NULL; 

    for(n=0; n< h->length; ++n) { 
     for(node=h[n].head; node; node=next) { 
      add (new, node->number, node->name,node->time); 
      next=node->next; 
      //free(node); 
     } 
    } 
    free(h); 
    return new; 
} 

und die Haupt:

int main(int argc, char *argv[]) 
    { 
     char **token; 
     FILE *delimitedFile; 
     /*Here's an example of tokenizing lines from an actual file*/ 
     /*Open file for reading ("r"), and take a FILE pointer, 
      which you can use to fetch lines using fgets()*/ 

     my_hash_table = createHashTable(17); 
     if(my_hash_table==NULL) 
     { return 1; 
     } 

     FILE * File2; 
      if ((File2=fopen(" File.txt","r")) !=NULL) 
      { // File.txt format: [name number time] 
       int li = 0; 
       char *lin = (char *) malloc(MAX_LINE * sizeof(char)); 

       while(fgets(lin, MAX_LINE, File2) != NULL) 
       { 
        token = my_linetok(lin, " "); 
        if(token != NULL) 
        { 
      char* number ; 
      char* name; 
      int time; 
      int i; 
         for(i = 0; token[i] != NULL; i++) 
         { 
      name=strdup(token[0]); 
      number=strdup(token[1]); 
      time=atoi(token[2]); 

      if (i==2) 
      { int insertDone=0; 
       insertDone =add(my_hash_table,number,name,time); 

      } 
      } 
      free(name); 
      free(number); 
      free(token); 

        } 
        else 
      { 
         printf("Error reading line %s\n", lin); 
         exit(1); 
        } 
       } 

      } 
      else 
      { 
       printf("Error opening file \nEXIT!"); 
     exit(0); 
      } 

     return 1; 
    } 
+1

Ich kann mir vorstellen, dass dies nicht die Ursache Ihres segfault ist, aber wollen Sie nicht mit 'list-> number 'vergleichen, nicht mit' list-> name'? –

+1

Außerdem bedeutet das Backtrace, dass Sie sich in einer Funktion namens 'lookup()' befinden, die von einer Funktion mit dem Namen 'add()' aufgerufen wird. Wo sind diese? –

+0

Sie befreien 'name', aber geben Sie' number' nicht frei. Hat Ihre Funktion 'add()' Speicher zugewiesen, um sowohl 'number' als auch' name' zu ​​enthalten, oder nur für 'number'? – DReJ

Antwort

0

Sie nicht tun tatsächlich die Quelle für add(), die vermutlich lookup_on_Clients() nennt, und die Backtrace erwähnt lookup() anstelle von lookup_on_Clients(), so kann ich nicht sicher sein, aber er re meine Diagnose ist:

  • Der Backtrace sagt list = 0xffffffff - das ist definitiv keine gültige Adresse, so ist es wahrscheinlich die list->name Zugang, der die SIGSEGV verursacht.
  • Ich bin auch gestört durch die Tatsache, dass der number Parameter zu lookup_on_Clients() wie char number[10] deklariert ist und doch gdb zeigt, dass es eine 10-stellige Zahl enthält - das deutet darauf hin, dass die Variable, die das Argument dafür hält, auf die gleiche Weise deklariert wird, was bedeutet, dass kein Platz für ein abschließendes 0 Byte ist. Und die Tatsache, dass Sie strcmp() darauf aufrufen, bedeutet, dass Sie number als nullterminierte Zeichenfolge behandeln, so dass die Variable, die das Argument number als number (möglicherweise eine lokale Variable in add() deklariert? ein Array mit einer Größe von mindestens 11, um Abstürze zu vermeiden. Sie sind sicher, wenn add() gerade sein eigenes number Argument gerade durch, da das dynamisch zugewiesen wird groß genug über strdup() in main(), aber ich würde dennoch die Deklaration auf lookup_on_Clients() ändern.
+0

Ich postete add() -Funktion. Sie können überprüfen. – FILIaS

2

Sie haben keinen Platz für null Terminator in number. Sie legen die Größe number auf 10 Zeichen fest, aber Sie haben 10 Ziffern in Ihrer Nummer und keinen Platz für \ 0.

EDIT:

Ich sah Ihren aktualisierten Code. Sie haben Hashtable der ursprünglichen Größe = 17, aber Ihre hasval = 27 erstellt. Aber Sie haben keinen Code, um die Größe der Hashtabelle richtig zu erweitern.

new_elem=hashtable[hashval].head; 
if(hashtable[hashval].length>0) // <-- when hashval is out of array 
           // hashtable[hashval] can have any value of length and head (not NULL) 
+0

das ist straddup does.no? – FILIaS

+0

Während Sie sicher sind, dass \ 0 in der ursprünglichen Zeichenfolge nicht durch andere Daten ersetzt wurde, ist es in Ordnung. Aber gemeinsam ist es unberechenbares Verhalten. – DReJ

+0

Also, was soll ich besser machen? – FILIaS

3

Das hier zugrunde liegende Problem ist, dass Sie eine Hash-Tabelle mit 17 Eimern zu erstellen:

my_hash_table = createHashTable(17); 

Aber C-Arrays sind 0-basiert, und PrimesIndex beginnt bei 1, nicht 0, so innen add(), der Aufruf von hash():

int hashval=hash (hashtable,number); 

wird eine Zahl zwischen 0 und 28 zurückzukehren, nicht eine Zahl zwischen 0 und 16. Also irgendwann ein out-of-Range-Wert zugewiesen werden soll hashval, und einer der nachfolgenden Zugriffe, die durch hashval, z.B.

new_elem=hashtable[hashval].head; 

wird uninitialised Speicher liest, was letztlich zu verrückt Zeigerwerte wie 0xffffffff Oberflächen später.

Lösung: Ändern Sie int PrimesIndex = 1; zu int PrimesIndex = 0;.

Aber ehrlich gesagt denke ich, dass es andere Probleme geben könnte, die ich vermisse. Es gibt:

  • Probleme mit der for Schleife innerhalb der while Schleife in main(), die ich in den Kommentaren darauf hingewiesen habe;
  • Die zweifelhafte Deklaration für den Parameter number zu lookup_on_Clients();
  • Die Tatsache, dass manchmal die Funktion heißt lookup() und manchmal lookup_on_Clients() (wie von Oli bemerkt);
  • Und ich traue nicht, dass my_linetok() (für die Sie keine Quelle anzeigen) ordnungsgemäß funktioniert - zumindest wenn es einen statischen Puffer verwendet, muss es ein Array von char * zuweisen, um die zu halten Zeiger auf die einzelnen Tokens, die niemals freigegeben werden - ein Speicherleck.
+0

Das stimmt. Nun, der einzige Grund, warum PrimesIndex 1 war, ist, dass ich von Anfang an eine Hash-Tabelle mit 17 Eimern (die erste Zahl auf Primzahlen) erstellt habe, also dachte ich, es wäre sinnlos, sie von 0 aus zu starten. Wie auch immer, ich glaube dasselbe nicht das das ernste Problem. (EDIT: Ich meinte PrimesIndex, für jeden Fall änderte ich es!) – FILIaS

+0

@FILIaS: ** JA ** das ist ** das ** Problem. Was verstehst du nicht über meine Erklärung? –

+0

@j_random_hacker. Für den ersten: Ich habe das schon geändert. Zweiter Hinweis: zweifelhaft ja. Aber was kann ich besser machen? Dritte Anmerkung: Thats from Copy Paste beachten Sie diese nicht. Vierte: Für was ich sehe, hat dieser Code Lecks. Aber das soll ich nicht ändern, also ... – FILIaS