Ayuda!! duda en un programa

Iniciado por BlerofonT, 4 Junio 2012, 22:05 PM

0 Miembros y 2 Visitantes están viendo este tema.

BlerofonT

Buenos dias chic@s. Tengo una duda con un programa. Realmente le he hecho de dos formas, de la primera no funciona y de la segunda si. Como estoy aprendiendo programacion, me gustaria que alguien me explique porke narices no funciona la primera(creo que es relacionado con el paso por punteros o direcciones de memoria, pero no lo se...). Aqui dejo el codigo. No os asusteis porke sea muy largo, con que mireis la ultima funcion llamada "eliminar"(elimina una estructura de un arreglo) que es donde esta el problema, ya vale(dejo el programa por si alguien le kiere ejecutar y para que se entienda mejor). El problema es que aunque paso a la funcion el arreglo como puntero, no me elimina la estructura del arreglo(aunke la "n" si disminuye una unidad). Realmente parece que si la elimina(si miramos las llamadas a visualizar), pero no llega bien a la funcion main. Supongo para alguien que sepa programar bien la duda sera estupida, pero yo no lo entiendo :(

Gracias a todos!!!

Código (cpp) [Seleccionar]
/*****   Preproceso*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define N 50
#define ELEM 20
#define UU char(163)/*Para los acentos*/

/***** Variables globales*/
/***** int const N=50;*/
struct Producto{
       int codigo;
       char nombre[N];
       float precio;
       int stock;
       };

/***** Declaracion de funciones o procedimientos*/
int menu (void);
void introducir (struct Producto x[],int &n);
void visualizar (struct Producto x[],int n);
int existe_codigo (struct Producto x[],int n, int cod);
void comprar (struct Producto x[],int n);
void vender (struct Producto x[],int n);
void modificar (struct Producto x[],int n);
int submenu (void);
void ordenar_cod (struct Producto x[],int n);
void ordenar_pre (struct Producto x[],int n);
void ordenar_sto (struct Producto x[],int n);
void ordenar_nom (struct Producto x[],int n);
void grabar_fichero (struct Producto x[],int n,char* nom);
void cargar_fichero (struct Producto x[], int &n, char* nom);
void cambiar (struct Producto x[], int &n, char* nom);
void eliminar (struct Producto x[], int &n);

/***** Programa principal*/

int main (){
    /***** Var. Locales*/
    int opcion=0, opcion2 =0;
    int n = 0;
    char nombre[ELEM];
    struct Producto producto[ELEM];
    printf ("C%cal es el nombre de la tienda??", UU);
    gets(nombre);
    cargar_fichero (producto, n, nombre);
   
    do{
       opcion = menu();
       switch(opcion){
             case 1:
                  introducir(producto, n);
                  break;
             case 2:
                  visualizar(producto, n);
                  break;
             case 3:
                  comprar(producto, n);
                  break;
             case 4:
                  vender(producto, n);
                  break;
             case 5:
                  modificar(producto, n);
                  break;
             case 6:
                  opcion2 = submenu();
                  switch(opcion2){
                                  case 1:
                                  ordenar_cod(producto, n);
                                  break;
                                  case 2:
                                  ordenar_nom(producto, n);
                                  break;
                                  case 3:
                                  ordenar_pre(producto, n);
                                  break;
                                  case 4:
                                  ordenar_sto(producto, n);
                                  break;           
                  }
                 
                  break; 
             case 7:
                  cambiar(producto, n, nombre);
                  break;
             case 8:
                  eliminar(producto, n);
                  visualizar (producto,n);/*Llamada para ver el ERROR*/
                  break;
       }
         
    } while (opcion !=0);
    grabar_fichero(producto, n, nombre);
    return 0;
}


/***** Cuerpo de las funciones*/
int menu (void){
    int opcion;
    do{
       printf ("\n\n1. Introducir Producto");
       printf ("\n2. Listar Productos disponibles");
       printf ("\n3. Comprar");
       printf ("\n4. Vender");
       printf ("\n5. Cambiar Precio");
       printf ("\n6. Ordenar");
       printf ("\n7. Cambiar tienda");
       printf ("\n8. Eliminar producto");
       printf ("\n0. Salir\n\n");
       fflush (stdin);
       scanf ("%d", &opcion);
       
    }while((opcion<0) || (opcion>8));
    return opcion;
}


int submenu (void){
    int opcion;
    do{
       printf ("\n¿Como quieres ordenar?");
       printf ("\n1. Codigo");
       printf ("\n2. Nombre");
       printf ("\n3. Precio");
       printf ("\n4. Stock\n\n");
       fflush (stdin);
       scanf ("%d", &opcion);
       
    }while((opcion<1) || (opcion>4));
    return opcion;
}
   

void introducir (struct Producto x[],int &n){
     int controlar;
     do{
     printf ("\nIntroduzca Codigo: ");
     fflush (stdin);
     scanf ("%d", &x[n].codigo);
     controlar = existe_codigo (x, n, x[n].codigo);
     if (controlar != -1)
        printf("\nEl producto ya existe!!!");
     }while (controlar != -1);
     
     printf ("\nIntroduzca Nombre Producto: ");
     fflush (stdin);
     gets (x[n].nombre);
     printf ("\nIntroduzca Precio: ");
     fflush (stdin);
     scanf ("%f", &x[n].precio);
     printf ("\nIntroduzca Stock: ");
     fflush (stdin);
     scanf ("%d", &x[n].stock);
     n++;
}


void visualizar (struct Producto y[],int n){
     int i;
     for (i=0; i<n; i++){
         printf ("\n%10d\t%20s\t%10.2f\t%10d", y[i].codigo, y[i].nombre, y[i].precio, y[i].stock);
     }
}


int existe_codigo (struct Producto x[],int n, int cod){
     int i, r = -1;
     for (i=0; i<n; i++){
         if (x[i].codigo == cod){
            r = i;
            break;
           
         }
     }
     return r;/*****Retorna la posicion si existe y -1 si no existe*/
}


void comprar (struct Producto x[],int n){
     int codigo, result, cant;
     printf ("\nQue producto desea comprar?(indique codigo)");
     fflush (stdin);
     scanf ("%d", &codigo);
     result = existe_codigo (x, n, codigo);
     if (result == -1){
          printf ("\nEl producto no existe!!!");
     }
     else{
          printf ("\nCuanta cantidad desea comprar??");
          fflush (stdin);
          scanf ("%d", &cant);
          x[result].stock = x[result].stock + cant;
     }
}


void vender (struct Producto x[],int n){
     int codigo, result, cant;
     printf ("\nQue producto desea vender?(indique codigo)");
     fflush (stdin);
     scanf ("%d", &codigo);
     result = existe_codigo (x, n, codigo);
     if (result == -1){
          printf ("\nEl producto no existe!!!");
     }
     else{
          printf ("\nCuanta cantidad desea vender??");
          fflush (stdin);
          scanf ("%d", &cant);
          x[result].stock = x[result].stock - cant;
     }
}


void modificar (struct Producto x[],int n){
     int codigo, result;
     float precio;
     printf ("\nQue producto desea modificar precio?(indique codigo)");
     fflush (stdin);
     scanf ("%d", &codigo);
     result = existe_codigo (x, n, codigo);
     if (result == -1){
          printf ("\nEl producto no existe!!!");
     }
     else{
          printf ("\nValor del nuevo precio: ");
          fflush (stdin);
          scanf ("%f", &precio);
          x[result].precio = precio;
     }
}


void ordenar_cod (struct Producto x[],int n){
     bool ordenado = false;
     int i;
     struct Producto aux;
     int j = 0;
     while (j<n-1 || ordenado == false){
           ordenado = true;
           for (i=0; i<n-1; i++){
                     if (x[i].codigo > x[i+1].codigo){
                     aux = x[i];
                     x[i] = x[i+1];
                     x[i+1] = aux;
                     ordenado = false;
                     }
           }                     
           j++;
     }
}


void ordenar_pre (struct Producto x[],int n){
     bool ordenado = false;
     int i;
     struct Producto aux;
     int j = 0;
     while (j<n-1 || ordenado == false){
           ordenado = true;
           for (i=0; i<n-1; i++){
                     if (x[i].precio > x[i+1].precio){
                     aux = x[i];
                     x[i] = x[i+1];
                     x[i+1] = aux;
                     ordenado = false;
                     }
           }                     
           j++;
     }
}


void ordenar_sto (struct Producto x[],int n){
     bool ordenado = false;
     int i;
     struct Producto aux;
     int j = 0;
     while (j<n-1 || ordenado == false){
           ordenado = true;
           for (i=0; i<n-1; i++){
                     if (x[i].stock > x[i+1].stock){
                     aux = x[i];
                     x[i] = x[i+1];
                     x[i+1] = aux;
                     ordenado = false;
                     }
           }                     
           j++;
     }
}


void ordenar_nom (struct Producto x[],int n){
     bool ordenado = false;
     int i;
     struct Producto aux;
     int j = 0;
     while (j<n-1 || ordenado == false){
           ordenado = true;
           for (i=0; i<n-1; i++){
                     if (strcmp (x[i].nombre , x[i+1].nombre) > 0){
                     aux = x[i];
                     x[i] = x[i+1];
                     x[i+1] = aux;
                     ordenado = false;
                     }
           }
           j++;
     }
}


void grabar_fichero (struct Producto x[], int n, char* nom){
     FILE *fichero = NULL;
     int i;
     fichero = fopen(nom, "wb");
     if (fichero == NULL){
        printf ("\nERROR: No se ha podido abrir %s", nom);
        getch();
        exit(0);
     }
     else{
         for (i=0; i<n; i++){
             fwrite(&x[i], sizeof(struct Producto), 1, fichero);
         }
         fclose(fichero);
     }
}


void cargar_fichero (struct Producto x[], int &n, char* nom){
     FILE *fichero = NULL;
     strcat(nom,".dat");
     fichero = fopen(nom, "rb");
     if (fichero == NULL){
        printf ("\nADVERTENCIA: No se ha podido abrir %s", nom);
        getch();
     }
     else{
             fread(&x[n], sizeof(struct Producto), 1, fichero);
             while(!feof(fichero)){
                 n++;
                 fread(&x[n], sizeof(struct Producto), 1, fichero);
             }
             fclose(fichero);
     }
}


void cambiar (struct Producto x[], int &n, char* nom){
     grabar_fichero(x, n, nom);
     printf ("\nC%cal es el nombre de la tienda a la que quieres cambiar??", UU);
     fflush (stdin);
     gets(nom);
     n=0;
     cargar_fichero (x, n, nom);
}


void eliminar (struct Producto x[], int &n){
     int pro_elim, result, i,j=0;
     struct Producto auxiliar[ELEM];
     printf ("\nCodigo del producto que deseas eliminar??");
     fflush (stdin);
     scanf ("%d", &pro_elim);
     result = existe_codigo (x, n, pro_elim);
     if (result == -1){
          printf ("\nEl producto no existe!!!");
     }
     else{
          for(i=0; i<n; i++){
                if (i!=result){
                      auxiliar[j]=x[i];
                      j++;
                }
          }
          n--;
          x = auxiliar;
     }
     visualizar (auxiliar,n);/*Llamada para ver el ERROR*/
     visualizar (x,n);/*Llamada para ver el ERROR*/
}


Funcion "eliminar" corregida y SI FUNCIONA:

Código (cpp) [Seleccionar]
void eliminar (struct Producto x[], int &n){
     int pro_elim, result, i,j=0;
     struct Producto auxiliar[ELEM];
     printf ("\nCodigo del producto que deseas eliminar??");
     fflush (stdin);
     scanf ("%d", &pro_elim);
     result = existe_codigo (x, n, pro_elim);
     if (result == -1){
          printf ("\nEl producto no existe!!!");
     }
     else{
          for(i=0; i<n; i++){
                if (i!=result){
                      auxiliar[j]=x[i];
                      j++;
                }
          }
          n--;
          for(i=0; i<n; i++){
                   x[i]= auxiliar[i];
          }
     }
     visualizar (auxiliar,n);/*Llamada para ver el ERROR*/
     visualizar (x,n);/*Llamada para ver el ERROR*/
}


El problema esta en:

Código (cpp) [Seleccionar]
x = auxiliar;

que lo he cambiado por lo siguiente y si funciona:

Código (cpp) [Seleccionar]
for(i=0; i<n; i++){
          x[i]= auxiliar[i];
          }


durasno

Hola! una pregunta esto es C++??? porque veo q usas int &n, creo q en C++ usan & en los parametros de la funcion, a menos q en C tambien se emplee y no me entere :)...

Te respondo como si esto fuese C: es raro que te deje compilar con
x = auxiliar;
el compilador deberia darte error. El problema es que "x" y "auxiliar" son arreglos; a pesar de q son arreglos de estructuras, para asignar uno a otro siempre se hace copiando cada elemento(como si fuesen arreglos comunes). Es por eso que te funciona bien con
for(i=0; i<n; i++){
          x[i]= auxiliar[i]; // asignacion de elemento x elemento
          }


Saludos

PD: la asignacion de estructuras si es valida, la  de arreglos no
Ahorrate una pregunta, lee el man

BlerofonT

#2
Gracias por la ayuda durasno!! El codigo es C++ y efectivamente es un paso por referencia el int &n. La verdad que no sabia que para copiar los arreglos tenias que ir elemento a elemento, asike muchas gracias. Yo pense que como los nombres de los arreglos (x  y auxiliar en mi caso) son direcciones de memoria del primer elemento del arreglo, pense que asignando x = auxiliar; me serviria(que por cierto no da ERROR).

Lo que me extraña mucho es que si te fijas en las funciones visualizar que tenemos justo debajo de x = auxiliar; , ambas lo muestran correctamente, con el elemento eliminado. E problema es que cuando vuelvo a la funcion "main" y tengo una nueva llamada a visualizar(justo el case 8 del switch) con el arreglo "producto" que deberia ser el mismo que el arreglo "x" de la funcion eliminar, pues este arreglo muestra un elemento menos(ya que pase la n por referencia) pero no elimina el que yo keria, sino el ultimo.

¿Alguien sabe porque?

maxim_o

Supongo que será por que n no es un puntero y esa funcion tampoco devuelve nada... por lo que el n-- que haces en la funcion eliminar en la funcion main no se "resta"... (es la unica diferencia que puedo ver desde la llamada visualizar de la funcion eliminar a la del main... en el main n vale 1 mas...

Además en esa funcion (eliminar), pasas la n como referencia, pero a la hora de llamarla no le pasas un puntero? le pasas un int normal y corriente? O estoy muy perdido yo... o ahí falla algo....


Y igual saldria bien cada vez que elimines rellenar de valor nulo la ultima posicion o entonces tendras que usar la n como puntero siempre para que una vez la modifiques en una funcion este en el main modificada tambien?

Me explico ("con numeros"); si un arreglo tiene 5 1 3 4 5
Imagina que el array es de tamaño 10 (posiciones de 0 -9), y decides borrar el 3...
copiaria en auxiliar el 5 1 4 5 y luego al volver a su "array original") pondria 5 1 4 5 (pero el ultimo 5 no está borrado....) por lo que quedaria 5 1 4 5 5


BlerofonT

#4
Hola de nuevo!!! Gracias maxim_o!!! Pero tu ejemplo del final con numeros no esta bien, te explico.

El codigo es C++ por eso hago el paso por referencia del entero "n"(no hace falta pasarle un puntero) y funciona perfecto.

El problema con numeros es:

Yo tengo el array 1 3 5 7 9, llamo a eliminar y quiero borrar por ejemplo 5, entonces me retorna 1 3 5 7 (sin el 9) ya que como he dicho, la "n" si que se resta una unidad, pero el array cambia de tamaño(uno menos) pero no cambia sus elementos.
En cambio, coloqué las llamadas a visualizar dentro de la funcion "eliminar" y al visualizar "auxiliar" se ve 1 3 7 9 y lo mas gracioso es que si visualizo "x" tambien se ve 1 3 7 9, EL PROBLEMA es que al retornar a main y llamar a visualizar con "producto" (que deberia ser igual que "x" debido a la llamada de la funcion "eliminar"), se visualiza como dije al principio 1 3 5 7.

¿Alguien me puede ayudar?... no lo entiendo :(

Ferno

Estoy casi seguro que es un problema de referencias.

Prueba esto en tu función eliminar:

Código (cpp) [Seleccionar]
for(i=0; i<n; i++){
                if (i!=result){
                      &(auxiliar[j])=&(x[i]);
                      j++;
                }
          }
          n--;
          x = auxiliar;
          }

STANHMAL

Wenaz,

El código es C no C++, ahora te explico porque no funciona de ambas maneras :


    x = auxiliar;


Cuando lo haces de esta forma estas asignándole a la variable x el valor que tiene auxiliar, pero como x y auxiliar no son simples variables, si no que son arreglos de variables, y para copiar un arreglo en otro, es necesario hacerlo elemento por elemento, tal y como lo haces de la segunda forma :


     for(i=0; i<n; i++){
          x[i]= auxiliar[i];
      }


Veo que usas variables de tipo bool, es incorrecto usarlas, pues son de C++ y no de C, te recomiendo hacer un enum para no tener que modificar tanto así:


...
enum bool {false, true};
...


y su utilización así :


void ordenar_cod (struct Producto x[],int n){
     enum bool ordenado = false;
    ...
}


es decir donde estas declarando las bool, le antepones el enum y listo.

bien, aparte de eso tienes otro reguero de cosas que no deberías de hacer, pásate por este post :

|Lo que no hay que hacer en C/C++. Nivel basico|

$4!u2
Power Metal vs Reggaeton



Que es mi ordenador mi tesoro que todo el mundo ha de temer. Mi ley, el ratón y el módem. Mi única patria, la red

maxim_o

El ha dicho que es C++....
aunque mas bien es una mezcla de ambos...

durasno

Hola! es raro lo que te pasa, asi que decidi adapatarlo a C puro :P (sacando el & de las funciones, paso n por valor y retorno esa n....) lo compile y probe el problema que decias, a mi me anda perfecto. Elimino y despues imprime correctamente ya sea desde el main o desde la funcion.
Seguro es como dijo ferno, tenes un problema de referencias pero eso ya pasa a un problema de C++, xq a mi me anda :)

Saludos
Ahorrate una pregunta, lee el man

BlerofonT

Hola chic@s!!!

Primero de todo agradecer de nuevo a durasno, maxim_o, STANHMAL y ferno por vuestra ayuda (gracias tambien a STANHMAL por indicarme otros errores y pasarme el link, ya q para la gente q estamos empezando es una buena ayuda). Bueno esta tarde a las 2:00 di con el problema pero me tuve q ir de casa, asike paso a indicarosle por si stais interesados,jejeje.(Por cierto el codigo es una mezcla de C y C++ como habeis dicho, pero esque me compre un libro para empezar que es bastante bueno, y explica junto el C y C++ y segun el libro lo de C te vale para C++ asike siempre guardo como .cpp)

SOLUCION DEL PROBLEMA

El problema esta en la linea "x = auxiliar;" (como dijo STANHMAL) que en principio no da ERROR ya que "auxiliar" si es un array pero "x" es una direccion de memoria y lo que hace es asignarle la direccion de memoria del primer elemento de "auxiliar" a "x". Cual es el problema, las direcciones de memoria. Al llamar a la funcion la paso como parametro "producto" cuya posicion es ABCF001 y se la asigna a "x", luego la posicion de "x" es ABCF001. Posteriormente se crea el array "auxiliar[ELEM]" cuya direccion de memoria del primer elemento (escribiendo "auxiliar") es CDEF005. Despues hago todo bien, peeeeero llegamos a "x = auxiliar;" sin haber cambiado nada en "x", y por tanto no he cambiado nada en "producto", y al hacer "x = auxiliar;" la "x" pasa a valer CDEF005. Por lo que justo antes de retornar a main, tenemos:

auxiliar => Direccion: CDEF005 => array con el elemento bien eliminado
x => Direccion: CDEF005 => apunta a "auxiliar" luego apunta al array con el elemento bien eliminado
producto => Direccion: ABCF001 => array que en ningun momento se modifico, ya que o le tenia que haber modificado antes de "x = auxiliar;" o sino tenia q tener actualmente la direccion CDEF005

Espero se me haya entendido :D

Por lo tanto, uso el bucefor. Ya dije desde el principio que el programa funcionaba con el bucle, pero solo estaba interesado en entender el problema de porque no funcionaba de la otra forma. Ahora ya sta todo claro.


NOTAS

Ferno
Estaba casi convencido cuando lei tu mensaje que funcionaria tal y como tu decias, ya que ya entendia el problema q tenia yo primero y tu solucion me parecia buena, pero fui a compilar y me dio ERROR, este era:

"In function 'void eliminar(Producto*, int&)':
non-Ivalue in assignment"

que si alguien sabe lo que significa que me lo explike, q stoy aprendiendo!!!!jejeje

Saludos a todos!!!