Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: eduu15 en 7 Abril 2018, 14:35 pm



Título: Punteros a cadenas dinamicas
Publicado por: eduu15 en 7 Abril 2018, 14:35 pm
-La idea que tenia que no la he podido implementar pero dudo que se pueda, es que al pedir un nombre y apellido al usuario a priori NO SABEMOS cual va a ser la longitud de stdin que teclee el usuario. En la linea del malloc puse 10 por poner como pude haber puesto 20 pero en realidad no se cuanto va a ocupar el nombre y el apellido que me ingrese el usuario por teclado no se como implementarlo de tal manera que cuando se teclee un nombre y un apellido se calcule la longitud y luego ya reservar memoria para esa longitud a parte tambien para reservar la memoria justa y necesaria para lo que me teclee el usuario y no andar a ciegas suponiendo que va ingresar un nombre y apellido de 10,20,30 etc bytes

-Como no me salio la idea hice esto que no se parece en nada a mi idea y que aun por encima no consigo hacer que funcione
Espero haberme explicado con claridad y gracias
Citar
Primera duda, porque el codigo no funciona?
Código:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    char *nombre,*nombre2;
    nombre=malloc(10*sizeof(char)); //reservo 10 bytes
    printf("Introduce tu nombre y apellido: ");

    fgets(nombre,9,stdin); //agrega NULL y \n si se ingresan menos caracteres
    if (nombre[strlen(nombre)-1] == '\n'){
        nombre[strlen(nombre)-1] = '\0';
    }

    printf("%s\n",nombre);

    long int longitud=(strlen(nombre)+1); //strlen no cuenta el NULL de final de cadena
    printf("%li\n",longitud);

    if(longitud>8){
       nombre2=realloc(nombre,15*sizeof(char)); //reasigno 5 bytes
       printf("%s\n",nombre);
       free(nombre2);

     }
     free(nombre);


    return 0;
}

Citar
Segunda duda, seria posible hacer la idea?



Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 7 Abril 2018, 18:44 pm
Citar
Puede resultar un poco confuso pero mas o menos la idea seria esta:
Código:
    #include <stdio.h>
    #include <stdlib.h>
     
    void limpiar( void ){
        system("cls||clear");
    }
     
    int main( void ){
        size_t tam_frases = 0, i;
        char **frases = NULL, salir;
     
        do {
            limpiar();
            frases = realloc(frases, (tam_frases + 1) * sizeof(char*));
            if(!frases) {
                fprintf(stderr, "\n\n *** Error al adquirir memoria ***\n\n");
                exit(1);
            }
     
            printf("\nIngrese frase....: ");
            scanf("%m[^\n]%*c", &frases[tam_frases]);
            ++tam_frases;
     
            printf("\nPara continuar \"S\" para finalizar \"N\"....: ");
            scanf("%c%*[^\n]%*c", &salir);
        } while(salir != 'n' && salir != 'N');
     
        printf ("\n Frases introducidas.....: ");
     
        for(i = 0; i < tam_frases; ++i)
            printf("\n>> %s", frases[i]);
     
        for(i = 0; i < tam_frases; ++i)
            free(frases[i]);
     
        return 0;
    }

POST del codigo de MAZUS: https://foro.elhacker.net/programacion_cc/arreglo_de_cadenas_con_memoria_dinamica_realloc_lenguaje_c-t458601.0.html;msg2090624#msg2090624
en este codigo no se especifica ningun tamaño se reserva segun se necesita para lo que el usuario teclee si mal no entendi el codigo


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 7 Abril 2018, 20:06 pm
Estaba pensando en otros lenguajes que derivan de c y se me vino a la cabeza python.
Y la idea que tengo en c en python es la funcion input en python3 y raw_input en python2, no se si es el mejor ejemplo pero el codigo en PYTHON3 seria algo asi:

Código:
while(1):
    teclado=str(input("Introduce lo que quieras: ")) #str convierte a string lo que le pasemos a input
    print(teclado)
Cada linea en python son 10 en c xD
Citar
Complicandolo un poco mas
Código:
while(1):
    teclado=str(input("Introduce lo que quieras o exit para salir: "))
    
    if(teclado=="exit"):
        break
    print(teclado)

Espero que ahora se haya entendido bien





Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 7 Abril 2018, 21:33 pm
Con fgets casis seguro que no se puede al tener que pasarle el numero de bytes


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: MAFUS en 7 Abril 2018, 21:48 pm
A ver, lástima que no haya nada como %m en windows pero se puede simular. La idea es ir adquiriendo trozos razonables de memoria con realloc, para no ir perdiendo tiempo en adquisición de memoria y copia.
En este caso se adquieren bloques de memoria de 10 bytes cada vez. Cuando se llena se adquieren 10 más de forma automática. Para el final de la adquisición de la cadena, marcado por el carácter '\n', de añade el carácter nulo '\0' para marcar el final de la cadena si hay espacio; si no añade un byte más exproceso para alojarlo.

Al final se genera una cadena dinámica del mismo tamaño que la adquirida por teclado y se le copiará el contenido. La cadena auxiliar, la utilizada para adquirir del teclado es destruida y se devuelve la cadena ajustada. Eso sí, hay que recordar destruirla cuando ya no se necesite. Se considera que un char es un byte.

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. char* string_input() {
  6.    char *ret_val; // cadena que será devuelta
  7.    char *str = NULL; // cadena auxiliar para conseguir datos del teclado
  8.    char c;
  9.    const unsigned chunk = 10; // tamaño de trozos de memoria en bytes o caracteres
  10.    int i=0; // posición del cursor en str
  11.  
  12.    while((c=getchar())!='\n') { // adquisición por teclado
  13.        if(i%chunk == 0) // si i ha alcanzado el máximo de memoria
  14.            str=realloc(str, i+chunk); // añadirle más
  15.        str[i] = c; // copiar el caracter adquirido a la cadena
  16.        ++i; // avanzar el puntero en str
  17.    }
  18.    if(i%chunk == 0) // si i ha alcanzado el máximo de memoria
  19.        str=realloc(str, i+1); // añadir un byte más a str
  20.    str[i] = '\0'; // cerrar la cadena
  21.  
  22.    ret_val = malloc(strlen(str)+1); // dimensionar la cadena de regreso con el tamaño exacto
  23.    strcpy(ret_val, str); // copiar la cadena
  24.  
  25.    free(str); // borrar la cadena auxiliar
  26.  
  27.    return ret_val; // devolver la cadena resultado
  28. }
  29.  
  30. int main(void) {
  31.    char *str;
  32.  
  33.    printf("> ");
  34.    str = string_input();
  35.  
  36.    printf("%s", str);
  37.  
  38.    free(str);
  39. }



Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 7 Abril 2018, 22:01 pm
Lo primero gracias por el code y lo segundo en el primer realloc no seria como hacer un malloc? porque al pasarle NULL se va a comportar como un malloc si no me equivoco ya que no estas reasignando memoria al pasarle NULL. No seria mejor hacer str=malloc(i+chunk) o un str=calloc(i+chunk)?


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: MAFUS en 7 Abril 2018, 22:05 pm
Sí, funciona como un malloc al pasarle null, pero si te fijas el realloc está en un bucle así que se necesita realojar el array. Por eso se pasa un null al principio, para que haga una primera adquisición tipo malloc pero a las siguientes trabaja como realloc. Por eso esa construcción.


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 7 Abril 2018, 22:08 pm
Vale ya entiendo gracias


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 8 Abril 2018, 01:21 am
Ahora estoy confuso... Y que diferencia habria entre el codigo https://foro.elhacker.net/programacion_cc/mostrar_una_cadena_sin_especificar_su_tamano-t482323.0.html;msg2159218#msg2159218 (https://foro.elhacker.net/programacion_cc/mostrar_una_cadena_sin_especificar_su_tamano-t482323.0.html;msg2159218#msg2159218) y hacer un
Código:
#include <stdio.h>
int main(){

int c;

while((c=getchar()) && !=EOF){
      putchar(c);
return 0;

}


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: MAFUS en 8 Abril 2018, 01:55 am
Este último que has puesto es una máquina de escribir. Lo que consigues por teclado lo sueltas por la pantalla. No hace nada más: no se puede guardar para usarlo después, tratarlo, modificarlo, en definitiva trabajar los datos. Tal como los consigues los sueltas.


Título: Re: Mostrar una cadena sin especificar su tamaño
Publicado por: eduu15 en 8 Abril 2018, 02:15 am
Y se podria guardar la salida de getchar?



He cambiado el titulo de la pregunta "Arrays de caracteres dinamicos" pero no se si estara bien porque en realidad serian punteros a cadenas dinamicas si no me equivoco



 Volvi a cambiar el titulo ahora creo que esta bien y es mas claro corrijanme si me equivoco



Que lio con el titulo...



Otra pregunta MAFUS perdona por hacer tantas... porque ret_val y str no son un puntero doble **ret_val **str como en este code: https://foro.elhacker.net/programacion_cc/punteros_a_cadenas_dinamicas-t482323.0.html;msg2159182#msg2159182



En total son 3 preguntas:
1-Y se podria guardar la salida de getchar?
2-el dichoso titulo de la pregunta
3-La del puntero doble



[MOD] No hacer quintuple post, se usa el botón "modificar" para añadir comentarios.


Título: Re: Punteros a cadenas dinamicas
Publicado por: MAFUS en 8 Abril 2018, 03:21 am
Bien, antes de nada y siguiendo las reglas del foro, no debe hacer publicaciones seguidas. Si no ha habido respuestas posteriores y quieres actualizar tu mensaje debes ir al botón 'editar' de tu último mensaje del hilo y allí añadir las novedades.

Respondiendo a tus preguntas:
1. Sí, se puede guardar la salida de getchar. Fíjate que aquí se hace
Código:
while((c=getchar())!='\n') {

2. El título está bien

3. En el código que has apuntado es puntero doble porque guarda una lista de cadenas cuando en el último el que te he hecho solo guarda una única cadena.


Título: Re: Punteros a cadenas dinamicas
Publicado por: eduu15 en 11 Abril 2018, 00:47 am
Estaba repasando el code y me surgio una duda. Porque otro free en main?
Citar
Code original

Código:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char* string_input() {
        char *ret_val; // cadena que será devuelta
        char *str = NULL; // cadena auxiliar para conseguir datos del teclado
        char c;
        const unsigned chunk = 10; // tamaño de trozos de memoria en bytes o caracteres
        int i=0; // posición del cursor en str
     
        while((c=getchar())!='\n') { // adquisición por teclado
            if(i%chunk == 0) // si i ha alcanzado el máximo de memoria
                str=realloc(str, i+chunk); // añadirle más
            str[i] = c; // copiar el caracter adquirido a la cadena
            ++i; // avanzar el puntero en str
        }
        if(i%chunk == 0) // si i ha alcanzado el máximo de memoria
            str=realloc(str, i+1); // añadir un byte más a str
        str[i] = '\0'; // cerrar la cadena
     
        ret_val = malloc(strlen(str)+1); // dimensionar la cadena de regreso con el tamaño exacto
        strcpy(ret_val, str); // copiar la cadena
     
        free(str); // borrar la cadena auxiliar
     
        return ret_val; // devolver la cadena resultado
    }
     
    int main(void) {
        char *str;
     
        printf("> ");
        str = string_input();
     
        printf("%s", str);
     
        free(str); //Porque este free? Para liberar ret_val?
    }


Título: Re: Punteros a cadenas dinamicas
Publicado por: MAFUS en 11 Abril 2018, 09:19 am
El fred que hay en string_input es para su variable local str. Ahora subte fijas en esa misma función se dimensiona otra variable, ret_val, que no es liberada, sino que su dirección a la que apunta es pasada a str de main y por tanto ahora es main la encargada de liberar esa memoria.