Denne funksjonen sjekker hvorvidt en understreng needle
eksisterer i en annen streng haystack
og returnerer posisjonen hvis den gjør det eller 0 hvis den ikke gjør det, med mindre posisjon er 0, i så fall vil den ikke bli lokalisert.
Leter du etter måter å forbedre denne koden, spesielt bedre feilhåndtering.
#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; }
Kommentarer
Svar
Bare et par bemerkninger:
-
Du bør legge til en ny linje etter siste linje:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Jeg vet ikke hva kompilator du bruker, men med når du kompileres med
gcc
og-Wall -Wextra -pedantic
får du: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; ^
-
Kodeformatering bør være mer konsistent. For eksempel, i denne linjen setter du et mellomrom før
needle
men ikke legger et mellomrom førhaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
er ikke en bærbar spesifikator forsize_t
-type, du bør bruke%zu
introdusert i C99. -
Du sa:
returnerer posisjonen hvis den gjør det eller 0 hvis den ikke gjør det, med mindre posisjon er 0, i så fall vil den ikke bli lokalisert.
Dette er virkelig ikke bra. For eksempel returnerer den 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Med dette returnerer den også null:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Du kan ikke se forskjellen mellom suksess og fiasko i disse to eksemplene. Egentlig har atoi()
det samme problemet. Jeg vet ikke hvilket operativsystem du bruker men kanskje du kan bruke ssize_t
som returtype hvis den er tilgjengelig og returnere -1 i tilfelle feil.
Svar
Legge til i forrige svar av @Arkadiusz Drabczyk:
En enkel, triviell implementering av contains
gjort slik:
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; }
Dette programmet (med noen få endringer som nevnt ovenfor) skal fungere:
#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; }
Utgang:
Posisjon: 18
Posisjon: -1
Kommentarer
- Jeg fjerner sjekken om at inngangen ikke er NULL, og ju st bruk et språkutvidelse for det (
__attribute__((nonnull))
i GCC).NULL
er noe du aldri forventer som input for denne funksjonen, og den legger til en eller to unødvendige kodelinjer. Jeg foretrekker å skrive i dokumentasjonen til funksjonen omtrent som: » Hvis inngangen til denne funksjonen er en NULL-peker, er oppførselen udefinert. «. - @CacahueteFrito Den opprinnelige koden gjorde det, og jeg vil streve for kompatibilitet (hvem vet hvordan OPEN brukte den?).
- Mangler inkluderer for
ssize_t
:#include <sys/types.h>
. Et annet alternativ ville være å brukeptrdiff_t
i stedet, fra#include <stddef.h>
; du returnerer faktisk en pekeforskjell:? needle_in_haystack - haystack :
Svar
Koden din fungerer ikke. Den returnerer 0
for haystack
"abbc"
og needle
"bc"
, selv om haystack
inneholder needle
.
Svar
Du trenger ikke den første sløyfen og alle lengdeberegningene. Btw., Funksjonen lykkes ikke hvis den første røya blir funnet, men bare den andre forekomsten av den første røya passer med nål.
Oppgaven kan reduseres til noen få linjer:
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; }
Kommentarer
- Hva er en god måte å bli bedre på å skrive mer kompakt, effektiv C-kode som denne ?Denne sorta minner meg om K & R C.
strstr()
. Der er ‘ en tryggere versjon kaltstrnstr()
. Du finner en implementering her: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
bli sant?