2017-06-21 11 views
1

Ich schrieb den folgenden Code mit der Absicht, Zeigerarithmetik auf Zeichenfolgen zu verwenden, um eine gezielte Teilzeichenfolge zu finden und zu ersetzen. Offensichtlich ist es nicht elegant, aber leider ist es auch falsch - es fügt der Saite irrsinnige Charaktere hinzu.Suchen und Ersetzen einer Teilzeichenfolge (Sprache C)

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

int main() { 
    char string[] = "The quick brown fox jumped over the lazy dog."; 
    char target[] = "brown" 
    char replacement[] = "ochre"; 
    char segment[80+1]; 
    char pre_segment[80+1]; 
    char post_segment[80+1]; 
    int S = strlen(string), T = strlen(target); 
    for (int i = 0; i < S; i++) { 
     strncpy(segment, string + i, T); 
     if (strcmp(segment, target) == 0) { 
     >>> strncpy(pre_segment, string, i); <<< 
      strncpy(post_segment, string + i + T, 
       S - (i + T)); 
      strcat(pre_segment, replacement); 
      strcat(pre_segment, post_segment); 
      printf("%s\n", pre_segment); 
     } 
    } 
    return 0; 
} 

Nachdem die Zeile wie markiert >>> diese < < <, irrelevante Zeichen wurden Ersatz vorangestellt, bevor ein Austausch mit pre_segment verkettet.

Kann mir jemand Vorschläge zum Debuggen geben? (Vorschläge für eine bessere Lösung sind ebenfalls willkommen, aber bitte versuchen Sie explizit zu sein. Ich sollte auch keine dynamische Speicherzuweisung verwenden.)

+0

„wie dies zu debuggen“? So wie Sie die meisten Programme debuggen würden. Verwenden Sie einen Debugger, um durch den Code zu gehen und den Status zu untersuchen, während Sie fortfahren. – kaylum

+0

@kaylum Ich kann dir sagen, wo es falsch läuft; Ich hatte gehofft, dass jemand, der sachkundiger ist, mir helfen könnte, * warum * zu verstehen. – Chris

+1

Warum erzählst du uns dann nicht, wo es falsch läuft? Das wären nützliche Informationen - damit wir das nicht selber debuggen müssen und auch zeigen, dass Sie es getan haben. Und Sie haben explizit gefragt, wie Sie das debuggen können. – kaylum

Antwort

5

Verwenden Sie nicht strncpy. Es tut fast sicher nicht, was Sie denken, dass es tut. Insbesondere garantiert es keine NULL-Beendigung, während es die Leute täuscht, dies zu tun. Wenn Sie genau n Zeichen kopieren möchten, verwenden Sie memcpy(dest, src, n); und dann explizit NUL-terminieren Sie mit dest[n] = '\0';. Der Mangel an NUL-Kündigung ist wahrscheinlich Ihre Probleme verursachen. (Überprüfen Sie das in Ihrem Debugger!)

Allerdings ist es nicht notwendig, die strncpy überhaupt zu tun. Verwenden Sie strncmp oder memcmp. (Verwenden Sie nur memcmp, wenn Sie wissen, dass mindestens strlen(target) Bytes in der Zeichenfolge verbleiben.) Wenn strlen(target) Bytes beginnend an einem bestimmten Punkt in string übereinstimmen target, dann haben Sie eine Übereinstimmung gefunden.

Noch besser wäre es, strstr zu verwenden, um das nächste Vorkommen der Zeichenfolge zu finden.

+0

Vielen Dank. Ich bin gleich wieder da, nachdem ich es versucht habe! – Chris

+0

Ihr Vorschlag funktionierte genau für mich, also wenn es Ihnen nichts ausmacht, kann ich einige Nachfragen stellen? (1) Woher wussten Sie, dass das was falsch war, und (2) wie würden Sie dieses genaue Problem in einem Debugger identifizieren? (d. h. wie würde es "aussehen"?) – Chris

+1

@chris: "fügt irrelevante Zeichen hinzu" bedeutet häufig eine nicht abgeschlossene Zeichenkette, und ein Missbrauch von "strncpy" führt oft zu nicht abgeschlossenen Zeichenketten. Also begann ich mit einer Voreingenommenheit basierend auf Erfahrung. Sie werden es in einem Debugger sehen, wenn Sie sehen, dass strlen einen unerwarteten Wert (oder segfaults) gibt oder dass irrelevante Zeichen gedruckt werden, oder indem Sie nach dem NUL-Terminator suchen und ihn nicht finden. 'strncpy' ist für die Verwendung mit gepackten Datenbankfeldern mit fester Länge gedacht, aber es war eine Mythologie entstanden, dass es irgendwie sicherer ist als strcpy. Es ist also immer einen Blick wert. – rici

0

Ich kann nicht mit @rici übereinstimmen, dass die Funktion strncpy nicht verwendet werden soll. Jede Funktion kann falsch verwendet werden. Und strncpy ist keine Ausnahme. Sie sollten nicht vergessen, dass die Funktion keine Zeichenfolge kopieren muss. Sie müssen also selbst ein Null-Zeichen an die kopierte Folge von Zeichen anhängen.

Und Sie haben vergessen, dies zu tun.

Obwohl Ihre Implementierung zu kompliziert und verwirrend ist, sollte sie auf jeden Fall sorgfältig geschrieben werden.

Hier ist eine aktualisierte Version Ihres Programms. Achten Sie auf diese Aussagen

segment[T] = '\0'; 
pre_segment[i] = '\0'; 
post_segment[S - (i + T)] = '\0'; 

Oder wenn Sie tp Verwendung Zeiger bevorzugen, dann Sie

*(segment + T) = '\0'; 
*(pre_segment + I) = '\0'; 
*(post_segment + S - (i + T)) = '\0'; 

Hier schreiben könnte Sie sind.

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

int main(void) 
{ 
    char string[] = "The quick brown fox jumped over the lazy dog."; 
    char target[] = "brown"; 
    char replacement[] = "ochre"; 
    char segment[80+1]; 
    char pre_segment[80+1]; 
    char post_segment[80+1]; 

    size_t S = strlen(string), T = strlen(target); 

    for (size_t i = 0; i < S; i++) 
    { 
     strncpy(segment, string + i, T); 
     segment[T] = '\0'; 

     if (strcmp(segment, target) == 0) 
     { 
      strncpy(pre_segment, string, i); 
      pre_segment[i] = '\0'; 

      strncpy(post_segment, string + i + T, S - (i + T)); 
      post_segment[S - (i + T)] = '\0'; 

      strcat(pre_segment, replacement); 
      strcat(pre_segment, post_segment); 
      printf("%s\n", pre_segment); 
     } 
    } 

    return 0; 
} 

Die Programmausgabe ist

The quick ochre fox jumped over the lazy dog. 
+3

Ich habe die Kommentare von @rici nicht gelesen, um zu sagen, dass 'strncpy()' niemals verwendet werden sollte; Es wird sicherlich oft missbraucht. Es gibt eine reflexartige Tendenz unter einigen, irgendeine Instanz von "strcpy()" in "strncpy()" im Interesse von "Sicherheit" umzuwandeln, und dies ist nicht immer die richtige Wahl. –

+0

Ich, äh, erhöhte deinen Ruf (diese Seite hasst solche Kommentare anscheinend). Ich schätze es, dass Sie die Bedeutung der Nullzeichen nach dem Kopieren ausdrücken. – Chris

1

Sie sollten immer versuchen, Ihren Code in kleinere Teile (Funktionen) zu teilen, können wir zwei wichtige Schritte im Prozess identifizieren einen Teil zu ersetzen, den Teil finden und dann ersetzt es. Dies ist eine Lösung, die ich für Sie vorschlage, es ist jetzt drei Jahre her, seit ich meine letzten c Zeile Code geschrieben so dass diese nicht perfekt, aber es macht den Job:

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


int find_occurence(char* original, char *target){ 
    size_t counter = 0; 
    char *index = original; 
    do{ 
    while(target[counter] == index[counter]) 
     counter++; 
    if (counter >= strlen(target)) 
     return (int)(index-original); 
    else 
     counter = 0; 
    } 
    while(*(index++)); 
    return -1; 
} 

void replace(char *original, char *target, char *replacement,char *destination){ 
    int index = find_occurence(original, target); 
    if (index == -1) 
    { 
    strncpy (destination, original, strlen(original)+1); 
    return; 
    } 

    char *last_part; 

    //Copy the string before target 
    strncpy (destination, original, index); 

    //Copy the replacement 
    strncpy (&destination[index], replacement, strlen(replacement)); 

    //Extract the part after the target 
    last_part = &original[index+strlen(target)]; 

    //Copy the part after the target plus the \0 character 
    strncpy (&destination[index+strlen(replacement)],last_part,strlen(last_part)+1); 
} 


int main() { 
    char *original = "I want to replace literally this by that"; 
    char *target = "this"; 
    char *replacement = "that"; 
    char destination[100]; 

    replace(original,target,replacement, destination); 

    printf("%s\n",destination); 


} 
+0

Dies könnte, wie ich schon sagte, nicht annähernd perfekt, der Leser sollte darauf aufbauen, aber ich werde es überprüfen und aktualisieren, danke für die wichtigen Hinweise – SEDaradji

+0

Ich habe den obigen Code behoben, ich glaube, es ist akzeptabel als Lösung in seinem aktueller Stand – SEDaradji

+0

Danke für die Unterstützung, es ist über drei Jahre her, seit ich aufgehört habe in c zu codieren, das sollte es tun – SEDaradji