TransWikia.com

Como puedo ordernar nombres por genero en C?

Stack Overflow en español Asked by David Ricardo lee on August 27, 2021

Estoy haciendo un programa donde el usuario ingresa 15 nombres nombres y determina si es hombre o mujer, el problema que tengo es que el programa termina abructamente despues del input, intente usar char* pero el compilador devuelve error: invalid conversion from 'const char*' to 'char' [-fpermissive]

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

int main( ) {
  char n[15],h[15],d[15], g[15];
  int i,c=0,p=0,e;

  printf("nCuantos nombre desea ingresar?n");
  scanf("%d",&e);

  for(i=0;i<e;i++){
    printf("ingrese el nombre %dn",i+1);
    scanf("%s",&n[i]);
    printf("escoja el genero de %sn",n[i]);
    scanf("%s",&g[i]);

    if(g[i]=='m'){  
      n[i]=h[i];
      c=c+1;
    }
    else if(g[i]=='f'){
      n[i]=d[i];
      p=p+1;    
    }
  }

  printf("-----------------n");
  printf("%d hombres: n",c);

  for(i=0;i<c;i++){
    printf("%sn",h[i]);
  }

  printf("%d mujeres: n",p);

  for(i=0;i<p;i++){
    printf("%sn",d[i]);
  }
}

3 Answers

Esto es un vector de 15 elementos de tipo char:

char n[15];

Y aquí escribes en dicho vector:

for(i=0;i<e;i++){
    scanf("%s",&n[i]);

¿Problemas de estas tres líneas? Dos, básicamente:

  1. Sobreescribes los datos del usuario

    Como he comentado, n es un vector de 15 elementos de tipo char:

          00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
     n -> xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
    

    Entonces, en la primera iteración almacenas un string a partir de la posición dada por n[0]:

          00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
     n ->  D  a  v  i  d  xx xx xx xx xx xx xx xx xx
    

    En la segunda iteración, almacenas otro string a partir de la posición de n[1]:

          00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
     n ->  D  L  a  u  r  a  xx xx xx xx xx xx xx xx
    

    Y, como ves, eso provoca que se pierda la primera cadena.

  2. Desbordamiento del buffer

    Siguiendo con lo comentado en el punto anterior, cuando e vaya teniendo valores altos, el algoritmo empezará a escribir en las últimas posiciones del array, luego habrá menos espacio útil para almacenar las cadenas, lo que aumenta el riesgo de que el código escriba fuera de los límites del array. Por ejemplo, si estamos en la 12º iteración, únicamente podremos introducir una cadena de 2 caracteres:

          00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
     n -> xx xx xx xx xx xx xx xx xx xx xx xx  A  B 
    

    Si introducimos una cadena más grande acabermos escribiendo fuera de los límites del array:

          00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 ~~~~~~~~~ <-- desbordamiento
     n -> xx xx xx xx xx xx xx xx xx xx xx xx  R  u  b  e  n  
    

    Cuando esto sucede pueden pasar dos cosas:

    • El Sistema Operativo detecta que accedes a memoria que no te pertenece y mata tu proceso
    • Sobreescribes el valor de otras variables, lo que vuelve tu programa (u otros procesos) inestables

Para resolver estos problemas tienes que usar un array doble o matriz

// Puede almacenar 15 nombres, cada uno con una longitud máxima de 19 caracteres
char n[15][20];

Realmente no necesitas usar matrices en n. Si sigues leyendo verás por qué.

Aunque claro, quizá n no sea el nombre más apropiado para una variable... no te van a cobrar ningún suplemento, así que te sugiero que los nombres de las variables sean representativos:

char nombre[15][20];

Tu código quedará más legible y será más dificil que metas la pata al usar las variables.

Una vez que ya has pedido el nombre y el género copias los datos a otro array (dependiendo del género):

if(g[i]=='m'){  
  n[i]=h[i];
  c=c+1;
}

Este código tiene también dos problemas:

  1. Las asignaciones se hacen justamente al revés, es decir, ahora mismo estás copiando caracteres de h en n y debería ser al revés. Además, fíjate que estás copiando caracteres, no cadenas.

    Un detalle importante en C es que las cadenas se copian usando funciones, como strcpy. Si esta función te da errores probablemente se deba a que no estás intentando copiar cadenas sino, como es este caso, caracteres sueltos (el compilador puede ser tu amigo)

    Como te comenté antes, no es necesario que uses matrices en n. El motivo es que tu código se limita a pedir un nombre y a copiarlo en otra lista en función del género.

    Es decir, las listas finales que deben ser matrices, pero n puede ser una cadena de caracters al uso:

     // Cadena de caracteres
     char nombre[20];
    
     // Listas de cadenas
     char hombres[15][20];
     char mujeres[15][20];
    

    De esta forma, reutilizas nombres para pedir los datos al usuario:

     for(i=0;i<e;i++){
         printf("ingrese el nombre %dn",i+1);
         scanf("%s", nombre);
    
         strcpy(hombres[i], nombre);
    
  2. Para el array h deberías usar el índice c en vez de i

    Efectivamente, usas c y p en lo que parece que debieran ser los índices para las dos listas de géneros... pero no aprovechas sus valores al rellenar dichas listas.

Aplicando las correcciones:

int main( ) {
  char nombre[20];
  char genero[15];
  char hombres[15][20];
  char mujeres[15][20];

  int indice_hombres = 0;
  int indice_mujeres = 0;

  int total_datos;
  printf("nCuantos nombre desea ingresar?n");
  scanf("%d",&total_datos);

  for(int i=0;i<total_datos;i++)
  {
    printf("ingrese el nombre %dn",i+1);
    scanf("%s", nombre);
    printf("escoja el genero de %sn", nombre);
    scanf("%s", genero);

    if(genero[0] == 'm')
    {  
      strcpy(hombres[indice_hombres], nombre);
      indice_hombres++;
    }
    else if( genero[0] == 'f')
    {
      strcpy(mujeres[indice_mujeres], nombre);
      indice_mujeres++;
    }
  }

Correct answer by eferion on August 27, 2021

El problema que estas viendo corresponde a esta línea:

printf("escoja el genero de %sn",n[i]);

Esto es debido a que estas indicando que vas a imprimir una string (%s) sin embargo le das a la función un char (n[i]).

                          string   char
                            V       V
printf("escoja el genero de %sn",n[i]);

C interpreta una string como un arreglo de chars finalizados por el carácter fin de string que corresponde a ''. Si tu compilador no te detuviera, el programa empezaría a leer posiciones en memoria consiguientes a n[i] buscando por '' hasta que eventualmente llegaría a un espacio en memoria que no está reservado para el mismo y tendrías como resultado un error de segmentation fault o similar.

Puedes comprobar esto reemplazando la línea por:

printf("escoja el genero de %cn",n[i]);

Y verás como el error se corrige porque la función printf sabe que solo debe de imprimir un carácter.

Ahora aquí es donde viene el problema porque en realidad estás queriendo guardar toda una string y no solo un carácter. Sin embargo, en tu definición:

char n[15],h[15],d[15], g[15];

Estas creando 4 arreglos de 15 caracteres, en otras palabras 4 strings. En el array n tienes 15 espacios solo para 1 carácter.

Una solución a esto sería crear un arreglo de 2 dimensiones, es decir, un arreglo de X número de strings de Y caracteres. Y se declararía así:

char nombres[MAX_CANT_NOMBRES][MAX_TAMANO_NOMBRE+1];

Esto crearía una lista de tamaño MAX_CANT_NOMBRES de nombres de tamaño de MAX_TAMANO_NOMBRE. El +1 es para hacer espacio para el carácter de fin de string ''.

Aquí te dejo un ejemplo para que veas como funcionaría, ignora la función de imprimirLista, la hice solo para que vieras el resultado de la lista que se crea y agrega conceptos más avanzados y confusos.

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

int MAX_TAMANO_NOMBRE = 20;    //Máximo largo de un nombre
int MAX_CANT_NOMBRES =15;      //Cuántos nombres vamos a guardar como máximo


void imprimirLista(char (*nombres)[MAX_CANT_NOMBRES][MAX_TAMANO_NOMBRE+1], char (*generos)[MAX_CANT_NOMBRES][2], int cantidad){
    for(int i=0;i<cantidad;i++){    
        printf("Nombre#%d: %s, sexo:%sn", cantidad,(*nombres)[i],(*generos)[i]);

    }
}

int main( ) {
    char nombres[MAX_CANT_NOMBRES][MAX_TAMANO_NOMBRE+1]; //15 nombres de un tamaño de 20 caracteres cada uno (se agrega uno para el caracter de fin de string '')
    char generos[MAX_CANT_NOMBRES][2];//Tienen un tamaño de 2 porque es la letra +''
    int iteraciones = 0;
    
    printf("nCuantos nombres desea ingresar?n");
    scanf("%d",&iteraciones);
    
    for(int i=0;i<iteraciones;i++){
        printf("Ingrese el nombre %dn",i+1);
        scanf("%s",nombres[i]);
        printf("Escoja el genero de %s (digite m o f)n",nombres[i]);
        scanf("%s",generos[i]);
    }
    
    imprimirLista(&nombres,&generos,iteraciones);
  
}

Para una lectura más simple podemos parametrizar con #define los tamaños del array 2D y utilizartypedef para las estructuras, algo así:

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

#define MAX_TAMANO_NOMBRE 20    //Máximo largo de un nombre
#define MAX_CANT_NOMBRES  15    //Cuántos nombres vamos a guardar como máximo

//Definimos un datatype que consiste en una lista de 15 nombres, con 20 caracteres (Array 2D de chars)
//El 20+1 es para incluir el caracter de fin de string: ''
typedef char listaNombres [MAX_CANT_NOMBRES][MAX_TAMANO_NOMBRE+1];

//Definimos un datatype que consiste en una lista de 15 nombres, con 20 caracteres (Array 2D de chars)
//El 20+1 es para incluir el caracter de fin de string: ''
typedef char listaGeneros [MAX_CANT_NOMBRES][2];

void imprimirLista(listaNombres * nombres, listaGeneros * generos, int cantidad){
    for(int i=0;i<cantidad;i++){    
        printf("Nombre#%d: %s, sexo:%sn", cantidad,(*nombres)[i],(*generos)[i]);

    }
}


int main( ) {
    listaNombres nombres;
    listaGeneros generos;
    
    int iteraciones = 0;
    
    printf("nCuantos nombres desea ingresar?n");
    scanf("%d",&iteraciones);
    
    for(int i=0;i<iteraciones;i++){
        printf("Ingrese el nombre %dn",i+1);
        scanf("%s",nombres[i]);
        printf("Escoja el genero de %s (digite m o f)n",nombres[i]);
        scanf("%s",generos[i]);
    }
    
    imprimirLista(&nombres,&generos,iteraciones);
    
}

Espero que esto no genere más preguntas que respuestas, sin embargo, te va a tirar en la dirección correcta, C es un lenguaje con una curva de aprendizaje muy alta.

Suerte en tu programación!

Answered by FranAcuna on August 27, 2021

El problema es que tu array n no tiene suficiente capacidad para lo que recolecta scanf(), los strings ya en sí son cadenas de caracteres (arrays):

char cadena[] = {"h","o","l","a"};

Cuando haces scanf("%s",&n[i]); le estás diciendo al compilador que te almacene en el primer elemento del array n (la primera iteración) la cadena ingresada. Estás ingresando una cadena en un espacio donde solo puede entrar un carácter.

La solución a esto es crear un array de arrays, donde los arrays son las cadenas (strings):

char n[15][15];

Por esto mismo también es recomendable definir de la misma manera los arrays h y d que deben de tener la misma capacidad que n, esto por que eventualmente van a almacenar un elemento de n.

Otra cosa que noté, es que haces asignaciones de este tipo:

n[i] = h[i];

Esto no es válido en primera instancia, ya que la asignación se debe de hacer de izquierda a derecha no al revés, debido a que en ese momento ese indice de h está vació.

Además puede generar errores, es peligroso. Siempre es mejor hacer uso de strcpy(), definida en el header <string.h>:

strcpy(h[i],n[i]);

Resumiendo, los arrays los debes de definir así:

char n[15][15];
char g[15]; //'g' solo va a recibir una letra
char h[15][15];
char d[15][15];

y el primer ciclo for debe de quedar así:

for (i = 0;i < e;i = i + 1) {
    printf("ingrese el nombre %dn",i + 1);
    scanf("%s",&n[i]);
    printf("escoja el genero de %sn",n[i]);
    scanf("%s",&g[i]);

    if(g[i] == 'm') {  
        strcpy(h[i],n[i]);
        c = c + 1;
    } else if(g[i] == 'f') {
        strcpy(d[i],n[i]);
        p = p + 1;    
    }
}

Espero te haya servido, saludos.

Answered by user166844 on August 27, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP