Esta função verifica se uma substring needle
existe ou não em outra string haystack
e retorna a posição se sim ou 0 se não, a menos que o a posição é 0, caso em que não será localizado.
Procurando maneiras de melhorar este código, especificamente melhor tratamento de erros.
#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; }
Comentários
Resposta
Apenas algumas observações:
-
Você deve adicionar uma nova linha após a última linha:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
Eu não sei o que compilador que você usa, mas com quando compilado com
gcc
e-Wall -Wextra -pedantic
você obtém: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; ^
-
A formatação do código deve ser mais consistente. Por exemplo, nesta linha você coloca um espaço em branco antes de
needle
, mas não coloque um espaço em branco anteshaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
não é um especificador portátil para o tiposize_t
, você deve usar%zu
introduzido no C99. -
Você disse:
retorna a posição se sim ou 0 se não, a menos que o a posição é 0; nesse caso, ela não será localizada.
Isso realmente não é bom. Por exemplo, com isso, ele retorna 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Com isso, ele também retorna zero:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
Você não pode dizer a diferença entre sucesso e fracasso nestes dois exemplos. Na verdade, atoi()
tem o mesmo problema. Não sei qual sistema operacional você usa mas talvez você possa usar ssize_t
como o tipo de retorno se estiver disponível e retornar -1 em caso de falha.
Resposta
Acrescentando à resposta anterior de @Arkadiusz Drabczyk:
Uma implementação simples e trivial de contains
poderia ser feito assim:
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; }
Então, este programa (com algumas alterações conforme mencionado acima) deve funcionar:
#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; }
Resultado:
Posição: 18
Posição: -1
Comentários
- Gostaria de remover a verificação de que a entrada não é NULL e ju st use uma extensão de idioma para isso (
__attribute__((nonnull))
no GCC).NULL
é algo que você nunca esperaria como entrada para esta função e adiciona uma ou duas linhas de código desnecessárias. Eu preferiria escrever na documentação da função algo como: ” Se a entrada para esta função for um ponteiro NULL, o comportamento é indefinido. “. - @CacahueteFrito O código original fez isso, e eu quero me esforçar para manter a compatibilidade (quem sabe como o OP estava usando isso?).
- Falta inclusão para
ssize_t
:#include <sys/types.h>
. Outra opção seria usarptrdiff_t
em vez de#include <stddef.h>
; você está, na verdade, retornando uma diferença de ponteiro:? needle_in_haystack - haystack :
Resposta
Seu código não funciona. Ele retorna 0
para haystack
"abbc"
e needle
"bc"
, embora haystack
contenha needle
.
Resposta
Você não precisa do primeiro loop e de todos os cálculos de comprimento. A propósito, a função não é bem-sucedida se o primeiro caractere for encontrado, mas apenas a segunda ocorrência do primeiro caractere se encaixa com agulha.
A tarefa pode ser reduzida a algumas linhas:
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; }
Comentários
- Qual é uma boa maneira de escrever um código C mais compacto e eficiente como este ?Isso me lembra de K & R C.
strstr()
. Há ‘ s uma versão mais segura chamada . Você pode encontrar uma implementação aqui: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
deve retornar verdadeiro?