Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - eferion

#471
Si lees las normas del foro... una de ellas dice: "No se hacen tareas".

Empieza a traducirlo tú y cuando te atasques avísanos.
#472
Citar
1.-porque se dice que las intrucciones como break (exepto de switch), continue, y goto hacen que un programa en c que debe ser programacion estructurada  deje de serlo al usar estas instrucciones.

Cuando tu escribes un programa en C, sin usar las instrucciones que comentas, se cumplen que las instrucciones se ejecutan siempre en el mismo orden que se encuentran escritas. La única excepción son los condicionales, pero dado que éstos son imprescindibles en el código, se asumen como algo normal.

Las instrucciones "break", "continue" y "goto" introducen saltos en el código, al igual que hacen las llamadas a funciones. Sin embargo hay una sutil diferencia. Cuando tu haces una llamada a una función y el código "sale" de la función, vuelve automáticamente a la instrucción siguiente a la que causaba la llamada:


void main( )
{
  int i=0;
  func( ); // llamada a funcion

  // al salir de "func", el codigo ejecutara esta instruccion
  // independientemente del contenido de "func"
  i++;
}


Sin embargo, las instrucciones que comentan rompen este diseño, ya que permiten que la ejecución sea, digamos, aleatoria. El más radical, como veremos, es goto, los otros dos son más "seguros".

goto

"goto" es la opción más radical de las disponibles. Permite saltar entre instrucciones sin restricciones.


int main( )
{
int main( )
{
  goto a;

d: putchar( 'a' ); goto e;
a: putchar( 'h' ); goto b;
h: putchar( 'n' ); goto i;
c: putchar( 'l' ); goto d;
e: putchar( ' ' ); goto f;
f: putchar( 'm' ); goto g;
b: putchar( 'o' ); goto c;
i: putchar( 'd' ); goto j;
g: putchar( 'u' ); goto h;
j: putchar( 'o' );
}


El programa anterior imprime "hola mundo", pero claro, como puedes ver, el código desde luego no se ejecuta, ni de lejos, en el mismo orden en el que se ha escrito.

break

"break" es menos agresivo que goto, ya que, si lo usamos, lo que vamos a conseguir es salir del bucle que se esté ejecutando.  Si hay varios bucles anidados, se saldrá únicamente del bucle más cercano.

Es una especie de "goto", solo que la elección del salto no es libre, después del "break" se ejecutará siempre la primera instrucción que esté fuera del bucle.


int main( )
{
  int i=0;
  while ( 1 ) // Este bucle no deberia terminar nunca
  {
    if ( i == 5 )
      break;

    // mas codigo

    i++;
  }

  printf( "Fin" );
}


En el ejemplo, el bucle "while" debería ejecutarse hasta el fin de los tiempos... sin embargo, al introducir el "break" conseguimos escapar del bucle. Como puedes ver, la instrucción "break" puede encontrarse en cualquier parte del bucle ( incluso dentro de condicionales, que suele ser lo habitual ). Este mismo comportamiento se puede reproducir con "goto":


int main( )
{
  int i=0;
  while ( 1 ) // Este bucle no deberia terminar nunca
  {
    if ( i == 5 )
      goto fin;

    // mas codigo

    i++;
  }

fin:  printf( "Fin" );
}


Lo ideal bastantes casos es poner la condición en el while y olvidarnos del break:


int main( )
{
  int i=0;
  while ( i != 5 )
  {
    // mas codigo

    i++;
  }

  printf( "Fin" );
}


Como comentaste antes, "break" tiene un trato de favor cuando se usa con "switch", la razón es que "switch" es un condicional, y aquí el uso de break sería equivalente a sustituir "switch" por "if".


int main( )
{
  int valor = func( );

  // switch ( es equivalente a la secuencia de ifs siguiente
  switch ( valor )
  {
    case 0:
      printf( "cero\n" );
      break;
    case 1:
      printf( "uno\n" );
      break;
    case 2:
      printf( "dos\n" );
      break;
  }

  if ( valor == 0 )
    printf( "cero\n" );
  else if ( valor == 1 )
    printf( "uno\n" );
  else if ( valor == 2 ) 
    printf( "dos\n" );
}


continue

"continue", a diferencia de "break", no sale del bucle. "continue" realiza un salto al inicio del bucle.

En este caso, podemos evitar el uso de "continue" introduciendo condicionales... aunque a veces por claridad es mejor poner un "continue".

Citar2- En que casos o usos de funciones como las anteriores o librerias al usarlas nuestro programa dejaria de ser estructurado.

Es indiferente, si las usas, el programa pierde su condición de estructurado. Aún así no te asustes, son sentencias totalmente válidas y conforme al estándar.

Mi consejo es usarlas si con ello se mejora la legibilidad del programa... en caso contrario es mejor evitarlas.

Citar3- En este ejemplo que se hace cuando se programa sockets:
Código
server.sin_addr = *((struct in_addr *)he->h_addr);

se utiliza para pasar los valores de he a h_addr pero es estado viendo alguno codigo donde usan puntero o vectores  y usan igual esto " -> ", lo que quisiera saber es si es el unico uso que se le da para trasferir datos y en que casos se puede usar y como se usa en realidad no se si me puedan ayudar con un ejemplo.

Esto son dos preguntas en una.

1. El uso del operador "->" está vinculado, en lenguaje "C", al uso de estructuras. Cuando quieres acceder a algún valor almacenado en una estructura tienes que usar el operador "." ( si la estructura la estás usando por valor ), o el operador "->" (si accedes a la estructura a través de un puntero). Y esto es así independientemente de la forma y tamaño de la estructura. Lo único que define la forma de acceder es la existencia o no de punteros.

2. A estas alturas sabrás que si intentas copiar, "a pelo" una cadena de caracteres en otra, el resultado no suele ser el esperado:


int main( )
{
  char* cad1 = "Mensaje";
  char* cad2 = "Otro mensaje";

  cad2 = cad1;

  printf ("%d %d", cad1, cad2 );
}


El programa hace una "copia" entre cadenas de caracteres e imprime la posición de memoria a la que apunta cada puntero después de la asignación. ¿Resultado? No se ha copiado la cadena... los dos punteros apuntan a la misma cadena (las posiciones de memoria que se imprimen son iguales).

Sin embargo, si se puede copiar una estructura en otra con una simple asignación:


typedef struct
{
  int numero1;
  int numero2;
} objeto;

int main( )
{
  objeto obj1, obj2;

  obj1.numero1 = 20;
  obj1.numero2 = 45;

  obj2 = obj1;

  printf ( "%d %d", obj2.numero1, obj2.numero2 );
}


Esto mismo es lo que está haciendo en la línea que has puesto de ejemplo. La explicación es la siguiente: "h_addr" es un puntero a una estructura, el asterisco que está justo después del '=' hace que para la asignación se use la estructura por valor, en vez de por puntero. El resultado es que se copia el contenido de "h_addr" en "server.sin_addr".

Citar4-Tambien queria ver si me podrian decir  si en c existe alguna alternativa a try-catch ya que esta solo encuentro informacion para c++ y al compilar me dice que esta indefido try.

Las excepciones son un mecanismo existente en C++, no en C. Su utilidad es aportar más flexibilidad al tratamiento de errores. Fijate que digo "aportar más flexibilidad" y no "permitir el", es decir, se puedes escribir un programa en C++ sin necesidad de usar excepciones.

La ventaja que tienen las excepciones es que puedes almacenar una gran cantidad de información valiosa sobre el error que se ha producido y tratarla en una parte del código de más alto nivel, incluso centralizada.

Si bien un buen uso de las excepciones aporta muchísimas ventajas, su uso no es obligatorio. E incluso un mal uso es perjudicial.

Un ejemplo de un mal uso:

Código (cpp) [Seleccionar]

void sumar( int a, int b )
{
  throw a + b;
}

int main( )
{
  try
  {
    sumar( 4, 6 );
  }
  catch ( const int& resultado )
  {
    std::cout << resultado;
  }
}


El tema de las excepciones es polémico, hay gente que está a favor, otros están en contra... cada uno que elija su propio criterio.

En C, al no existir excepciones, tienes que hacer las comprobaciones a mano para evitar errores:


int dividir( int dividendo, int divisor )
{
  if ( divisor == 0 )
  {
    // Tratamiento del error
  }
  else
    return dividendo / divisor;
}
#473
Cita de: #Aitor en  7 Mayo 2014, 14:07 PM
En principio no entiendo esta linea.

Código (c++) [Seleccionar]
int max = ( argc > MAXSTRINGS ) ? MAXSTRINGS : argc - 1;

Puesto de otra forma:


int max;
if ( argc > MAXSTRINGS )
  max = MAXSTRINGS;
else
  max = argc - 1;


Cita de: #Aitor en  7 Mayo 2014, 14:07 PM
Y luego no termino de entender, por qué el programa no explota si la idea de

Código (c++) [Seleccionar]
const int MAXSTRINGS = 100;
string frase[ MAXSTRINGS ];


Es la misma idea qué:
Código (c++) [Seleccionar]
string frase[100];

Efectivamente es lo mismo. La ventaja que tiene mi código es que puedes cambiar el 100 por cualquier otro valor sin necesidad de navegar por el código (imagínate que tienes que cambiar el 100 en 30 sitios diferentes... con mi código solo tendrías que cambiarlo en un solo sitio)

El motivo por el que ya no explota no está ahí, sino en el bucle:

for(int it = 0; it < max; it++)

En tu versión, estás asumiendo que "max" es siempre 100 y eso es incorrecto... si solo pasas 3 palabras, "max" deberá valer 3, no 100
#474
Tranquilo, uno no nace sabiendo y es necesario darse unos cuantos golpes para aprender.

Buena suerte.
#475

void insertarPaisesG(int ID, char Nombre[]){
Paises * nuevo;
nuevo = (Paises *)malloc(sizeof(Paises));

nuevo->IDpais=ID;
strcpy(nuevo->Pais, Nombre);


if(PAIprimero->p!=PAIultimo){


Si acabas de arrancar el programa, asumo que no hay elementos en la lista, luego PAIprimero debería ser null... si esto es así, lo mejor que te puede pasar al hacer "PAIprimero->p" es que el programa se rompa.

Luego otro detalle:

fwrite(recorre, sizeof(Paises), 1, archivo);

Eres consciente de que ahí estás guardando el puntero al siguiente elemento... puntero que al cargar ya no será válido puesto que los elementos cargados se pondrán en posiciones diferentes de la memoria.

Para evitar este "acoplamiento" podrías adaptar un poco "struct paises" para poder separar la chicha de la lista enlazada:


typedef struct pais
{
int ID;
char Nombre[20];
int NoParticipantes;
int NoMedallas;
} Pais;

typedef struct nodo
{
  Pais pais;
  struct nodo* p;
} Nodo;


de esta forma, para componer la lista creas elementos de tipo "Nodo" y para guardar accedes únicamente al elemento nodo.pais:


void insertarPaisesG(int ID, char Nombre[]){
Nodo* nuevo;

        // Mejor calloc que malloc... calloc reinicia la memoria
        // asi los campos "NoParticipantes" y "NoMedallas" empezaran con valor 0 automaticamente.
nuevo = (Nodo*)calloc(1, sizeof(Nodo));

nuevo->pais.ID=ID;
strcpy(nuevo->pais.Nombre, Nombre);

// ...
}

void guardarPaises(){
printf("\n\n\nGuardando informaci�n de paises");
FILE * archivo = fopen("Paises.dat", "wb");
if(archivo == NULL){
printf("\n\n\nError al guardar en archivo");
return;
}

Nodo* recorre = PAIprimero;
while (recorre != NULL){
fwrite(&(recorre->pais), sizeof(Pais), 1, archivo); // Solo guardamos la "chicha"
recorre = recorre->p;
}

fclose(archivo);
}

void cargarPaises(){
FILE * archivo = fopen("Paises.dat", "rb");
if(archivo == NULL){
printf("\n\n\nError al cargar desde archivo");
return;
}

Pais pais; // No tiene sentido que uses malloc aqui... ademas se te olvido el free correspondiente
int leidos;
do{
leidos = fread(&(pais), sizeof(Pais), 1, archivo);
if (leidos == 1)
insertarPaisesG(pais.ID, pais.Nombre);
} while (leidos == 1);

fclose(archivo);
}
#476
No he terminado de comprender el motivo por el cual usas la cabecera de entrada salida de C++ y luego usas las funciones de C en vez de cin y cout.

Código (cpp) [Seleccionar]
for(int it = 0; it < 100; it++) {

Estás presuponiendo que te van a pasar 100 palabras... y eso no tiene que ser cierto... el número viene dado por argc, no puedes pasar de esa cantidad.

Es decir, lo que viene siendo...

Código (cpp) [Seleccionar]

#include <iostream>
#include <string>

using namespace std;

const int MAXSTRINGS = 100;

char transformar_caracter(char letra)
{
 if ( letra%2 )
   letra--;
 else
   letra++;

 return letra;
}

int main(int argc, char **argv )
{
 if(argc < 2)
   return 0;

 string frase[ MAXSTRINGS ];

 int max = ( argc > MAXSTRINGS ) ? MAXSTRINGS : argc - 1;
 for(int it = 0; it < max; it++)
 {
   frase[it] = argv[ it + 1];

   int tam = frase[it].size();

   for(int i=0; i<tam; i++)
     cout << transformar_caracter(frase[it][i]);
   cout << "\t"; // Lo he puesto para separar cada palabra
 }

 cout << endl;
 return 0;
}


el array "frase" lo he mantenido porque imagino que tu idea es usarlo en cambios futuros... ahora mismo no sería necesario. Yo personalmente hubiese usado un contenedor en vez de un array "crudo", pero así también funciona.
#477
Código (cpp) [Seleccionar]

int x;
int y;

// ...

int main(){
// ...
while(!mala_opcion){
cin >> eleccion;
switch(eleccion){
case 1:
int x;
int y;


si te fijas tienes x e y declaradas dos veces... la primera declaración se corresponde con variables globales ( mejor no usarlas... uno de los motivos es el que hace que tu programa falle ). Debido a que dentro de main has declarado dos variables iguales, las que se van a usar en esa sección del código son las locales... las globales ni se enteran.

por otro lado:

Código (cpp) [Seleccionar]

cout << "\n\n  Introduzca el valor 'x': " << endl;
cin >> x;
cout << "\n\n  Introduzca el valor 'y': " << endl;
cin >> y;
sumar(x, y);

// ...

void sumar(int, int){
cout << "\n\nResultado de la Suma:  " << x + y << endl;
}


la función "sumar" recibe dos argumentos pero no los usa absolutamente para nada... está tirando de las variables globales... que como hemos comentado hace un momento no se han enterado de las asignaciones.

Y para terminar...

Código (cpp) [Seleccionar]

double dividir(int, int){
cout << "\n\nResultado de la Division:  " << x / y << endl;
}


"dividir" debería retornar un double... pero no hay return. Además, la división entre dos enteros va a ser otro entero... sin decimales.

Esto tiene varias soluciones diferentes, yo te propongo la más limpia.

Los pasos a seguir son los siguientes:

1. Elimina las variables globales (todas)
2. Pon nombre a los argumentos de las funciones y usa esas variables dentro de cada función
3. No uses conio.h
4. Para no perder los decimales, hacemos un cast a double en el caso de "dividir"
5. Modificamos "dividir" para que no retorne un double ( no es necesario )
6. "\n" y "endl", ambas introducen un salto de linea... no hace falta combinarlas

Y este es el resultado:

Código (cpp) [Seleccionar]

#include <iostream>

using namespace std;

void sumar(int, int);
void restar(int, int);
void multiplicar(int, int);
void dividir(int, int);

int main()
{
  cout << "------C A L C U L A D O R A------" << endl;
  cout << "Escoja escribiendo el numero, el tipo de calculo que desea realizar:" << endl;
  cout << " 1) Sumar          2) Restar" << endl << " 3) Multiplicar    4) Dividir" << endl;

  bool repetir = false; // esta se corresponde con mala_opcion, el nombre y su uso no son para nada claros

  do // no tiene sentido comprobar "repetir" en la primera iteracion
  {
    int eleccion;
    cin >> eleccion;
    switch(eleccion)
    {
      case 1:
        int x, y;
        cout << endl << "Introduzca el valor 'x': " << endl;
cin >> x;
cout << "Introduzca el valor 'y': " << endl;
cin >> y;
sumar(x, y);
break;

      case 2:
        int x, y;
        cout << endl << "Introduzca el valor 'x': " << endl;
        cin >> x;
        cout << "Introduzca el valor 'y': " << endl;
        cin >> y;
        restar(x, y);
        break;

      case 3:
        int x, y;
        cout << endl << "Introduzca el valor 'x': " << endl;
        cin >> x;
        cout << "Introduzca el valor 'y': " << endl;
        cin >> y;
        multiplicar(x, y);
        break;

      case 4:
        int x, y;
        cout << endl << "Introduzca el valor 'x': " << endl;
        cin >> x;
        cout << "Introduzca el valor 'y': " << endl;
        cin >> y;
        dividir(x, y);
break;

      default:
        cout << endl << "Has introducido un comando incorrecto, vuelva a repetir." << endl;
        repetir = true;
        break;
    }
  }

  cin.get();
  return 0;
}

void sumar(int x, int y)
{
cout << endl <<  "Resultado de la Suma:  " << x + y << endl;
}

void restar(int x , int y){
cout << endl << "Resultado de la Resta:  " << x - y << endl;
}

void multiplicar(int x, int y){
cout << endl << "Resultado de la Multiplicacion:  " << x * y << endl;
}

void dividir(int x, int y){
  // Hay dos formas de hacer cast... estilo C y estilo C++:
  double dividendo, divisor;

  // Estilo C
  // Es mas inseguro y es mejor evitarlo... pero al principio es mas sencillo de usar
  dividendo = (double)x;
  divisor = (double)y;

  // Estilo C++
  // La opcion recomendada, aunque conviene revisar los diferentes tipos de casting que hay
  dividendo = static_cast< double >( x );
  divisor = static_cast< double >( y );

  cout << endl << "Resultado de la Division:  " << dividendo / divisor << endl;
}
#478
int ntriangulos;
// ...
ntriangulos=1.0;


Es una pijotada, pero si la variable es de tipo entero... no le pases floats... y qué pasa si te da por poner 1.5?? funcionará como te esperas?? seguramente no.

m=ntriangulos;
//...
p=ntriangulos;


Esto para que?? si el valor de "p" no cambia después... usa ntriangulos directamente... tener variables duplicadas no tiene sentido y, como norma general, dificulta la legibilidad del código.

Es más, si te das cuenta, m y n tienen el mismo valor en cada iteración del bucle, luego "triangulo[m].loquesea" se pierde cuando llegas a "triangulo[p].loquesea".


do{

    for(n=ntriangulos-1; n>=0&&ntriangulos<NTRIANGULOS; n--)
    {
        // ....
        ntriangulos++;
    }

} while(ntriangulos<NTRIANGULOS);


¿Ese "ntriangulos" debería estar ahi?? si es así, sería más lógico ponerlo al lado de "n--" para que quede más claro el código.

Es más, si tenemos en cuenta que...


    ntriangulos=1.0;

do{

    for(n=ntriangulos-1; n>=0&&ntriangulos<NTRIANGULOS; n--)


entonces, el bucle for solo se ejecuta una vez... qué sentido tiene eso?

Tu código es bastante confuso y trabado... ah si, y también te recomiendo empezar a practicar con el depurador de código.
#479
Perdón.

vale, cierto, tu quieres sacar un solo carácter... para eso tienes que usar putchar( nombres[ 0 ][ 0 ] )

puts es para cadenas de texto... es decir, puts( nombres[ 0 ] )
#480
puts( nombres[0][0] ) debería funcionarte