Denne funktion kontrollerer om der findes en understreng needle
i en anden streng haystack
eller returnerer positionen, hvis den gør det, eller 0, hvis den ikke gør det, medmindre position er 0, i hvilket tilfælde den ikke bliver placeret.
På udkig efter måder at forbedre denne kode på, specifikt bedre fejlhå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 bemærkninger:
-
Du skal tilføje en ny linje efter den sidste linje:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Jeg ved ikke hvad kompilator, du bruger, men med når den 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 skal være mere ensartet. For eksempel sætter du i dette felt et mellemrum før
needle
men sætter ikke et mellemrum førhaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
er ikke en bærbar specifikator forsize_t
type, skal du bruge%zu
introduceret i C99. -
Du sagde:
returnerer positionen, hvis den gør det, eller 0 hvis den ikke gør det, medmindre position er 0, i hvilket tilfælde den ikke bliver placeret.
Dette er virkelig ikke godt. For eksempel returnerer dette 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Med dette returnerer det også nul:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Du kan ikke se forskellen mellem succes og fiasko i disse to eksempler. Faktisk har atoi()
det samme problem. Jeg ved ikke, hvilket operativsystem du bruger men måske kan du bruge ssize_t
som returtype, hvis den er tilgængelig, og returnere -1 i tilfælde af fejl.
Svar
Tilføjelse til det forrige svar af @Arkadiusz Drabczyk:
En enkel, triviel implementering af contains
gjort sådan:
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; }
Derefter skal dette program (med et par ændringer som nævnt ovenfor) 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; }
Output:
Position: 18
Position: -1
Kommentarer
- Jeg fjerner afkrydsningen af, at input ikke er NULL, og ju brug en sprogudvidelse til det (
__attribute__((nonnull))
i GCC).NULL
er noget, du aldrig ville forvente som input til denne funktion, og det tilføjer en eller to unødvendige kodelinjer. Jeg foretrækker at skrive i dokumentationen til funktionen sådan: ” Hvis input til denne funktion er en NULL-markør, er adfærden udefineret. “. - @CacahueteFrito Den oprindelige kode gjorde det, og jeg vil stræbe efter kompatibilitet (hvem ved, hvordan OPen brugte den?).
- Mangler inkluderer for
ssize_t
:#include <sys/types.h>
. En anden mulighed ville være at brugeptrdiff_t
i stedet fra#include <stddef.h>
; du returnerer faktisk en markørforskel:? needle_in_haystack - haystack :
Svar
Din kode fungerer ikke. Den returnerer 0
til haystack
"abbc"
og needle
"bc"
, selvom haystack
indeholder needle
.
Svar
Du behøver ikke den første sløjfe og alle længdeberegningerne. Btw., Funktionen lykkes ikke, hvis den første char findes, men kun den anden forekomst af den første char passer med nålen.
Opgaven kan reduceres til et par 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
- Hvad er en god måde at blive bedre til at skrive mere kompakt, effektiv C-kode som denne ?Denne slags minder mig om K & R C.
strstr()
. Der ‘ er en sikrere version kaldetstrnstr()
. Du kan finde en implementering her: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
returnere sandt?