Cette fonction vérifie si une sous-chaîne needle
existe ou non dans une autre chaîne haystack
et renvoie la position si oui ou 0 si ce n’est pas le cas, sauf si le la position est 0, auquel cas il ne sera pas localisé.
Recherche de moyens daméliorer ce code, en particulier une meilleure gestion des erreurs.
#include <stdio.h> #include <stdlib.h> #include <string.h> size_t contains(const char * needle, const char *haystack); int main(void) { char *needle = "test"; char *haystack = "This is a dinosaurtest."; printf("Position: %lu", contains(needle, haystack)); return EXIT_SUCCESS; } size_t contains(const char * needle, const char *haystack) { if(needle == NULL || haystack == NULL) { return 0; } long int first_char_pos = -1; size_t len_h = strlen(haystack); size_t len_n = strlen(needle); size_t i, j; size_t exist_count = 0; // Find the first character. If it doesn"t exist, we"re done. for(i = 0; i < len_h; i++) { if((haystack[i] == needle[0]) && (first_char_pos == -1)) { first_char_pos = i; exist_count++; } } if(first_char_pos == -1) { return 0; } printf("First char match index: %li\n", first_char_pos); printf("Char: %c\n", haystack[first_char_pos]); size_t current_index = (size_t) first_char_pos; for(i = first_char_pos; i < len_h; i++) { if(haystack[i] == needle[exist_count] && (i == (current_index + 1))) { current_index = i; exist_count++; } printf("Exist count: %lu\n", exist_count); //<--Debugging if(exist_count == len_n) { return first_char_pos; } } return 0; }
Commentaires
Réponse
Juste quelques remarques:
-
Vous devriez ajouter une nouvelle ligne après la dernière ligne:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Je ne sais pas quoi compilateur que vous utilisez mais avec une fois compilé avec
gcc
et-Wall -Wextra -pedantic
vous obtenez:gcc -O2 nh.c -lm -o nh -Wall -Wextra -pedantic nh.c: In function ‘contains’: nh.c:25:15: warning: unused variable ‘j’ [-Wunused-variable] size_t i, j; ^
-
La mise en forme du code doit être plus cohérente. Par exemple, dans cette ligne, vous mettez un espace avant
needle
mais ne mettez pas despace avanthaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
nest pas un spécificateur portable pour le typesize_t
, vous devez utiliser%zu
introduit dans C99. -
Vous avez dit:
renvoie la position si cest le cas ou 0 si ce nest pas le cas, sauf si le la position est 0, auquel cas, il « ne sera pas localisé.
Ce nest vraiment pas bon. Par exemple, avec ceci, il renvoie 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Avec ceci, il renvoie également zéro:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Vous ne pouvez « pas faire la différence entre le succès et léchec dans ces deux exemples. En fait, atoi()
a le même problème. Je ne sais pas quel système dexploitation vous utilisez mais peut-être que vous pourriez utiliser ssize_t
comme type de retour sil est disponible et renvoyer -1 en cas déchec.
Réponse
Pour compléter la réponse précédente de @Arkadiusz Drabczyk:
Une implémentation simple et triviale de contains
pourrait être fait comme ceci:
ssize_t contains(const char * needle, const char *haystack) { char *needle_in_haystack; if(!needle || !haystack) return -1; needle_in_haystack = strstr(haystack, needle); return needle_in_haystack ? needle_in_haystack - haystack : -1; }
Ensuite, ce programme (avec quelques changements comme mentionné ci-dessus) devrait fonctionner:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> ssize_t contains(const char * needle, const char *haystack) { char *needle_in_haystack; if(!needle || !haystack) return -1; needle_in_haystack = strstr(haystack, needle); return needle_in_haystack ? needle_in_haystack - haystack : -1; } int main(void) { char *needle = "test"; char *haystack = "This is a dinosaurtest."; char *haystack2 = "This does not contain the string."; printf("Position: %zd\n", contains(needle, haystack)); printf("Position: %zd\n", contains(needle, haystack2)); return EXIT_SUCCESS; }
Résultat:
Position: 18
Position: -1
Commentaires
- Je supprimerais la vérification que lentrée nest pas NULL, et ju st utiliser une extension de langue pour cela (
__attribute__((nonnull))
dans GCC).NULL
est quelque chose auquel vous ne vous attendriez jamais comme entrée pour cette fonction, et il ajoute une ou deux lignes de code inutiles. Je préférerais écrire dans la documentation de la fonction quelque chose comme: » Si lentrée de cette fonction est un pointeur NULL, le comportement nest pas défini. « . - @CacahueteFrito Le code dorigine la fait, et je veux rechercher la compatibilité (qui sait comment lOP lutilisait?).
- Inclusion manquante pour
ssize_t
:#include <sys/types.h>
. Une autre option serait dutiliser à la placeptrdiff_t
, de#include <stddef.h>
; vous renvoyez en fait une différence de pointeur:? needle_in_haystack - haystack :
Answer
Votre code ne fonctionne pas. Il renvoie 0
pour haystack
"abbc"
et needle
"bc"
, même si haystack
contient needle
.
Réponse
Vous navez pas besoin de la première boucle et de tous les calculs de longueur. Btw., La fonction ne réussit pas, si le premier caractère est trouvé, mais seule la deuxième occurrence du premier caractère correspond à laiguille.
La tâche peut être réduite à quelques lignes:
int contains(char *buf, char *needle) { char *src, *srch, *srcp; for(src=buf; *src; src++) { for(srch = needle, srcp = src; *srch && *srcp && *srch == *srcp; srch++, srcp++); if(!*srch) return src - buf; } return -1; }
Commentaires
- Quel est un bon moyen daméliorer lécriture de code C plus compact et efficace comme celui-ci ?Cela me rappelle K & R C.
strstr()
. Il existe ‘ une version plus sûre appeléestrnstr()
. Vous pouvez trouver une implémentation ici: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
renvoie true?