Tato funkce kontroluje bez ohledu na to, zda podřetězec needle
existuje v jiném řetězci haystack
a vrátí pozici, pokud ano, nebo 0, pokud ne, pokud pozice je 0, v takovém případě nebude nalezena.
Hledá způsoby, jak vylepšit tento kód, konkrétně lepší zpracování chyb.
#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; }
Komentáře
Odpověď
Několik poznámek:
-
Za poslední řádek byste měli přidat nový řádek:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Nevím, co kompilátor, který používáte, ale při kompilaci s
gcc
a-Wall -Wextra -pedantic
získáte: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; ^
-
Formátování kódu by mělo být konzistentnější. Například v tomto řádku vložíte mezery před
needle
, ale mezery před nimi nevložítehaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
není přenosný specifikátor pro typsize_t
, měli byste použít%zu
zavedený v C99. -
Řekli jste:
vrátí pozici, pokud ano, nebo 0, pokud ne, pokud pozice je 0, v takovém případě nebude nalezena.
To opravdu není dobré. Například s tímto vrátí 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
S tímto také vrátí nulu:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
V těchto dvou příkladech nerozeznáte rozdíl mezi úspěchem a neúspěchem. Ve skutečnosti má atoi()
stejný problém. Nevím, jaký operační systém používáte ale možná byste mohli použít ssize_t
jako návratový typ, pokud je k dispozici, a návrat -1 v případě selhání.
Odpověď
Přidání k předchozí odpovědi od @Arkadiusze Drabczyka:
Může být jednoduchá, triviální implementace contains
provedeno takto:
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; }
Poté by tento program (s několika výše uvedenými změnami) měl fungovat:
#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; }
Výstup:
Pozice: 18
Pozice: -1
Komentáře
- Odstranil bych kontrolu, zda vstup nemá NULL, a ju k tomu použijte jazykovou příponu (
__attribute__((nonnull))
v GCC).NULL
je něco, co byste jako vstup pro tuto funkci nikdy nečekali, a přidává jeden nebo dva zbytečné řádky kódu. Raději bych do dokumentace funkce napsal něco jako: " Pokud je vstupem této funkce ukazatel NULL, chování není definováno. ". - @CacahueteFrito Původní kód to udělal a já chci usilovat o kompatibilitu (kdo ví, jak jej OP používal?).
- Chybějící zahrnutí pro
ssize_t
:#include <sys/types.h>
. Další možností by bylo použítptrdiff_t
místo z#include <stddef.h>
; ve skutečnosti vracíte rozdíl ukazatele:? needle_in_haystack - haystack :
odpověď
Váš kód nefunguje. Vrací 0
pro haystack
"abbc"
a needle
"bc"
, přestože haystack
obsahuje needle
.
Odpověď
Nepotřebujete první smyčku a všechny výpočty délky. Btw., Funkce není úspěšná, pokud je nalezen první znak, ale pouze druhý výskyt prvního znaku zapadá do jehly.
Úkol lze zredukovat na několik řádků:
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; }
Komentáře
- Jaký je dobrý způsob, jak se zlepšit při psaní kompaktnějšího a efektivnějšího C kódu, jako je tento ?Toto třídění mi připomíná K & R C.
strstr()
. ' Existuje bezpečnější verze s názvemstrnstr()
. Implementaci najdete zde: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
vrátit true?