Arreglo de cadenas con memoria dinámica (realloc) lenguaje C.

Iniciado por NOB2014, 3 Octubre 2016, 23:02 PM

0 Miembros y 1 Visitante están viendo este tema.

NOB2014

Hola a todos.
Alguien me podría decir como solucionar el siguiente error:
Citarrepaso.c: In function 'main':
repaso.c:44:3: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat=]
  printf( "\n %s ", frases[n] );
  ^

Créanme que con lo tedioso que me resulta buscar la solución en inglés lo hice por un montón de páginas y no logré dar con la solución, creo que el error lo tengo en la línea 29 pero no lo logro.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_CHAR 30

void limpiar( void );

int main( void ){
size_t contador=0, ch, n;
char *frases=NULL, *tmpFrases=NULL, ingreso[MAX_CHAR], salir, *p=NULL;

do{
limpiar();
printf("\n Ingrese frase(maximo %d)....: ", MAX_CHAR);
fgets( ingreso , MAX_CHAR, stdin );
if((p=strchr(ingreso, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
contador++;

tmpFrases = (char*)realloc( frases, contador * sizeof(char) );

if( tmpFrases!=NULL ){
frases=tmpFrases;
frases[contador-1] = *ingreso ;
}
else{
free( frases );
puts( "Error (re)allocating memory" );
exit(1);
}

printf("\n Para continuar \"S\" para finalizar \"N\"....:");
scanf("%c", &salir);
while((ch = getchar()) !='\n' && ch!=EOF);
}while ( salir != 'n' && salir != 'N' );

printf ("\n Frases introducidas.....: ");
for( n=0; n < contador-1; n++ )
printf( "\n %s ", frases[n] );

free( frases );


return 0;
}

void limpiar( void ){
system("cls||clear");
}

dato000 gracias por ocuparte del tema anterior. -
Saludos
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

MAFUS

frases no es un array de cadenas, es solo una cadena, prueba de ello es su definición:
char *frases

para que sea un array dinámico de frases deberías hacer
char **frases

después a cada frase nueva haces crecer el puntero con calloc

char frases = calloc(frases, (tam_frases + 1) * sizeof(char*))

seguidamente cargas la nueva frase al array

scanf("%m[^\n]%*c", &frases[tam_frases]);

y actualizas tam_frases

++tam_frases

Para acabar acuérdate de liberar toda la memoria adquirida por scanf para cada cadena.
for(i = 0; i < tam_frases; ++i)
    free(cadena[i])

NOB2014

Hola, MAFUS.
En mucho tiempo es la primera vez que no me resulta(tus ayudas) y además no entiendo los trozos de código que propones, por lo tanto, voy a intentarlo de otra manera, estoy desconcertado, tal vez otra propuesta me aclare las cosas. -

Un abrazo. -
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

geeke

#3
También puedes usar array de punteros

char *frases[size]
for (i = 0; i < size; i++)
   frases[i] = malloc(len_frase * sizeof(char));

MAFUS

Un array de cadenas es fijo, no podrá crecer más si así lo necesita.

En unas horas te voy a pasar un código ejecutable que pone en práctica lo que te he dicho.

NOB2014

#5
Hola, que tengan un muy buen día. -
De tanto buscar encontré un Ej. que si bien estaba en c++ lo pude adaptar, este código cumple con todas mis expectativas en cuanto a lo que necesitaba sobre el tema, seria bueno que además del código de MAFUS (que deseo con muchas ansias verlo editado) alguien más de su versión de como haria lo mismo pero con otro código. -

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_CHAR 30

void limpiar( void );
void mostrar( char **frases, int numStrings );
void liberar( char **frases, int numStrings );

int main( void ){
char **frases = NULL, tmp_frase[MAX_CHAR], *p=NULL;
int i, numStrings = 0, ch;

while( 1 ){
limpiar();
if( numStrings > 0){
mostrar( frases, numStrings );
}
printf( "\n Introduzca una cadena (Enter para finalizar)......: ");
fgets(tmp_frase, MAX_CHAR, stdin );
if((p=strchr(tmp_frase, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
   if (strlen(tmp_frase) == 0){
break;
   }
   frases = (char **) realloc (frases, (numStrings+1) * sizeof(char *));
if( frases!=NULL ){
    frases[numStrings++] = strdup(tmp_frase);
}else{
printf( "\n Error, no se pudo asignar memoria" );
printf( "\n Pulse [Enter] para finalizar..." ); getchar();
liberar( frases, numStrings );
exit(1);
}
}
liberar( frases, numStrings );

return 0;
}

void limpiar( void ){
system("cls||clear");
}

void mostrar( char **frases, int numStrings ){
int i;

printf("\n ========================= Ingresos ========================= " );
for(i=0; i < numStrings; i++){
printf("\n %s", frases[i]);
}
printf("\n ============================================================\n\n " );
}

void liberar( char **frases, int numStrings ){
int i;
for (i=0; i < numStrings; i++){
free (frases[i]);
}

free (frases);
}


Un fuerte abrazo para todos.
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

MAFUS

#6
Como verás hace uso de argumentos no tan comunes en scanf, pero con ellos obtengo el dato que quiero y además me libero de \n en el buffer, todo en la misma línea.

#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;
}

dato000



no puedo parar de reir con ese gif, siempre que lo veo me quedo mirandolo como un idiota contento.

Cita de: NOB2014 en  3 Octubre 2016, 23:02 PM
dato000 gracias por ocuparte del tema anterior. -
Saludos

Yo que hice??? en fin, slds

Creo que ya todo esta dicho, punteros no es mi fuerte, pero lo que tengo que añadir del codigo de MAFUS es que no es estandar esa asignación scanf("%m") y que puede variar su resultado dependiendo del compilador, pues he visto casos en los que al recibir caracter espacio o salto de linea obtiene un desbordamiento y almacena basura en un espacio de memoria aleatorio después de la primera palabra de una serie de caracteres, pues scanf se supone que es más para memoria estatica.

Aunque supongo que con la extensión del estandar y las librerias apropiadas junto con un compilador actualizado ese problema seria resuelto y se usaria como un realloc verdadero.



NOB2014

abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

MAFUS

La opción %m está incluida en el estándar POSIX.1-2008: http://pubs.opengroup.org/onlinepubs/9699919799/

Si se usa con %ms no recogerá toda la línea ya que el modificador %s se detiene en el primer carácter en blanco. Para ello se usa el %[^\n] que recoge toda la línea hasta el final o hasta encontrarse un carácter de nueva línea.

Como nota adicional el %*c al final de la cadena de control hace que se recoja el carácter de nueva línea pero no se asigne a ningún sitio, así se quita del buffer de entrada.