Trimmfunktion in C

Ich versuche, eine idiomatische Trimmfunktion in C zu schreiben. Wie sieht das aus? Soll ich stattdessen die neue Zeichenfolge mallocieren und zurückgeben?

void trim(const char *input, char *result) { int i, j = 0; for (i = 0; input[i] != "\0"; i++) { if (!isspace(input[i])) { result[j++] = input[i]; } } } 

Kommentare

  • Dort ‚ ist eine Reihe von Problemen mit diesem Code. ‚ ist anfällig für Pufferüberlaufangriffe und ‚ Nicht tun, was eine typische “ trim “ -Funktion tut. Durch Trimmen werden führende und nachfolgende Leerzeichen entfernt. Dadurch werden sie alle entfernt.
  • Danke. Können Sie bitte erläutern, wie mit Pufferüberlaufangriffen umgegangen werden soll?
  • Sie sollten Daten niemals blind in einen Puffer kopieren, wenn Sie ‚ nicht wissen, wie viel Speicherplatz zugewiesen ist dazu bittet ‚ nur um Ärger. Eine einfache Sache wäre, einen Parameter hinzuzufügen, der die Größe des Puffers berücksichtigt. Auf diese Weise muss ‚ der Anrufer angeben, wie groß er wirklich ist. Dann liegt es an Ihnen, ‚ niemals zu versuchen, über die angegebene Länge hinaus zu lesen / schreiben. Natürlich ist es ‚ nicht narrensicher, der Anrufer kann Ihnen falsche Längen geben, aber das wäre ein Problem für sie, nicht für Sie.

Antwort

Wie @JeffMercado hervorhob, werden dadurch Leerzeichen entfernt, anstatt führende und nachfolgende Leerzeichen zu kürzen. Angenommen, Sie möchten die aktuelle Funktionalität beibehalten, nennen wir sie remove_spaces.

Hier gibt es einen wirklich subtilen Fehler:

... isspace(input[i]) ... 

isspace nimmt den Wert eines vorzeichenlosen Zeichens oder EOF. Wenn Sie ein char übergeben, das normalerweise signiert ist, wird ein undefiniertes Verhalten erzeugt. Sagen Sie stattdessen:

... isspace((unsigned char) input[i]) ... 

Ein weiterer Fehler: Sie geben keinen NUL-Terminator aus, was bedeutet, dass der Anrufer nicht wissen kann, wie lang die Zeichenfolge ist ( es sei denn, der Puffer wurde vor dem Aufrufen Ihrer Funktion auf Null gesetzt.

Das Beheben dieser Fehler führt zu folgenden Ergebnissen:

void remove_spaces(const char *input, char *result) { int i, j = 0; for (i = 0; input[i] != "\0"; i++) { if (!isspace((unsigned char) input[i])) { result[j++] = input[i]; } } result[j] = "\0"; } 

@JeffMercado sagte auch diese Funktion ist in gewissem Sinne nicht wahr, vorausgesetzt, der Anrufer weiß, dass er einen Puffer von mindestens strlen(input) + 1 zuweisen muss. Der Anrufer ist jedoch möglicherweise faul und sagt nur char result[100]. Das Hinzufügen eines Ausgabepuffergrößenparameters schützt wahrscheinlich vor einem solchen Fehler:

void remove_spaces(const char *input, char *output, size_t output_size); 

Überprüfen Sie, ob Sie dies implementieren können Einige Dinge, die Sie beachten sollten:

  • Vergessen Sie nicht den NUL-Terminator, wenn Sie die Größe des Ausgabepuffers überprüfen.

  • Seien Sie nicht wie strncpy und lassen Sie den NUL-Terminator weg, wenn Sie die Zeichenfolge abschneiden müssen, da dies zu subtilen Fehlern führen kann.

  • Wenn Sie int für i und j und verwenden size_t Für output_size sollten Sie Compiler-Warnungen zum Vergleich zwischen signierten und nicht signierten erhalten. Wenn Sie dies nicht tun, erhöhen Sie die Compiler-Warnungen. Wenn Sie GCC über die Befehlszeile verwenden, gewöhnen Sie sich an, gcc -Wall -W einzugeben.

Kommentare

  • strncpy() ist selbst keine Zeichenfolgenfunktion obwohl einige annehmen. Das Ergebnis als String wäre also sowieso Zufall. Das macht die Analogie bestenfalls lückenhaft.

Antwort

Wir wissen, dass wir einen Zeiger vorwärts und rückwärts bewegen können und wir wissen auch, dass wir eine Saite von links abschneiden können. Wenn wir den Zeiger inkrementieren und den Zeiger dekrementieren, um ihn von rechts zu trimmen, reichen zwei while -Schleifen aus. Sie werden feststellen, dass die Anzahl der rechten Schritte geringer ist als die Anzahl der linken Schritte.

Code für den rechten Schnitt:

#include <stdio.h> #include <ctype.h> void trim_both(char *, char *); int main (void) { char title[100] = " My long string "; char title_t[100] = ""; (void) printf("String before left trim is:[%s]\n", title); trim_both(title, title_t); (void) printf("String after left trim is:[%s]\n", title_t); } // trim spaces from left void trim_both(char *title_p, char *title_tp) { int flag = 0; // from left while(*title_p) { if(!isspace((unsigned char) *title_p) && flag == 0) { *title_tp++ = *title_p; flag = 1; } title_p++; if(flag == 1) { *title_tp++ = *title_p; } } // from right while(1) { title_tp--; if(!isspace((unsigned char) *title_tp) && flag == 0) { break; } flag = 0; *title_tp = "\0"; } } 

Antwort

Einfachster Weg (entfernt nur Leerzeichen):

Trim.Start:

  1. Vergleichen Sie die Zeichen bis Sie entsprechen " " (Leerzeichen oder andere Zeichen wie \n oder \t) beim Start der Zeichenfolge und inkrementieren Sie die Variable temp (i).
  2. Bewegen Sie den Zeiger um i (str+=i). Jetzt beginnt die Zeichenfolge mit char, das kein Leerzeichen (oder ein anderes weißes Zeichen) ist.

Trim.End:

  1. Machen Sie dasselbe für Trim.Start, jedoch ab dem Ende der Zeichenfolge.
  2. Setzen Sie das letzte Zeichen (letztes Leerzeichen) als \0.

Wichtig ist, dass die Funktion Zeiger auf Zeiger (Zeichenfolge) nimmt.Achten Sie auf den Funktionsaufruf: StringTrim(&p2);

char * StringTrim(char * *pointerToString) { u8 start=0, length=0; // Trim.Start: length = strlen(*pointerToString); while ((*pointerToString)[start]==" ") start++; (*pointerToString) += start; if (start < length) // Required for empty (ex. " ") input { // Trim.End: u8 end = strlen(*pointerToString)-1; // Get string length again (after Trim.Start) while ((*pointerToString)[end]==" ") end--; (*pointerToString)[end+1] = 0; } return *pointerToString; } 

Verwendung:

 char str1[] = " test1 "; char * p1 = str1; Debug("1. before trim: [%s]", p1); StringTrim(&p1); Debug("1. after trim [%s]", p1); char str2[] = " test2"; char * p2 = str2; Debug("2. before trim: [%s]", p2); StringTrim(&p2); Debug("2. after trim [%s]", p2); char str3[] = "test3 "; char * p3 = str3; Debug("3. before trim: [%s]", p3); StringTrim(&p3); Debug("3. after trim [%s]", p3); char str4[] = " "; char * p4 = str4; Debug("4. before trim: [%s]", p4); StringTrim(&p4); Debug("4. after trim [%s]", p4); char str5[] = ""; char * p5 = str5; Debug("5. before trim: [%s]", p5); StringTrim(&p5); Debug("5. after trim [%s]", p5);  

Ergebnis :

 1. before trim: [ test1 ] 1. after trim [test1] 2. before trim: [ test2] 2. after trim [test2] 3. before trim: [test3 ] 3. after trim [test3] 4. before trim: [ ] 4. after trim [] 5. before trim: [] 5. after trim []  

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.