Deze functie controleert of een deelstring needle
bestaat in een andere tekenreeks haystack
en de positie retourneert als dit het geval is of 0 als dit niet het geval is, tenzij de positie is 0, in welk geval het “niet wordt gelokaliseerd.
Op zoek naar manieren om deze code te verbeteren, met name een betere foutafhandeling.
#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; }
Reacties
Antwoord
Slechts een paar opmerkingen:
-
Je moet een nieuwe regel toevoegen na de laatste regel:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Ik weet niet wat compiler die je gebruikt maar waarmee je compileert met
gcc
en-Wall -Wextra -pedantic
krijg je: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; ^
-
Code-opmaak zou meer consistent moeten zijn. In deze regel zet je bijvoorbeeld een witruimte voor
needle
maar zet je geen witruimte ervoorhaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
is geen draagbare specificatie voorsize_t
type, je zou%zu
geïntroduceerd in C99 moeten gebruiken. -
U zei:
geeft de positie terug als dit het geval is of 0 als dit niet het geval is, tenzij de positie is 0, in welk geval het “niet wordt gelokaliseerd.
Dit is echt niet goed. Hiermee wordt bijvoorbeeld 0 geretourneerd:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Hiermee wordt ook nul geretourneerd:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
U kunt in deze twee voorbeelden “geen verschil zien tussen succes en mislukking. In feite heeft atoi()
hetzelfde probleem. Ik weet niet welk besturingssysteem u gebruikt maar misschien kun je ssize_t
gebruiken als het retourtype als het beschikbaar is en -1 retourneren in geval van een fout.
Antwoord
Toevoegen aan het vorige antwoord door @Arkadiusz Drabczyk:
Een eenvoudige, triviale implementatie van contains
zou kunnen zijn doe je als volgt:
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; }
Dan zou dit programma (met een paar wijzigingen zoals hierboven vermeld) moeten werken:
#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; }
Uitvoer:
Positie: 18
Positie: -1
Reacties
- Ik zou het vinkje verwijderen dat de invoer niet NULL is, en ju Gebruik daarvoor een taalextensie (
__attribute__((nonnull))
in GCC).NULL
is iets dat je nooit zou verwachten als invoer voor deze functie, en het voegt een of twee onnodige regels code toe. Ik zou liever in de documentatie van de functie iets schrijven als: ” Als de invoer voor deze functie een NULL-pointer is, is het gedrag ongedefinieerd. “. - @CacahueteFrito De originele code deed het, en ik wil streven naar compatibiliteit (wie weet hoe het OP het gebruikte?).
- Ontbrekende include voor
ssize_t
:#include <sys/types.h>
. Een andere optie zou zijn om in plaats daarvanptrdiff_t
te gebruiken, van#include <stddef.h>
; je geeft eigenlijk een pointer-verschil terug:? needle_in_haystack - haystack :
Answer
Uw code werkt niet. Het retourneert 0
voor haystack
"abbc"
en needle
"bc"
, ook al bevat haystack
needle
.
Antwoord
Je hebt de eerste lus en alle lengteberekeningen niet nodig. Trouwens, de functie slaagt niet als het eerste teken wordt gevonden, maar alleen het tweede voorkomen van het eerste teken past met de naald.
De taak kan worden teruggebracht tot een paar regels:
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; }
Reacties
- Wat is een goede manier om beter te worden in het schrijven van compactere, efficiëntere C-code zoals deze ?Dit soort doet me denken aan K & R C.
strstr()
. Er is ‘ een veiligere versie genaamdstrnstr()
. U kunt hier een implementatie vinden: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
true retourneren?