Denna funktion kontrollerar huruvida en understräng needle
finns i en annan sträng haystack
eller returnerar positionen om den gör det eller 0 om den inte gör det, såvida inte positionen är 0, i vilket fall kommer den inte att lokaliseras.
Letar du efter sätt att förbättra den här koden, särskilt bättre felhantering.
#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
Bara några kommentarer:
-
Du bör lägga till en ny rad efter den sista raden:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Jag vet inte vad kompilator du använder men med när du kompileras med
gcc
och-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; ^
-
Kodformatering borde vara mer konsekvent. Till exempel, i den här raden lägger du ett vitt utrymme före
needle
men placerar inte ett vitt utrymme förehaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
är inte en bärbar specifikator försize_t
-typ, du bör använda%zu
som introducerades i C99. -
Du sa:
returnerar positionen om den gör det eller 0 om den inte gör det, såvida inte positionen är 0, i vilket fall kommer den inte att lokaliseras.
Det här är verkligen inte bra. Till exempel returnerar den 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Med detta returnerar den också noll:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Du kan inte se skillnaden mellan framgång och misslyckande i de här två exemplen. Egentligen har atoi()
samma problem. Jag vet inte vilket operativsystem du använder men kanske kan du använda ssize_t
som returtyp om det är tillgängligt och returnera -1 vid misslyckande.
Svar
Tillägg till föregående svar av @Arkadiusz Drabczyk:
En enkel, trivial implementering av contains
gjort så här:
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; }
Då bör detta program (med några ändringar som nämnts ovan) fungera:
#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
- Jag skulle ta bort kontrollen att ingången inte är NULL och ju st använder ett språktillägg för det (
__attribute__((nonnull))
i GCC).NULL
är något som du aldrig skulle förvänta dig som inmatning för den här funktionen, och det lägger till en eller två onödiga kodrader. Jag föredrar att skriva i dokumentationen för funktionen ungefär som: ” Om ingången till den här funktionen är en NULL-pekare är beteendet odefinierat. ”. - @CacahueteFrito Den ursprungliga koden gjorde det, och jag vill sträva efter kompatibilitet (vem vet hur OP använde den?).
- Saknas inkludera för
ssize_t
:#include <sys/types.h>
. Ett annat alternativ skulle vara att användaptrdiff_t
istället från#include <stddef.h>
; du returnerar faktiskt en pekdifferens:? needle_in_haystack - haystack :
Svar
Din kod fungerar inte. Den returnerar 0
för haystack
"abbc"
och needle
"bc"
, även om haystack
innehåller needle
.
Svar
Du behöver inte den första slingan och alla längdberäkningar. Btw., Funktionen lyckas inte, om den första tecknet hittas, men bara den andra förekomsten av den första tecknet passar med nålen.
Uppgiften kan reduceras till några rader:
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
- Vad är ett bra sätt att bli bättre på att skriva mer kompakt, effektiv C-kod så här ?Denna sorta påminner mig om K & R C.
strstr()
. Det finns ’ en säkrare version som heterstrnstr()
. Du hittar en implementering här: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
bli sant?