Această funcție verifică dacă există sau nu un subșir needle
există într-un alt șir haystack
și returnează poziția dacă există sau 0 dacă nu „t, cu excepția cazului în care poziția este 0, caz în care nu va fi localizat.
Căutați modalități de a îmbunătăți acest cod, în special o mai bună gestionare a erorilor.
#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; }
Comentarii
Răspuns
Doar câteva observații:
-
Ar trebui să adăugați o linie nouă după ultima linie:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Nu știu ce compilator pe care îl utilizați, dar când este compilat cu
gcc
și-Wall -Wextra -pedantic
veți obține: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; ^
-
Formatarea codului ar trebui să fie mai consistentă. De exemplu, în această linie puneți un spațiu înainte de
needle
, dar nu puneți un spațiu înaintehaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
nu este un specificator portabil pentru tipulsize_t
, ar trebui să utilizați%zu
introdus în C99. -
Ați spus:
returnează poziția dacă o face sau 0 dacă nu, cu excepția cazului în care poziția este 0, caz în care nu va fi localizat.
Acest lucru nu este chiar bun. De exemplu, cu aceasta returnează 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Cu aceasta, returnează și zero:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Nu puteți face diferența dintre succes și eșec în aceste două exemple. De fapt, atoi()
are aceeași problemă. Nu știu ce sistem de operare utilizați dar poate ați putea folosi ssize_t
ca tip de returnare dacă este disponibil și returnează -1 în caz de eșec.
Răspuns
Adăugarea la răspunsul anterior de către @Arkadiusz Drabczyk:
O implementare simplă și banală a contains
realizat astfel:
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; }
Apoi, acest program (cu câteva modificări menționate mai sus) ar trebui să funcționeze:
#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; }
Ieșire:
Poziție: 18
Poziție: -1
Comentarii
- Aș elimina verificarea dacă intrarea nu este NULĂ și ju Folosiți o extensie de limbă pentru aceasta (
__attribute__((nonnull))
în GCC).NULL
este ceva la care nu v-ați aștepta niciodată ca intrare pentru această funcție și adaugă una sau două linii de cod inutile. Aș prefera să scriu în documentația funcției ceva de genul: ” Dacă intrarea pentru această funcție este un pointer NULL, comportamentul este nedefinit. „. - @CacahueteFrito Codul original a făcut-o și vreau să mă străduiesc pentru compatibilitate (cine știe cum îl folosea OP?).
- Lipsește includerea pentru
ssize_t
:#include <sys/types.h>
. O altă opțiune ar fi să folosițiptrdiff_t
în schimb, din#include <stddef.h>
; întoarceți de fapt o diferență de pointer:? needle_in_haystack - haystack :
Răspuns
Codul dvs. nu funcționează. Returnează 0
pentru haystack
"abbc"
și needle
"bc"
, chiar dacă haystack
conține needle
.
Răspuns
Nu aveți nevoie de prima buclă și de toate calculele de lungime. De altfel, funcția nu reușește, dacă se găsește primul caracter, dar numai al doilea ocurență al primului caracter se potrivește cu acul.
Sarcina poate fi redusă la câteva linii:
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; }
Comentarii
- Ce este o modalitate bună de a obține mai bine la scrierea unui cod C mai compact și mai eficient ca acesta ?Această sortă îmi amintește de K & R C.
strstr()
. Există ‘ o versiune mai sigură numităstrnstr()
. Puteți găsi o implementare aici: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
să revină adevărat?