“ Merkkijono ” sisältää funktion C: ssä

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

  • Lisää joitain esimerkkejä osoittaaksesi tarkalleen mitä tarkoitat sanomalla ” sisältää ”. Epäilen, että koodisi toimii tarkoitetulla tavalla.
  • Tämä on jo olemassa: strstr(). Siellä ’ on turvallisempi versio nimeltä strnstr(). Toteutus löytyy täältä: github.com/lattera/freebsd/blob/master/lib/libc/string/…
  • @RolandIllig: miksi, voitko selittää?
  • Pitäisikö contains("tt", "test") palauttaa tosi?
  • @ CacahueteFrito Joten, maksat tietämättömät kustannukset käytettävyydestä ja suorituskyvystä datan vioittumisen peittämiseksi joissakin harvoissa olosuhteissa sen sijaan, että luotat ohjelmiesi invarianteihin, korjaat tietoja tai ilmoitat virheestä? Se näyttää olevan huono idea kaikkialla.

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ä ennen haystack:

    size_t contains(const char * needle, const char *haystack); 
  • %lu ei ole kannettava määritin tyypille size_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 sijaan ptrdiff_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.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *