“ Sträng ” innehåller funktion i C

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

  • Lägg till några exempel för att visa exakt vad du menar med att säga ” innehåller ”. Jag tvivlar på att din kod fungerar som avsett.
  • Det finns redan: strstr(). Det finns ’ en säkrare version som heter strnstr(). Du hittar en implementering här: github.com/lattera/freebsd/blob/master/lib/libc/string/…
  • @RolandIllig: varför, kan du förklara?
  • Bör contains("tt", "test") bli sant?
  • @ CacahueteFrito Så, du betalar en inte obetydlig kostnad för användbarhet och prestanda för att maskera datakorruption i vissa sällsynta fall, istället för att förlita dig på dina programvarianter, lappa data eller rapportera felet? Det verkar vara en dålig idé runtom.

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öre haystack:

    size_t contains(const char * needle, const char *haystack); 
  • %lu är inte en bärbar specifikator för size_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ända ptrdiff_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.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *