“ Ciąg ” zawiera funkcję w C

Ta funkcja sprawdza czy podłańcuch needle istnieje w innym ciągu haystack i zwraca pozycję, jeśli tak, lub 0, jeśli nie, chyba że pozycja wynosi 0, w takim przypadku nie zostanie zlokalizowana.

Poszukiwanie sposobów na ulepszenie tego kodu, w szczególności lepszej obsługi błędów.

#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; } 

Komentarze

  • Dodaj kilka przykładów, aby dokładnie pokazać, co masz na myśli, mówiąc, że ” zawiera „. Wątpię, czy Twój kod działa zgodnie z przeznaczeniem.
  • To już istnieje: strstr(). Jest ' jest bezpieczniejsza wersja o nazwie strnstr(). Implementację można znaleźć tutaj: github.com/lattera/freebsd/blob/master/lib/libc/string/…
  • @RolandIllig: dlaczego, czy możesz wyjaśnić?
  • Czy contains("tt", "test") zwraca prawdę?
  • @ CacahueteFrito Więc płacisz niemałe koszty związane z użytecznością i wydajnością, aby maskować uszkodzenia danych w niektórych rzadkich przypadkach, zamiast polegać na niezmiennikach programów, łataniu danych lub zgłaszaniu błędu? To wydaje się zły pomysł.

Odpowiedź

Tylko kilka uwag:

  • Należy dodać nową linię po ostatniej linii:

     $ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $ 
  • Nie wiem co kompilator, którego używasz, ale skompilowany z gcc i -Wall -Wextra -pedantic otrzymujesz:

    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; ^ 
  • Formatowanie kodu powinno być bardziej spójne. Na przykład w tym wierszu umieszcza się białą spację przed needle, ale nie należy umieszczać spacji przed haystack:

    size_t contains(const char * needle, const char *haystack); 
  • %lu nie jest przenośnym specyfikatorem dla typu size_t, należy użyć %zu wprowadzonego w C99.

  • Powiedziałeś:

zwraca pozycję, jeśli tak, lub 0, jeśli tak nie jest, chyba że pozycja wynosi 0, w takim przypadku nie zostanie zlokalizowana.

To naprawdę nie jest dobre. Na przykład z tym zwraca 0:

char *needle = "This"; char *haystack = "This is a dinosaurtest."; 

W tym przypadku zwraca również zero:

char *needle = "non-existent"; char *haystack = "This is a dinosaurtest."; 

W tych dwóch przykładach nie można odróżnić sukcesu od porażki. W rzeczywistości atoi() ma ten sam problem. Nie wiem, jakiego systemu operacyjnego używasz ale może mógłbyś użyć ssize_t jako typu zwracanego, jeśli jest dostępny i zwrócić -1 w przypadku niepowodzenia.

Odpowiedź

Dodanie do poprzedniej odpowiedzi autorstwa @Arkadiusza Drabczyka:

Prosta, trywialna implementacja contains może być zrobione w ten sposób:

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; } 

Następnie ten program (z kilkoma zmianami, jak wspomniano powyżej) powinien działać:

#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; } 

Wynik:

Stanowisko: 18
Stanowisko: -1

Komentarze

  • Chciałbym usunąć sprawdzanie, czy dane wejściowe nie mają wartości NULL i ju st użyj do tego rozszerzenia języka (__attribute__((nonnull)) w GCC). NULL to coś, czego nigdy byś się nie spodziewał jako dane wejściowe dla tej funkcji, i dodaje jeden lub dwa niepotrzebne wiersze kodu. Wolałbym napisać w dokumentacji funkcji coś takiego: ” Jeśli dane wejściowe do tej funkcji to wskaźnik NULL, zachowanie jest niezdefiniowane. „.
  • @CacahueteFrito Wykonał to oryginalny kod, a ja chcę dążyć do kompatybilności (kto wie, jak korzystał z tego OP?).
  • Brak uwzględnienia dla ssize_t: #include <sys/types.h>. Inną opcją byłoby użycie zamiast tego ptrdiff_t z #include <stddef.h>; w rzeczywistości zwracasz różnicę wskaźnika: ? needle_in_haystack - haystack :

Odpowiedź

Twój kod nie „nie działa. Zwraca 0 dla haystack "abbc" i needle "bc", mimo że haystack zawiera needle .

Odpowiedź

Nie potrzebujesz pierwszej pętli i wszystkich obliczeń długości. Przy okazji, funkcja nie powiedzie się, jeśli pierwszy znak zostanie znaleziony, ale tylko drugie wystąpienie pierwszego znaku pasuje do igły.

Zadanie można zredukować do kilku wierszy:

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; } 

Komentarze

  • Jaki jest dobry sposób na ulepszenie pisania bardziej zwartego i wydajnego kodu C, takiego jak ten ?To trochę przypomina mi K & R C.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *