Programa se cierra al llamar a una funcion dentro de un do-while (lenguaje C)

Iniciado por polopo100, 15 Septiembre 2014, 01:47 AM

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

polopo100

Buenas, tengo un programa que debe leer el nombre de un cliente, los productos que compra, que cantidad, calcular el precio total de compra junto con el impuesto. Todo esto utilizando solo arreglos de una dimension y funciones. El problema es que al llamar la función "ventas" que se encarga de hacer los calculos de impuesto y demás, el programa se cierra sin ningun tipo de error, no se que estoy haciendo mal, ¿podrían echarme una mano por favor?

Les muestro el código que escribí:



#include <stdio.h>
#include <conio.h>
int lectura();
float ventas(int Nombre[30],int Descripcion[30],int Cantidad[30],float Precio[30],int X,int C);
float impresion(int Name[30],int Descr[30],int Cant[30],float Price[30],int X1,int C1,float Precioto[30],float subto,float tax,float Total,float Altotal);
int main()
{
int x=0;
printf("Mi nombre");
getch();
for(x=0;x<50;x++)
    {printf("\n");}
lectura();

return 0;
}
int lectura()
{
int descripcion[30];
int cantidad[30];
float precio[30];
int nombre[30];
int x=0,c=0;
char lim=0,limprod=0;
   do
{
  printf("\nIngrese el nombre del cliente: ");
  scanf("%s",&nombre[c]);
  do
  {
  printf("\nIngrese descripcion del producto: ");
  scanf("%s",&descripcion[x]);
  printf("\nIngrese cantidad del producto: ");
  scanf("%d",&cantidad[x]);
  printf("\nIngrese precio individual: ");
  scanf("%f",&precio[x]);
  x++;
  printf("\nIngresar otro producto? S/N ");
  limprod=getch();
  }
  while(limprod=='s'||limprod=='S');
  ventas(nombre,descripcion,cantidad,precio,x,c);
  printf("\nProcesar otro cliente? S/N");
  lim=getch();
  c++;
}
while(lim=='s'||lim=='S');
}
float ventas(int Nombre[30],int Descripcion[30],int Cantidad[30],float Precio[30],int X,int C)
{
    float precioto[30];
    int n=0;
    float subtotal=0,impuesto=0,total=0,altotal=0;
    int cltotal=0;
    for(n=0;n<X;n++)
    {
     precioto[n]=Cantidad[n]*Precio[n];
     subtotal+=precioto[n];
    }
    impuesto=subtotal*0.07;
    total=subtotal+impuesto;
    altotal+=total;
    impresion(Nombre,Descripcion,Cantidad,Precio,X,C,precioto,subtotal,impuesto,total,altotal);
}
float impresion(int Name[30],int Descr[30],int Cant[30],float Price[30],int X1,int C1,float Precioto[30],float subto,float tax,float Total,float Altotal)
{
    int n=0;
    printf("\n");
    printf(" Nombre del cliente: x %s x",Name[C1]);
    printf("\nDESCRIPCION\tCANTIDAD\tPRECIO\tPRECIO TOTAL");
    for(n=0;n<X1;n++)
    {
     printf("\n%s\t%.2f\t%.2f\t%.2f",Descr[n],Cant[n],Price[n],Total);
    }
    printf("\n\t\tSUBTOTAL: %.2f",Precioto);
    printf("\n\t\tITBMS: %.2f",tax);
    printf("\n\t\tTOTAL A PAGAR: %.2f",Total);
    printf("\n");
    printf(" Nombre del cliente: x %s x",Name[C1]);
    printf("\nDescripcion\tCANTIDAD\tPRECIO\tPRECIO TOTAL");
    printf("\nTotal Vendido por el Almacen: %.2f",Altotal);
}

Drewermerc

Hola amigo.
Bueno ahorita no tengo un compilador como borland para poder probar tu código ya que usas conio.h así que aquí te digo los errores que vi en tu código que a lo mejor son la causa de tu problema.
primero en la función lectura.
Declaraste las variables nombre y descripción como int cuando creo que son char.
y con scanf intentas solo capturar un carácter así que debes usar %c al igual que al imprimirlo debes cambiar el %s por %c algo así:

printf(" Nombre del cliente: x %c x",Name[C1]);
scanf("%c",descripcion[x]);

asi con la demas funciones y con loa argumentos que le pasas a las funciones ya que tienes mal el tipo de variable.
Tabien en lectura no veo que retornes algo así que la función la puede dejar  así:

void lectura()


Bueno espero que con esto se corrija el error que dices si tenes algún problema comenta;
bueno para mas información sobre lo de conio.h aqui te dejo este enlace.
http://foro.elhacker.net/programacion_cc/lo_que_no_hay_que_hacer_en_cc_nivel_basico-t277729.56.html
si evitas la librería a lo mejor sera mas fácil que te ayuden por aquí.
Saludos.
Drewermerc.

eferion

Deberías aprender a leer los errores que te da el compilador. Tu código tiene un montón de errores:

Código (cpp) [Seleccionar]

int nombre[30];
int descripcion[30];


tanto nombre como descripción han sido definidos como un array de enteros... si intentas tratar esto como una lista de strings lo vas a pasar mal.


char nombre[30][50];
char descripcion[30][50];


Ahora, tanto 'nombre' como 'descripcion' permiten almacenar 30 strings diferentes, cada uno con una longitud máxima de 49 caracteres.





float ventas(int Nombre[30],int Descripcion[30],int Cantidad[30],float Precio[30],int X,int C);
float impresion(int Name[30],int Descr[30],int Cant[30],float Price[30],int X1,int C1,float Precioto[30],float subto,float tax,float Total,float Altotal);


Vamos a ver, 'nombre', 'descripcion', 'cantidad' y 'precio' van siempre juntos... ¿por qué no los agrupas en una estructura? El código va a quedar mucho más bonito y legible... además, no es prudente usar funciones con muchos parámetros, por lo que interesa reducirlos al máximo:


// Definición de la estructura
typedef struct
{
  char nombre[ 50 ];
  char descripcion[ 50 ];
  int cantidad;
  float precio;
} Articulo;

// ...

// Declaramos un array de 30 artículos
Articulo articulos[ 30 ];

// Acceso a datos del articulo 10
articulos[ 9 ].cantidad = 10;


Con esto, las funciones ahora quedan un poco más legibles:


float ventas( Articulo *articulos, int X, int C );
float impresion( Articulo *articulos, int X1, int C1, float Precioto[30], float subto, float tax, float Total, float Altotal );


Esto aún puede mejorar un poco más, dado que tanto "ventas" como "impresion" van a recorrer toda la lista de artículos, no hace falta pasar 'X':


float ventas( Articulo *articulos, int C );
float impresion( Articulo *articulos, int C1, float Precioto[30], float subto, float tax, float Total, float Altotal );


Y aún se le puede dar una vuelta de rosca más. Dado que el arreglo de artículos debe ir siempre acompañado del total de artículos, parece lógico agrupar estos dos elementos en una nueva estructura:


typedef struct
{
  Articulo lista[ 30 ];
  int totalArticulos;
} Venta;


Con lo que ahora las funciones quedan más limpias todavía:


float ventas( Venta *venta );
float impresion( Venta *venta, float Precioto[30], float subto, float tax, float Total, float Altotal );


Mejor así, no?




int x=0,c=0;

¿Qué significa 'x'? ¿y 'c'? no son nombres 'válidos' porque no aportan información acerca de su finalidad. Es complicado seguir un código con variables sin sentido aparente. Hay que facilitar la lectura del código al máximo.

Por ejemplo, 'x' podría llamarse 'idArticulo' y 'c' lo podrías renombrar por 'totalArticulos'.




int lectura();
float ventas( ... );
float impresion( ... );


Si las funciones no tienen 'return algo', entonces deberían estar declaradas como 'void funcion':

void lectura();
void ventas( ... );
void impresion( ... );


Además, en C, si una función no está prensada para que reciba argumentos, hay que indicarlo poniendo 'void' entre los paréntesis:

void lectura( void );
void ventas( ... );
void impresion( ... );






printf("\nIngrese el nombre del cliente: ");
scanf("%s",&nombre[c]);


En C, los strings son punteros, por lo que sobra ese '&' que tienes ahí


printf("\nIngrese el nombre del cliente: ");
scanf("%s",nombre[c]);






do
{
  printf("\nIngrese el nombre del cliente: ");
  scanf("%s",&nombre[c]);
 
  do
  {
    printf("\nIngrese descripcion del producto: ");
    scanf("%s",&descripcion[x]);
    printf("\nIngrese cantidad del producto: ");
    scanf("%d",&cantidad[x]);
    printf("\nIngrese precio individual: ");
    scanf("%f",&precio[x]);
    x++;
    printf("\nIngresar otro producto? S/N ");
    limprod=getch();
  } while(limprod=='s'||limprod=='S');

  ventas(nombre,descripcion,cantidad,precio,x,c);
  printf("\nProcesar otro cliente? S/N");
  lim=getch();
  c++;
} while(lim=='s'||lim=='S');


Según este código... cada venta se asocia a un cliente... además este cliente puede adquirir un número indeterminado de artículos... este diseño no te va a permitir nunca guardar un historial de pedidos. Aprovechando la infraestructura que te he comentado, se podría modificar para adaptarla a estos requisitos:


#define MAX_LENGTH 50
#define MAX_ARTICULOS 30

typedef struct
{
  char nombre[ MAX_LENGTH ];
  char descripcion[ MAX_LENGTH ];
  int cantidad;
  float precio;
} Articulo;

typedef struct
{
  char cliente[ MAX_LENGTH ];
  Articulo articulos[ MAX_ARTICULOS ];
  int numeroArticulos;
} Venta;


He aprovechado también a introducir dos 'defines' porque no me gustan los literales metidos a pelo en el código.

Con este diseño conseguimos que cada cliente tenga su propia lista de artículos, aunque no le saques partido a dicho detalle en esta aplicación.





float ventas(int Nombre[30],int Descripcion[30],int Cantidad[30],float Precio[30],int X,int C)
{
    float precioto[30];
    int n=0;
    float subtotal=0,impuesto=0,total=0,altotal=0;
    int cltotal=0;
    for(n=0;n<X;n++)
    {
     precioto[n]=Cantidad[n]*Precio[n];
     subtotal+=precioto[n];
    }
    impuesto=subtotal*0.07;
    total=subtotal+impuesto;
    altotal+=total;
    impresion(Nombre,Descripcion,Cantidad,Precio,X,C,precioto,subtotal,impuesto,total,altotal);
}


¿Es necesario hacer estos cálculos aquí?

Asumiendo que sí, no es un buen sistema porque la llamada a "impresion" tiene demasiados argumentos... imagínate el lío si intercambias por error dos argumentos. Entre otras cosas puede que no seas capaz de ver el error tras muchas horas de sufrimiento.

Apoyándonos nuevamente en el diseño que hemos ido realizando, esto se puede mejorar sustancialmente:


typedef struct
{
  char nombre[ MAX_LENGTH ];
  char descripcion[ MAX_LENGTH ];
  int cantidad;
  float precio;
  float total;
} Articulo;

typedef struct
{
  char cliente[ MAX_LENGTH ];
  Articulo articulos[ MAX_ARTICULOS ];
  int numeroArticulos;
  float subtotal;
  float impuestos;
  float total;
} Venta;


Hemos añadido nuevos campos a las estructuras... ahora ya podemos actualizar el código de la función:


void ventas( Venta* venta, float* totalAlmacen )
{
  venta->subtotal = 0;
  venta->impuestos = 0;

  int i;
  for( i = 0; i < venta->numeroArticulos; i++ )
  {
    Articulo* articulo = &venta->articulos[ i ];
    articulo->total = articulo->cantidad * articulo->precio;

    float impuestos = articulo->total * 0.07;
    venta->subtotal += articulo->total;
    venta->impuestos += impuestos;
  }

  venta->total = venta->subtotal + venta->impuestos;
  *totalAlmacen += venta->total;

  impresion( venta, totalAlmacen );
}


Fíjate lo sencilla que ha quedado ahora la llamada a "impresion".

Si miras el código, verás que en el bucle uso el puntero "Articulo* articulo = &venta->articulos[ i ]". El puntero lo uso únicamente para reducir la cantidad de código a escribir... si no usase este puntero el código quedaría tal que:


for( i = 0; i < venta->numeroArticulos; i++ )
{
    Articulo* articulo = &venta->articulos[ i ];
    venta->articulos[ i ].total = venta->articulos[ i ].cantidad * venta->articulos[ i ].precio;

    float impuestos = venta->articulos[ i ].total * 0.07;
    venta->articulos[ i ].subtotal += venta->articulos[ i ].total;
    venta->articulos[ i ].impuestos += impuestos;
}


Parece obvio que el primer código es más legible.




El flujo de tu programa es deficiente.

"lectura" llama a "ventas" y este a su vez a "impresion". Esta cadena de llamadas debería estar controlada desde el "main". Los motivos son varios, pero tampoco es plan de escribir una tesis con este programa. Es importante intentar reducir la dependencia entre funciones.




El código final con los cambios aplicados:


#include <stdio.h>
#include <ctype.h>

#define MAX_LENGTH 50
#define MAX_ARTICULOS 30

typedef struct
{
  char nombre[ MAX_LENGTH ];
  char descripcion[ MAX_LENGTH ];
  int cantidad;
  float precio;
  float total;
} Articulo;

typedef struct
{
  char cliente[ MAX_LENGTH ];
  Articulo articulos[ MAX_ARTICULOS ];
  int numeroArticulos;
  float subtotal;
  float impuestos;
  float total;
} Venta;

void lectura( Venta* venta );
void ventas( Venta* venta, float* totalAlmacen );
void impresion( Venta* venta, float totalAlmacen );

int main()
{
  int x;
  for( x = 0; x < 50; x++ )
    printf("\n");

  float totalAlmacen = 0;
  Venta venta;

  lectura( &venta );
  ventas( &venta, &totalAlmacen );
  impresion( &venta, totalAlmacen );
  return 0;
}

void lectura( Venta* venta )
{
  int i = 0;

  printf("\nIngrese el nombre del cliente: ");
  scanf("%s", venta->cliente );

  char respuesta;
  do
  {
    printf("\nIngrese descripcion del producto: ");
    scanf("%s", venta->articulos[ i ].descripcion );

    printf("\nIngrese cantidad del producto: ");
    scanf("%d", &venta->articulos[ i ].cantidad );

    printf("\nIngrese precio individual: ");
    scanf("%f", &venta->articulos[ i ].precio );

    i++;

    printf("\nIngresar otro producto? S/N ");
    scanf( " %c", &respuesta );

  } while( tolower( respuesta ) == 's' );

  venta->numeroArticulos = i;
}

void ventas( Venta* venta, float* totalAlmacen )
{
  venta->subtotal = 0;
  venta->impuestos = 0;

  int i;
  for( i = 0; i < venta->numeroArticulos; i++ )
  {
    Articulo* articulo = &venta->articulos[ i ];
    articulo->total = articulo->cantidad * articulo->precio;
    float impuestos = articulo->total * 0.07;
    venta->subtotal += articulo->total;
    venta->impuestos += impuestos;
  }

  venta->total = venta->subtotal + venta->impuestos;
  *totalAlmacen += venta->total;
}

void impresion( Venta* venta, float totalAlmacen )
{
  printf("\n");
  printf(" Nombre del cliente: x %s x", venta->cliente );
  printf("\n%-30s | %-10s | %-10s | %-10s",
         "DESCRIPCION",
         "CANTIDAD",
         "PRECIO",
         "TOTAL" );

  int i;
  for( i = 0; i < venta->numeroArticulos; i++ )
  {
    Articulo* articulo = &venta->articulos[ i ];
    printf("\n%-30s | %10d | %10.2f | %10.2f",
           articulo->descripcion,
           articulo->cantidad,
           articulo->precio,
           articulo->total );
  }

  printf("\n\t\t%20s %6.2f", "SUBTOTAL:", venta->subtotal );
  printf("\n\t\t%20s %6.2f", "ITBMS:", venta->impuestos );
  printf("\n\t\t%20s %6.2f", "TOTAL A PAGAR:", venta->total );
  printf("\n");
  printf("\nTotal Vendido por el Almacen: %.2f", totalAlmacen );
}




polopo100

Gracias por sus respuestas Drewermerc y eferion, quizas debí aclarar algunas cosas, estoy en el primer nivel de un curso de programación de mi carrera, probablemente por eso he cometido errores que a ustedes les parezcan básicos. Para este programa en especifico me dieron ciertas limitaciones como que no puedo usar arreglos bidimensionales y la obligación de incluir la liberia conio.h, o usar otros recursos que mi instructor "no ha abarcado".

Ademas hay varios terminos que no entiendo a que se refieren, mas que nada en la respuesta de eferion, como las estructuras o punteros, no se siquiera la teoria relacionada, me puse a leer sobre dichos temas ya que por lo que estoy viendo en la respuesta de eferion son extremadamente útiles, pero para fines de este problema no puedo usarlos.

Corregí como sugeriste Drewermerc, los tipos de variable de nombre y descripcion en la declaración y en cada función, pero sigue cerrandose el programa. Ahora tengo una duda, ¿no hay posibilidades de guardar una cadena de caracteres en un arreglo unidimensional? Debe ser forzosamente en un arreglo bidimensional? Solo para quedar claro. Disculpen las molestias y gracias por sus respuestas.

eferion

Cita de: polopo100 en 15 Septiembre 2014, 20:00 PM
¿no hay posibilidades de guardar una cadena de caracteres en un arreglo unidimensional? Debe ser forzosamente en un arreglo bidimensional?

un número, por ejemplo el 10, se codifica en hexadecimal tal que: 00 00 00 0A. El 20.000 se codifica tal que: 00 00 4E 20. Es decir, un int SIEMPRE va a ocupar el mismo número de bits, independientemente de su valor.

Ahora probamos con strings. "Hola" requiere 5 bytes ( 4 para los caracteres y 1 para el caracter nulo de fin de cadena ), "Adios" requiere 6 y "elhacker.net", 13. Como ves, el espacio necesario para poder almacenar una cadena de caracteres depende de la longitud de la misma y esa es la razón por la que las cadenas son SIEMPRE punteros.

Un string en C puede quedar definido tal que:

char cadena[20]; // Longitud máxima de la cadena: 19

Con esto te respondo a tu segunda pregunta... NO, no tienen que ser arrays bidimensionales.

Si necesitas almacenar un nombre y una descripción puedes hacerlo tal que...

char cliente[ 20 ];
char descripcion[ 20 ];


... por ejemplo.


Lo que si te digo es que tu profesor no debería obligarte a usar conio... pero eso allá cada uno.