Funzione trim in C

Sto cercando di scrivere una funzione trim idiomatica in C. Che aspetto ha? Devo invece mallocare la nuova stringa e restituirla?

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]; } } } 

Commenti

  • Ecco ‘ un numero di problemi con quel codice, ‘ è vulnerabile agli attacchi di buffer overflow e non ‘ fare quello che fa una tipica funzione ” trim “. Trim rimuove gli spazi bianchi iniziali e finali. Questo li elimina tutti.
  • Grazie. Puoi spiegarci come gestire gli attacchi di overflow del buffer?
  • Non dovresti mai copiare alla cieca i dati in un buffer quando non ‘ non sai quanto spazio è allocato ad esso, che ‘ sta solo cercando guai. Una cosa semplice da fare sarebbe aggiungere un parametro che prende la dimensione del buffer. In questo modo ‘ è tutto a disposizione del chiamante per dirti quanto è veramente grande. Quindi spetta a te ‘ non tentare mai di leggere / scrivere oltre la lunghezza specificata. Ovviamente ‘ non è a prova di errore, il chiamante può darti lunghezze fasulle, ma questo sarebbe un problema da parte loro, non tuo.

Risposta

Come ha sottolineato @JeffMercado, questo rimuove gli spazi invece di tagliare gli spazi iniziali e finali. Supponendo che tu voglia mantenere la funzionalità corrente, chiamiamola remove_spaces.

Cè “un bug davvero sottile qui:

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

isspace assume il valore di un carattere non firmato o EOF. Passandogli un char, che di solito è firmato, produrrà un comportamento indefinito. Pronuncia invece:

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

Un altro bug: non emetti un terminatore NUL, il che significa che il chiamante non avrebbe modo di sapere quanto è lunga la stringa ( a meno che non abbia azzerato il buffer prima di chiamare la funzione).

La correzione di questi bug ci dà:

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 ha detto anche questa funzione è vulnerabile alloverflow del buffer. In un certo senso, questo non è vero, a condizione che il chiamante sappia di allocare un buffer di almeno strlen(input) + 1. Ma il chiamante potrebbe essere pigro e dire semplicemente char result[100]. Laggiunta di un parametro della dimensione del buffer di output probabilmente eviterà un errore del genere:

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

Verifica se riesci a implementarlo . Alcune cose da tenere a mente:

  • Non dimenticare il terminatore NUL quando controlli la dimensione del buffer di output.

  • Non essere come strncpy e ometti il terminatore NUL quando devi troncare la stringa, in quanto può portare a piccoli bug.

  • Se utilizzi int per i e j e size_t per output_size, dovresti ricevere avvisi del compilatore sul confronto tra firmato e non firmato. Se non lo fai, attiva gli avvisi del compilatore. Se stai utilizzando GCC dalla riga di comando, prendi labitudine di digitare gcc -Wall -W.

Commenti

  • strncpy() non è una funzione stringa, anche anche se alcuni presumono. Quindi il risultato che è una stringa sarebbe comunque un caso. Il che rende lanalogia nel migliore dei casi approssimativa.

Risposta

Sappiamo che possiamo spostare un puntatore avanti e indietro e sappiamo anche che possiamo tagliare una stringa da sinistra. Se incrementiamo il puntatore e lo riduciamo per tagliare da destra, allora sono sufficienti due cicli while. Noterai che il conteggio della camminata a destra è inferiore al conteggio della camminata a sinistra.

Codice di assetto a destra:

#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"; } } 

Risposta

Modo più semplice (rimuove solo gli spazi):

Taglia.Start:

  1. Confronta caratteri fino a sono uguali a " " (spazio o altri caratteri come \n o \t) allinizio della stringa e incrementa la variabile temp (i).
  2. Sposta il puntatore su i (str+=i). Ora la stringa inizia da char che non è uno spazio char (o qualsiasi altro carattere bianco).

Trim.End:

  1. Fai la stessa cosa per Trim.Start ma dalla fine della stringa.
  2. Imposta lultimo carattere (ultimo spazio) come \0.

La cosa importante è che la funzione prenda il puntatore al puntatore (stringa).Guarda la chiamata di funzione: 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; } 

Utilizzo:

 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);  

Risultato :

 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 []  

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *