Esta función comprueba si existe o no una subcadena needle
en otra cadena haystack
y devuelve la posición si lo hace o 0 si no lo hace, a menos que el la posición es 0, en cuyo caso, no será localizado.
Buscando formas de mejorar este código, específicamente un mejor manejo de errores.
#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; }
Comentarios
Respuesta
Solo un par de comentarios:
-
Debe agregar una nueva línea después de la última línea:
$ ./nh First char match index: 18 Char: t Exist count: 1 Exist count: 2 Exist count: 3 Exist count: 4 Position: 18 $
-
No sé qué compilador que usa pero con cuando se compila con
gcc
y-Wall -Wextra -pedantic
obtiene: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; ^
-
El formato del código debe ser más coherente. Por ejemplo, en esta línea, coloca un espacio en blanco antes de
needle
pero no ponga un espacio en blanco anteshaystack
:size_t contains(const char * needle, const char *haystack);
-
%lu
no es un especificador portátil para el tiposize_t
, debe usar%zu
introducido en C99. -
Dijiste:
devuelve la posición si lo hace o 0 si no lo hace, a menos que el la posición es 0, en cuyo caso, no se localizará.
Esto realmente no es bueno. Por ejemplo, con esto devuelve 0:
char *needle = "This"; char *haystack = "This is a dinosaurtest.";
Con esto, también devuelve cero:
char *needle = "non-existent"; char *haystack = "This is a dinosaurtest.";
No se puede diferenciar entre el éxito y el fracaso en estos dos ejemplos. En realidad, atoi()
tiene el mismo problema. No sé qué sistema operativo utiliza pero tal vez pueda usar ssize_t
como tipo de retorno si está disponible y devolver -1 en caso de falla.
Respuesta
Agregando a la respuesta anterior de @Arkadiusz Drabczyk:
Una implementación simple y trivial de contains
podría ser hecho así:
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; }
Entonces, este programa (con algunos cambios como se mencionó anteriormente) debería 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:
Posición: 18
Posición: -1
Comentarios
- Quitaría la marca de que la entrada no es NULL, y ju st use una extensión de idioma para eso (
__attribute__((nonnull))
en GCC).NULL
es algo que nunca esperaría como entrada para esta función, y agrega una o dos líneas de código innecesarias. Preferiría escribir en la documentación de la función algo como: » Si la entrada a esta función es un puntero NULL, el comportamiento no está definido. «. - @CacahueteFrito El código original lo hizo, y quiero luchar por la compatibilidad (¿quién sabe cómo lo estaba usando el OP?).
- Falta incluir para
ssize_t
:#include <sys/types.h>
. Otra opción sería usarptrdiff_t
en su lugar, de#include <stddef.h>
; en realidad, está devolviendo una diferencia de puntero:? needle_in_haystack - haystack :
Respuesta
Su código no funciona. Devuelve 0
para haystack
"abbc"
y needle
"bc"
, aunque haystack
contiene needle
.
Respuesta
No necesita el primer ciclo y todos los cálculos de longitud. Por cierto, la función no tiene éxito si se encuentra el primer carácter, pero solo la segunda aparición del primer carácter encaja con la aguja.
La tarea se puede reducir a unas pocas líneas:
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; }
Comentarios
- ¿Cuál es una buena manera de mejorar la escritura de código C más compacto y eficiente como este? ?Esto me recuerda a K & R C.
strstr()
. Existe ‘ una versión más segura llamadastrnstr()
. Puede encontrar una implementación aquí: github.com/lattera/freebsd/blob/master/lib/libc/string/…contains("tt", "test")
devolver verdadero?