2017-06-30 4 views
0

Ich versuche, dies zu debuggen und herauszufinden, was den Segmentierungsfehler verursachen kann. Ich bin ziemlich neu. Dies ist eine kleine Methode, die Duplikate entfernen soll, die innerhalb eines Arrays aufeinander folgen.Segmentierung Fehler w/Zeichenarrays & Zeiger

void removeddup(char *str){ 
    int i; 
    int j; 
    int len= str_len(str)-1; 
    int removed = 0; 
    for(i=0; i < (len-removed);) 
    { 
     if(str[i]==str[i+1]) 
     { 
      for(j=i; i<(len-removed);j++) 
      str[j]=str[j+1]; 
      removed++; 
     }else{ 
     i++; 
     } 
    } 
} 

es so

char str1[100] 
case '6': 
     removeddup(str1); 
     break; 
+3

'for (j = i; i <(LEN-entfernt); j ++)': Da 'i <(LEN-entfernt)' ändert sich nicht, es kann eine Endlosschleife verursachen. – BLUEPIXY

+2

@BLUEPIXY 'else {i ++; } ' – Barmar

+0

Wie rufen Sie Ihre Funktion? – AnT

Antwort

0

genannt wird Ihre Idee ist nicht schlecht, ist ein Problem hier

for(j=i; i<(len-removed);j++) 
    str[j]=str[j+1]; 

halten Sie j erhöht wird, aber die Bedingung i<(len-removed) wird wahr für immer halten. An einem bestimmten Punkt versuchen Sie zu lesen und in den Speicher schreiben weit über Grenzen Ihres Gedächtnisses und Sie werden am Ende mit einem segfault (wie Peter sagte). Ihr Problem ist, dass Sie nicht korrekt berechnen, wie viele Zeichen es gibt.

Angenommen, Sie tun, dass

str[j]=str[j+1]; 

auch nicht sehr effizient ist. Ich bekomme den Punkt, Sie versuchen, in das nächste Zeichen zu kopieren, bis Sie \0 finden. Lassen Sie uns sagen, Ihre Eingabe ist abccccddddeee, das ist eine schrecklich lange Anzahl von einzelnen Kopien, die Sie tun werden.

Es wäre am besten, die Anzahl der doppelten Kopien zu berechnen und dann memmove zu verwenden, um den gesamten Speicherblock auf einmal zu verschieben, was effizienter ist.

Ich änderte Sie Code mit memmove anstelle Ihrer Ansatz. Ich ließ auch Kommentare erklären, wie man die Länge der Duplikate und die Parameter von memmove berechnet, die manchmal hart sein können. Normalerweise nehme ich ein Stück Papier und mache es zuerst von Hand, dann bekommst du viel schneller die Idee.

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

void removeddup(char *str){ 
    int i; 
    int j; 
    int len= strlen(str)-1; 
    int removed = 0; 

    for(i=0; i < (len-removed);) 
    { 
     if(str[i]==str[i+1]) 
     { 
      // we calculate the length of the duplicates 
      j = 0; 
      while(str[i] == str[i + ++j]); 

      // we have j duplicates of str[i] (counting str[i]) 
      // we copy the rest of the string after the j-1 duplicates 
      // the destination is the next character after str[i] (str + i +1) 
      // the source is str[i+j] 
      // 
      // now we have to determine how many chars to copy. In general 
      // you do string_length - index_of_source + 1, which also copies 
      // the \0 string-terminating character. 
      // 
      // In your case 
      // string_length: len - removed + 1 (the +1 because you 
      //     defined len := strlen(str)-1; 
      // index_of_source: i + j 
      // ==> len - removed + 1 - (i + j) + 1 
      // so 

      memmove(str + i + 1, str + i + j, len - removed + 1 - (i+j) + 1); 

      // now we set how many characters we've removed 
      removed += j - 1; 

      // we go the next character 
      i++; 

     }else{ 
      i++; 
     } 
    } 
} 


int main(void) 
{ 

    char text[] = "abccccccdeeefffffffffffff"; 

    printf("Original: %s\n", text); 
    removeddup(text); 
    printf("removed: %s\n", text); 

    return 0; 
} 

Beachten Sie auch, dass diese Methode funktioniert nur, wenn Sie Schreibzugriff auf den Puffer haben. Wenn Sie ein Zeichenfolgenliteral übergeben (const char *text = "abcdddd";), , erhalten Sie eine segfault, da Zeichenfolgenliterale im schreibgeschützten Speicher sind.

Beachten Sie auch, dass die Zeile mit den while endet mit ;

while(condition); 

// is equivalent to 

while(condition) 
{ 
}