Fonction Trim en C

Jessaie décrire une fonction Trim idiomatique en C. A quoi ça ressemble? Dois-je à la place valider la nouvelle chaîne et la renvoyer?

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

Commentaires

  • Là ‘ est un certain nombre de problèmes avec ce code, il ‘ est vulnérable aux attaques par débordement de tampon et il nest pas ‘ t faire ce que fait une fonction  » trim « . Trim supprime les espaces blancs de début et de fin. Cela les enlève tous.
  • Merci. Pouvez-vous expliquer comment gérer les attaques par débordement de tampon?
  • Vous ne devez jamais copier aveuglément des données dans un tampon lorsque vous ne savez pas ‘ combien despace est alloué à lui, que ‘ ne fait que demander des ennuis. Une chose simple à faire serait dajouter un paramètre qui prend en compte la taille du tampon. De cette façon, ‘ est tout sur lappelant pour vous dire à quel point il est vraiment grand. Ensuite, il ‘ à vous de ne jamais tenter de lire / écrire au-delà de la longueur donnée. Bien sûr, ce ‘ n’est pas infaillible, l’appelant peut vous donner de fausses longueurs, mais ce serait un problème de son côté, pas du vôtre.

Réponse

Comme @JeffMercado la souligné, cela supprime les espaces au lieu de couper les espaces de début et de fin. En supposant que vous souhaitiez conserver la fonctionnalité actuelle, appelons-la remove_spaces.

Il existe « un bug vraiment subtil ici:

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

isspace prend la valeur dun caractère non signé ou EOF. Lui passer un char, qui est généralement signé, produira un comportement indéfini. À la place, dites:

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

Autre bogue: vous némettez pas de terminateur NUL, ce qui signifie que lappelant naurait aucun moyen de savoir combien de temps la chaîne est ( sauf sil a remis à zéro le tampon avant dappeler votre fonction).

La correction de ces bogues nous donne:

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 a également dit cette fonction est vulnérable au dépassement de la mémoire tampon. Dans un sens, ce nest pas vrai, à condition que lappelant sache allouer un tampon dau moins strlen(input) + 1. Mais lappelant peut être paresseux et dire simplement char result[100]. Lajout dun paramètre de taille de tampon de sortie vous évitera probablement une telle erreur:

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

Voyez si vous pouvez limplémenter . Quelques points à garder à lesprit:

  • Noubliez pas le terminateur NUL lorsque vous vérifiez la taille du tampon de sortie.

  • Ne soyez pas comme strncpy et omettez le terminateur NUL lorsque vous devez tronquer la chaîne, car cela peut entraîner des bogues subtils.

  • Si vous utilisez int pour i et j et size_t pour output_size, vous devriez recevoir des avertissements du compilateur concernant la comparaison entre signé et non signé. Si vous ne le faites pas, affichez les avertissements de votre compilateur. Si vous utilisez GCC depuis la ligne de commande, prenez lhabitude de taper gcc -Wall -W.

Commentaires

  • strncpy() nest pas une fonction de chaîne, même bien que certains supposent. Donc, le résultat étant une chaîne serait de toute façon un hasard. Ce qui rend lanalogie au mieux fragmentaire.

Réponse

Nous savons que nous pouvons déplacer un pointeur vers lavant et vers larrière , et nous savons également que nous pouvons couper une chaîne à partir de la gauche. Si nous incrémentons le pointeur et décrémentons le pointeur pour découper à partir de la droite, alors deux boucles while suffisent. Vous remarquerez que le nombre de pas à droite est inférieur au nombre de pas à gauche.

Code de coupe à droite:

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

Réponse

Méthode la plus simple (supprime uniquement les espaces):

Trim.Start:

  1. Comparez les caractères jusquà ils sont égaux à " " (espace ou autres caractères comme \n ou \t) au début de la chaîne et incrémenter la variable de température (i).
  2. Déplacer le pointeur sur i (str+=i). La chaîne commence maintenant par char qui nest pas un caractère despace (ni aucun autre caractère blanc).

Trim.End:

  1. Faites de même pour Trim.Start mais à partir de la fin de la chaîne.
  2. Définissez le dernier caractère (dernier espace) comme \0.

La chose importante est que la fonction prend le pointeur sur le pointeur (chaîne).Surveillez lappel de fonction: 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; } 

Utilisation:

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

Résultat :

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

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *