Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: AxelP en 23 Diciembre 2014, 04:46 am



Título: Buscar una cadena en un archivo.
Publicado por: AxelP en 23 Diciembre 2014, 04:46 am
Hola. Debo hacer un programa que busque una cadena dada en un archivo existente, el problema es que al parecer hay algo mal en la comparación y no se que es que me dice que la cadena no existe, espero me puedan ayudar.
El código para crear el archivo es este:
Código:
#include <stdio.h>
#include <conio.h>
#include <string.h>

int main()
{
    FILE *archivin;
    char cadenita1[]= "Prueba de creacion de archivo\n";
    char cadenita2[]= "Ya casi estamos de vacaciones\n";
    char cadenita3[]= "Pero vamos a reprobar psicologia\n";
    char cadenita4[]= "Vamos a regresar en enero\n";

    archivin = fopen("C:\\Users\\Axel\\Documents\\Archivo info.txt", "wt");   
    fputs(cadenita1, archivin);
    fputs(cadenita2, archivin);
    fputs(cadenita3, archivin);
    fputs(cadenita4, archivin);
    fclose(archivin);
   
    printf("El archivo ha sido creado y/o modificado.");
    getch();
}

EL código para comparar y buscar es este:
Código:
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <locale.h>

int main()
{
setlocale(LC_ALL, "spanish");
FILE *archivo;
char buscar[100];
char cadena1[100];
char cadena2[100];
char cadena3[100];
char cadena4[100];

archivo = fopen("C:\\Users\\Axel\\Documents\\Archivo info.txt", "r");
fgets(cadena1, 100, archivo);
fgets(cadena2, 100, archivo);
fgets(cadena3, 100, archivo);
fgets(cadena4, 100, archivo);

printf("¿Qué cadena quieres buscar? ");
gets(buscar);

if (strcmpi(cadena1, buscar) == 0)
{
printf("\n\nLa cadena que buscas está en el archivo, y se encuentra en la primera línea.");
}
else if (strcmpi(cadena2, buscar) == 0)
{
printf("\n\nLa cadena que buscas está en el archivo, y se encuentra en la segunda línea.");
}
else if (strcmpi(cadena3, buscar) == 0)
{
printf("\n\nLa cadena que buscas está en el archivo, y se encuentra en la tercera línea.");
}
else if (strcmpi(cadena4, buscar) == 0)
{
printf("\n\nLa cadena que buscas está en el archivo, y se encuentra en la cuarta línea.");
}
else
{
printf("\n\nLa cadena que buscas no se encuentra en el archivo.");
}
fclose(archivo);
getch();
}

Como dije, el problema es que siempre me dice que la cadena no se encuentra en el archivo. Haciendo pruebas, comparé buscar con buscar y si funcionó, entonces no se que error haya al comparar con la cadena.


Título: Re: Buscar una cadena en un archivo.
Publicado por: engel lex en 23 Diciembre 2014, 07:10 am
te puedo decir que el programa tiene errores, main debe tener return, no se debe usar conio(aqui solo lo usas para el getch, que tampoco se recomienda), se desprueba el uso de gets (a cambio debes usar fgets con su respectivos valores para flujo de entrada) y strcmpi es especifico de visual studio (yo uso strcasecmp pero es especifico de unix)...

con las respectivas modificaciones indicadas me funciona bien el codigo... con tu codigo relamente no use, pero puedes usar el debugger para correrlo paso a paso y buscar los errores


Título: Re: Buscar una cadena en un archivo.
Publicado por: rir3760 en 23 Diciembre 2014, 17:57 pm
siempre me dice que la cadena no se encuentra en el archivo. Haciendo pruebas, comparé buscar con buscar y si funcionó, entonces no se que error haya al comparar con la cadena.
El problema se debe a que utilizas fgets para leer las lineas del archivo (lee y almacena el avance de linea) y gets para obtener la linea a buscar (lee y descarta el avance de linea). La solución ya la indico engel lex: sustituir el uso de gets por fgets

Un saludo


Título: Re: Buscar una cadena en un archivo.
Publicado por: AxelP en 24 Diciembre 2014, 02:44 am
Hola, ¡gracias a todos! Ya logré hacerlo funcionar :D
Lo del return no lo sabía engel lex, ¿me podrías explicar por qué se usa? Y sobre el strcmpi leí que sirve para comparar las cadenas sin distinguir entre mayúsculas y minúsculas, por eso lo usé.
rir3760 gracias a tu explicación entendí por qué se debe usar fgets.
Muchas gracias a ambos y me disculpo por tantas dudas, soy principiante y no se mucho aún.
Aquí les dejo el código como quedó funcionando bien.

Código:
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <stdlib.h>

int main()
{
setlocale(LC_ALL, "spanish"); //Sirve para usar caracteres especiales del español.
FILE *archivo;
char buscar[100];
char cadena1[100];
char cadena2[100];
char cadena3[100];
char cadena4[100];
int continuar, vaciarmem;

archivo = fopen("C:\\Users\\Axel\\Documents\\Ejemplo.txt", "r");
fgets(cadena1, 100, archivo);
fgets(cadena2, 100, archivo);
fgets(cadena3, 100, archivo);
fgets(cadena4, 100, archivo);

continuar = 0;
while (continuar == 0)
{
printf("¿Qué cadena quieres buscar? ");
fgets(buscar, 100, stdin);

if (strcmpi(cadena1, buscar) == 0)
{
printf("\nLa cadena que buscas está en el archivo, y se encuentra en la primera línea.");
}
else if (strcmpi(cadena2, buscar) == 0)
{
printf("\nLa cadena que buscas está en el archivo, y se encuentra en la segunda línea.");
}
else if (strcmpi(cadena3, buscar) == 0)
{
printf("\nLa cadena que buscas está en el archivo, y se encuentra en la tercera línea.");
}
else if (strcmpi(cadena4, buscar) == 0)
{
printf("\nLa cadena que buscas está en el archivo, y se encuentra en la cuarta línea.");
}
else
{
printf("\nLa cadena que buscas no se encuentra en el archivo.");
}
printf("\n\n¿Quieres buscar otra cadena? 0 = Si / 1 = No ");
scanf("%d", &continuar);
while ((vaciarmem = getchar()) != '\n' && vaciarmem != EOF); //Sirve para vaciar el buffer o memoria, mas info. en http://www.taringa.net/post/ciencia-educacion/14450390/Lectura-de-cadenas-en-C.html
system("cls");    
}

fclose(archivo);
printf("Presiona enter para salir...");
getchar();
}

También me gustaría saber cómo funciona el segundo while que sirve para vaciar la memoria y evitar que se salte todos los fgets en el primero. Gracias  :)


Título: Re: Buscar una cadena en un archivo.
Publicado por: engel lex en 24 Diciembre 2014, 03:12 am
Citar
Lo del return no lo sabía engel lex, ¿me podrías explicar por qué se usa?

las funciones de c/c++ deben tener obligatoriamente return para que estén "bien armadas" el return es el valor de retorno de la funcion, a demás 0 en el main le indica al sistema operativo que todo fue bien

sobre el while
Código
  1. while ((vaciarmem = getchar()) != '\n' && vaciarmem != EOF);

esto es para limpiar la memoria de entrada de valores, es decir, el scanf o getchar pueden leer sin avisar al usuario... es decir, si mandaste una cadena más larga de lo esperada con espacios, o cualquier cosa rara, el scanf o getchar solo leeran lo indicado por el programador yel resto quedará en el buffer de entrada (stdin)

así que cuando hagas otro getchar, scanf o fgets simplemente tomará esos datos directamente sin preguntarle al usuario (ya que así funcionan)...

en este caso lees todo hasta que consigas "\n" (salto de linea) o EOF (end of file, fin de archivo o stream de datos) y te aseguras que eso no pase


pd: cuando haces enter en la consola se agrega un "\n" que muchas veces no se lee, eso tambien puede hacer que getchar se salte


Título: Re: Buscar una cadena en un archivo.
Publicado por: Yoel Alejandro en 24 Diciembre 2014, 20:18 pm
Te voy a explicar con más cuidado lo del avance de línea, gets() y fgets().

En C una cadena no es más que un arreglo (vector) de caracteres, donde el último elemento debe ser un carácter '\0' llamado carácter nulo. Ahora, considera este código:
Código
  1. int main() {
  2.    char * str1[100];
  3.    char * str2[100];
  4.  
  5.    fgets( str1, 100, sdtin );
  6.    gets( str2 );
  7.  
  8.    return 0;
  9. }

¿Cuál es la diferencia? Pues, si corres el programa y escribes en el teclado "hola", la cadena str1 contendrá los caracteres

h - o - l - a - \n - \0

('\n' es el ENTER o avance de línea, y '\0' es el nulo de terminación) mientras str2 será:

h - o - l - a - \0

Por eso rir7376 te dice que fgtes() lee y almacena el avance de línea, mientra gets() lee y descarta.

¿Qué problemas se pueden ocasionar? Pues si usas gets(), el carácter '\n' NO es pasado a la cadena y por lo tanto permanece en el búfer de lectura del teclado. Debes limpiarlo y para ello se usa la clásica sentencia
Código
  1. while ( getchar() != '\n' ) ;
con el punto y coma al final. Si no limpias el búfer, corres el riesgo que de que este carácter '\n que quedó "flotando" por ahí se introduzca en forma indeseada con la próxima orden de lectura del teclado. Ese es el problema .... :-\

Por otra parte si usaste fgets(), el carácter '\n' es pasado a la cadena pero ahora tienes una cadena terminada en '\n', o sea 'h' - 'o' - 'l'- 'a' - '\n', y no 'h' - 'o' - 'l'  'a' como quizá esperabas. Lo puedes eliminar de varias maneras aunque no se si es propósito de discusión ese tema aquí.

En cualquier caso, fgets() es más seguro que gets() por lo que deberías preferirla. Y de cualquier modo, debes usar siempre una o siempre la otra, pero no mezclándolas.

Espero haberte ayudado  :)