Tämä toiminto tarkistaa onko alimerkkijono needle
olemassa toisessa merkkijonossa haystack
ja palauttaa sijainnin, jos on, tai 0, jos se ei ”t, ellei sijainti on 0, jolloin sitä ei löydy.
Etsitään tapoja parantaa tätä koodia, erityisesti virheenkäsittelyä.
#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; }
Kommentit
Vastaa
Vain muutama huomautus:
-
Sinun pitäisi lisätä uusi rivi viimeisen rivin jälkeen:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
En tiedä mitä kääntäjä, jota käytät, mutta käännettynä
gcc
– ja-Wall -Wextra -pedantic
-sivustoilla saat: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; ^
-
Koodin muotoilun tulisi olla johdonmukaisempi. Esimerkiksi tässä rivissä laitat välilyönnin ennen
needle
, mutta älä laita välilyöntiä ennenhaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
ei ole kannettava määritin tyypillesize_t
, sinun tulee käyttää%zu
, joka on otettu käyttöön C99: ssä. -
Sanoit:
palauttaa sijainnin, jos se tapahtuu, tai 0, jos se ei t, ellei sijainti on 0, jolloin sitä ei löydy.
Tämä ei todellakaan ole hyvä. Esimerkiksi tällöin se palauttaa arvon 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Tämän avulla se palauttaa myös nollan:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Tässä kahdessa esimerkissä ei voi sanoa eroa onnistumisen ja epäonnistumisen välillä. Itse asiassa atoi()
on sama ongelma. En tiedä mitä käyttöjärjestelmää käytät mutta ehkä voisit käyttää palautustyyppinä ssize_t
, jos se on käytettävissä, ja palauttaa -1 vian sattuessa.
Vastaa
Lisäys @Arkadiusz Drabczykin edelliseen vastaukseen:
Yksinkertainen, triviaali toteutus contains
voi olla tehty näin:
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; }
Tämän jälkeen tämän ohjelman (muutamalla yllä mainitulla muutoksella) pitäisi toimia:
#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; }
Tulos:
Sijoitus: 18
Sijoitus: -1
Kommentit
- Poistan tarkistuksen siitä, että tulo ei ole NULL, ja ju st käytä kielilaajennusta siihen (
__attribute__((nonnull))
GCC: ssä).NULL
on jotain, jota et koskaan odota tämän toiminnon syötteenä, ja se lisää yhden tai kaksi tarpeetonta koodiriviä. Haluaisin mieluummin kirjoittaa funktion dokumentaatioon jotain: ” Jos tämän toiminnon tulo on NULL-osoitin, käyttäytymistä ei ole määritelty. ”. - @CacahueteFrito Alkuperäinen koodi teki sen, ja haluan pyrkiä yhteensopivuuteen (kuka tietää, kuinka OP käytti sitä?).
- Sisältää puuttuu
ssize_t
:#include <sys/types.h>
. Toinen vaihtoehto olisi käyttää sen sijaanptrdiff_t
, nimestä#include <stddef.h>
; palautat osoitineron:? needle_in_haystack - haystack :
Vastaa
Koodisi ei toimi. Se palauttaa 0
kohteille haystack
"abbc"
ja needle
"bc"
, vaikka haystack
sisältää needle
.
Vastaa
Et tarvitse ensimmäistä silmukkaa ja kaikkia pituuslaskelmia. Huomaa, että funktio ei onnistu, jos ensimmäinen merkki löytyy, mutta vain toisen merkin toinen esiintyminen sopii neulaan.
Tehtävä voidaan supistaa muutamaan riviin:
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; }
Kommentit
- Mikä on hyvä tapa parantaa kirjoittamalla pienempi, tehokas C-koodi, kuten tämä ?Tämä sorta muistuttaa minua K & R C.
strstr()
. Siellä ’ on turvallisempi versio nimeltästrnstr()
. Toteutus löytyy täältä: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
palauttaa tosi?