[C con Clase] Hijo, comprueba tu división con esto.

Davidson, Steven srd4121 en njit.edu
Jue Sep 25 20:13:01 CEST 2014


Hola Marcelino,

2014-09-25 10:49 GMT-04:00 marcelinux <marcelinator en gmail.com>:

> Hola amigos.
> Espero que no se moleste nadie por tratarle de amigo sin conocernos tanto,
> pero, para mí, una persona que comparte su conocimiento y sus dudas, me
> merece el trato de amigo.
>

Personalmente, no me molesta.

Al tema.
> Soy programador de otros lenguajes y estoy empezando con c y c++.
> He encontrado un programa en c que resuelve una división entera mostrando
> el cociente y el resto.
> Lo voy a usar para comprobar las divisiones de mi hijo en el cole.
> Pero, yendo más allá, lo he "convertido" en c++, mostrando cada iteración.
> Ya sabes, tomo la primera cifra, divido, calculo el resto, bajo la cifra
> siguiente, etc.
> La visualización es algo pobre porque, habiendo librerías gráficas y
> semigráficas (wxWidgets o nCurses), iré mejorando su aspecto.
> Os pego ambos programas.
> PD: Los he realizado en fuentes completos (sin cabeceras) para poder
> consultarlos con AvPag y RePag.
> Se admite cualquier comentario constructivo
>
>
Genial. Te comento mientras veo el código fuente.

division_con_resto.c
> [code]#include <stdio.h>
> main(){
>         int numerador=1,denominador;
>         while(numerador){
>                 printf("Dame el numerador (0=fin)\n");
>                 scanf("%d",&numerador);
>                 if(numerador){
>
                        printf("\nDame el denominador\n");
>                         scanf("%d",&denominador);
>                         int vueltas=0;
>                         while(numerador>=denominador){
>                                 numerador=numerador-denominador;
>

Acostúmbrate a usar los operadores de "operación y asignación"; esto es,

numerador -= denominador;

                                vueltas++;
>                         }
>

Como no haces otra cosa que obtener el cociente y el resto en este bucle,
sugiero dividir entre enteros directamente - sin la necesidad de un bucle.
Esto es,

cociente = numerador / denominador;
resto = numerador % denominador;

                        printf("Cociente: %d\n",vueltas);
>                         printf("Resto: %d\n", numerador);
>                 }
>         }
>

Debes retornar un entero. Si no, entonces indica 'void' para 'main()'.

}[/code]
>
>
Como una mejora, podemos eliminar la sentencia 'if' en el primer bucle si
reorganizamos las sentencias y el bucle para repetir otro patrón de
sentencias. Como un bucle ya "contiene" una condición, podemos combinar
ambas sentencias: 'if' y 'while' en un solo bucle. Esto es,

printf( "Dame el numerador (0=fin)\n" );
scanf( "%d", &numerador );

while( numerador )
{
  printf( "\nDame el denominador\n" );
  ...
  printf( "Dame el numerador (0=fin)\n" );
  scanf( "%d", &numerador );
}


> dividete.cpp
>
>
[CORTE]

#include <cstdlib>
> #include <string>
> #include <iostream>
> #include <iomanip>
> #include <sstream>
>
> //#define vervose
>
> int cifrasNumerador;
> char linea[21] = "                    ";
> const char rayas[11] = "__________";
> int posicionResto = 1, posicionCociente = 4;
>

No es nada recomendable usar variables globales. Sin embargo, no hay
problema si definimos constantes globales.


> using namespace std;
>
>
[CORTE]

int GetNumeroDeCifras(long numero){
>

No es necesario hacer estas conversiones. Podemos usar matemáticas para
determinar la cantidad de dígitos decimales; esto es,

return int(log10(numero)) + 1;

[CORTE]


> string BajaLaCifraSiguiente(string dividendoStr, string restoStr, int
> cifra){
>

Al pasar objetos, los cuales no tienes intención de modificar, procura
pasarlos por referencia (a objetos constantes) en lugar de por copia; o sea,

string BajaLaCifraSiguiente( const string &dividendoStr, const string
&restoStr, int cifra )

        #ifdef vervose
>                 cout << "BajaLaCifraSiguiente\tRecibe dividendoChar:" <<
> dividendoStr << ", resto:" << restoStr << " y cifra:" << cifra << endl;
>         #endif
>         char digito;
>         digito = dividendoStr[cifra];
>         #ifdef vervose
>                 cout << "Dígito " << digito << " en la cifra " << cifra <<
> endl;
>         #endif
>         int posicion;
>         posicion = restoStr.length();
>         #ifdef vervose
>                 cout << "Posición donde se inserta en el resto: " <<
> posicion << endl;
>         #endif
>         char *dividendoParcial = new char[posicion+1];
>         int i;
>         for(i = 0; i <= posicion; i++){
>

Tenemos un error al llegar a la última iteración, porque usamos 'i' como
índice para cadenas de diferentes cantidades: 'restoStr()' tiene una
cantidad menor que 'dividendoParcial', la cual tiene un carácter más. El
problema está en acceder al elemento de índice, 'posicion', del objeto,
'restoStr()'.

                #ifdef vervose
>                         cout << "i = " << i;
>                         cout << "\trestoStr[" << i << "] = " <<
> restoStr[i] << endl;
>                 #endif
>                 dividendoParcial[i] = restoStr[i];
>                 #ifdef vervose
>                         cout << "dividendoParcial[" << i << "] = " <<
> dividendoParcial[i] << endl;
>                 #endif
>         }
>         dividendoParcial[posicion] = digito;
>
>
Como estás construyendo una cadena para 'dividendoParcial', debes indicar
el final de tal cadena asignando el carácter nulo. Esto significa que
deberías hacer esto,

dividendoParcial[posicion] = 0;

Por lo tanto, o bien necesitas un carácter de más, o bien la cadena termina
en el índice 'posicion-1' para que puedas asignar el carácter nulo en el
índice: 'posicion'.

        #ifdef vervose
>                 cout << "BajaLaCifraSiguiente\tDevuelve " <<
> dividendoParcial << endl;
>         #endif
>         return(dividendoParcial);
>

Esto supondrá un grave problema de fuga de memoria, porque no habrá forma
de liberar la memoria que adjudicaste dinámicamente con 'new[]'. Deberías
hacer esto:

string resultado( dividendoParcial );
delete[] dividendoParcial;

return resultado;  // No necesitas paréntesis

}
>
>
Como al final necesitas un objeto de la clase 'string', sugiero crear tal
objeto dinámico en lugar de crear un array dinámico.

Por último, creo que no necesitas usar cadenas de caracteres. Puedes usar
matemáticas para conseguir lo que quieres y así no tienes que estar andando
con conversiones entre cadenas y enteros, hasta el momento de necesitarlas:
cuando hay que mostrar los resultados a la pantalla.

long int Divide(long dividendo, long divisor){
>         #ifdef vervose
>                 cout << "Divide\tRecibe dividendo:" << dividendo << " y
> divisor:" << divisor << endl;
>         #endif
>         long res = dividendo;
>         if(dividendo > divisor){
>                 long coc = GetCociente(dividendo, divisor);
>                 res = GetResto(dividendo, divisor);
>
>                 posicionCociente++;
>                 cout << "\n" << dividendo;// << "    ";
>                 cout.write(linea, posicionCociente);
>                 cout << coc << endl;
>                 cout << res << endl;
>         }
>         #ifdef vervose
>                 cout << "Divide\tDevuelve resto:" << res << endl;
>         #endif
>         return(res);
> }
>
> int main(){
>         MuestraAyuda();
>         long numerador = 1, denominador = 1;
>         while( numerador = GetDividendo() ){
>                 int r;
>                 if(numerador){
>

Aquí puedes intentar combinar 'while' y esta 'if' en un solo 'while', como
hicimos antes.

                        if( denominador = GetDivisor() ){
>                                 cifrasNumerador =
> GetNumeroDeCifras(numerador);
>                                 DibujaLaDivision(numerador, denominador);
>
>                                 string dividendoStr =
> NumToString(numerador);
>
>                                 string restoStr;
>                                 string numeradorParcialStr;
>                                 numeradorParcialStr = dividendoStr[0];
>                                 long restoParcial =
> strtol(numeradorParcialStr.c_str(), NULL, 0);
>

No veo que sea necesario esta conversión, porque a estas alturas
'numeradorParcialStr' contiene un solo carácter. Puedes hacer la conversión
directamente; por ejemplo,

long restoParcial = numeradorParcialStr[0] - '0';

                                int cifra;
>                                 for(cifra = 1; cifra < cifrasNumerador;
> cifra++){
>                                         restoStr =
> NumToString(restoParcial);
>                                         numeradorParcialStr =
> BajaLaCifraSiguiente(dividendoStr, restoStr, cifra);
>

Como usas 'numeradorParcialStr' para luego convertir su cadena a un entero,
¿por qué no trabajar siempre con enteros? Así te libras de hacer tantas
conversiones.

                                        long numeradorParcialLong =
> strtol(numeradorParcialStr.c_str(), NULL, 0);
>                                         restoParcial =
> Divide(numeradorParcialLong, denominador);
>                                         r =
> GetNumeroDeCifras(restoParcial);
>                                 }
>                         }
>


Espero que todo esto te oriente.

Steven
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20140925/854472d7/attachment.html>


Más información sobre la lista de distribución Cconclase