elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Introducción a Git (Primera Parte)


  Mostrar Mensajes
Páginas: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [15] 16 17 18 19 20 21 22 23 24 25 26
141  Programación / Programación C/C++ / Re: dudas con strcpy en: 15 Marzo 2014, 21:44 pm
En el caso que plantea leosansan, supongo que dependerá del compilador. Probablemente cualquier compilador moderno tomará previsiones adecuadas si la cadena de origen excede en longitud a la cadena de destino.

Sin embargo la filosofía de C es que "los programadores saben lo que están haciendo", por eso pienso que a pesar de la ayuda que pueda proporcionar el compilador, un buen programador de C debe garantizarse por sí mismo la consistencia de este tipo de operaciones. Así que al autor del post: pues, ya lo sabes!!!

Interesante un detalle adicional de la cita de cplusplus y que se me había pasado por alto: Las cadenas origen y destino no deben solaparse. Esta es otra consideración a tener en cuenta, no se debe intentar escribir una cadena sobre sí misma.

NOTA: Estas dificultades se evitan cómodamente usando la clase string de C++. Pero personalmente creo que quién se quiera formar como un verdadero programador debería pasar primero por C (con todas sus dificultades asociadas), y luego ir a C++. Hay que "ensuciarse" primero para aprender bien. Bueno, al menos es mi criterio, no se qué opinen los demás (?)
142  Programación / Programación C/C++ / Binomio de Newton, y triángulo de Pascal en: 15 Marzo 2014, 21:21 pm
Hace un tiempo un usuario me rcomendó escribir y compartir un programa que trabaje sobre el triángulo de Pascal. La verdad no es difícil generar el triángulo, así que para añadir más gusto decidí ir más allá y generar el binomio de Newton de un exponente arbitario. Pero antes de proseguir en este tema vamos a señalar algunas consideraciones teóricas (tal vez para quiénes ya olvidaron sus clases de mate, jeje).

En álgebra, al desarrollar (a+b)^2, obtenemos:

a^2 + 2ab + b^2

y para (a+b)^3:

a^3 + 3a^2b + 3ab^2 + b^3

Pues bien, lo que se quiere es el desarrollo para una potencia entera positiva cualquiera, y que lo imprima "con formato". Es decir, una línea para la base y otra para los exponentes:

 3     2       2    3
a  + 3a b + 3ab  + b


Para obtener el desarrollo general necesitamos el triángulo de Pascal (http://es.wikipedia.org/wiki/Tri%C3%A1ngulo_de_Pascal). Las tres primeras líneas del triángulo son:

  1
 1 1
1 2 1

y se construye de esta manera: todas las filas empiezan y terminan con 1, además de la tercera filas en adelante cada elemento se obtiene sumando los dos que tiene directamente arriba, uno a la derecha y otro a la izquierda. En la tercera fila, el "2" se obtuvo sumando 1 + 1 de este modo. Vamos con 4 filas:

   1
  1 1
 1 2 1
1 3 3 1

y ahora el primer "3" de la 4ta fila es la suma 1 + 2 de los elementos que tiene arriba suyo, el otro "3" es la suma 2 + 1, y así sucesivamente.

Pues bien, el j-ésimo elemento de la i-ésima fila del triángulo (empezando los índices en cero) se llama coeficiente binomial que por falta de una mejor simbología en este portal representaré como <i,j>. Con ésto, el binomio (a + b)^N se desarrolla como la suma desde i=0 hasta i=N de los términos de la forma <N,i> * a^(N-i) * b^i. O sea, por ejemplo:

(a + b)^3 = <3,0>*a^3 + <3,1>*a^2*b + <3,2>*a*b^2 + <3,3>*b^3

los coeficientes binomiales <3,j> no son más que los elementos de la cuarta fila del triángulo:

   1
  1 1
 1 2 1
1 3 3 1

por tanto

(a + b)^3 = 1*a^3 + 3*a^2*b + 3*a*b^2 + 1*b^3
          = a^3 + 3a^2b + 3ab^2 + b^3

y por supuesto, para desarrollar el binomio de orden N necesitamos construir el triángulo de N+1 filas.

Bueno, y ya  :D. La parte de hacer todos los cálculos no encierra nada que no se pueda comprender leyendo el código fuente, y sus respectivos comentarios. Lo más desafiante (para mí) fue hacer la presentación "formateada" que expliqué antes. Usando algúun tipo de función gotoxy() o su equivalente es fácil, pues nos movemos a la línea de arriba para escribir los exponentes, y a la de abajo para el resto de la expresión. Sin embargo esta función no es portable por lo que decidí no usarla.

En su lugar pensé hacer algo similar a cómo las pantallas LCD que los aparatitos electrónicos. Una matriz de celdas donde cada celda permite representar un carácter. Un programa debe calcular todas las letras y mandar a imprimirlas. Bueno, ..... creo que la idea quedó clara, se debe disponer una matriz "board" o tablero de dos filas, e ir rellenando los caracteres adecuados. Luego que se tenga toda la expresión formada, se imprimen con funciones estándares.

El problema es que se debe calcular en tiempo de ejecución el ancho total de las líneas, dependiendo de la potencia del binomio que se quiera. Tomar en cuenta también que los números ocupan un ancho fijo, porque para potencias grandes pueden ser de una, dos, tres cifras, etc. También tener presente que los coeficientes iguales a 1 no se imprimen, como tampoco los exponentes iguales a 1. Este programa, tal como está desarrollado, está limitado a expresiones cuyo ancho sea menor o igual que la pantall (no hace "salto" de línea).

Otra dificultad fue hacerlo enteramente en C (sin usar clases), por eso malloc() y free() por varias partes, jeje. El argumento (potencia del binomio) está pasado como argumento de la línea de comandos. Así que probándolo con potencia 3:

./binomio 3

nos da:

(a + b)^3 es:

 3     2       2    3
a  + 3a b + 3ab  + b

y para divertirnos un poco, con potencia 7:

(a + b)^7 es:

 7     6       5 2      4 3      3 4      2 5      6    7
a  + 7a b + 21a b  + 35a b  + 35a b  + 21a b  + 7ab  + b


Vamos con el código:
Código
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. int ** pascal( const int );
  6. int ** tartaglia( const int );
  7. void destroy_pascal( int **, const int );
  8. void destroy_tartaglia( int **, const int );
  9. int digits( int );
  10.  
  11. int main(int argc, char* argv[]) {
  12.  
  13.   int **A, N;
  14.   int i;
  15.   int width, col;
  16.   char *board[2];
  17.  
  18.   /* Verificando integridad de los datos */
  19.   if ( argc < 2 )
  20.      return -1;
  21.   N = atoi( argv[1] );
  22.  
  23.   if ( N < 0 ) {
  24.      printf("Solo para N >= 0\n");
  25.      return -1;
  26.   }
  27.   if ( N == 0 ) {
  28.      printf("a + b\n");
  29.      return -1;
  30.   }
  31.  
  32.   /* Coeficientes de pascal */
  33.   A = pascal( N );
  34.  
  35.   /* Calculamos el ancho total de la cadena */
  36.   width = 0;
  37.   for ( i = 0; i <= (float)N/2; i++ ) {
  38.      if ( i == 0 ) /* terminos a^N, y b^N */
  39.         width += 2 * ( 1 + digits(N) );
  40.      if ( i == 1 ) /* terminos a^(N-1)*b, y a*b^(N-1) */
  41.         width += 2 * ( 2 + digits(A[N][i]) + digits(N-1) );
  42.      if ( i > 1 ) /* terminos a^(N-i)*b^i */
  43.         if ( !(N % 2) && i == (float)N/2 )
  44.            /* termino central se suma solo una vez */
  45.            width += 2 + digits(A[N][i]) + digits(N-1) + digits(i);
  46.         else
  47.            /* y los restantes, dos veces */
  48.            width += 2 * ( 2 + digits(A[N][i]) + digits(N-1) + digits(i) );
  49.   }
  50.   /* cadenas " + " */
  51.   width += 3 * N;
  52.  
  53.   /* Representacion final */
  54.   if ( ( board[0] = malloc( (width + 1) * sizeof(char) ) ) == NULL )
  55.      return -1;
  56.   if ( ( board[1] = malloc( (width + 1) * sizeof(char) ) ) == NULL )
  57.      return -1;
  58.  
  59.   memset( board[0], ' ', width + 1);
  60.   memset( board[1], ' ', width + 1);
  61.   col = 0;
  62.   for ( i = 0; i <= N; i++) {
  63.      if ( A[N][i] != 1 ) { /* binomial N sobre i */
  64.         col += sprintf( board[1] + col, "%d", A[N][i] );
  65.         board[1][col] = ' ';
  66.      }
  67.      if ( N - i > 0 ) /* base 'a' */
  68.         board[1][col++] = 'a';
  69.      if ( N - i > 1 ) { /* exponente N - i */
  70.         col += sprintf( board[0] + col, "%d", N - i);
  71.         board[0][col] = ' ';
  72.      }
  73.      if ( i > 0 ) /* base 'b' */
  74.         board[1][col++] = 'b';
  75.      if ( i > 1 ) { /* exponente i */
  76.         col += sprintf( board[0] + col, "%d", i);
  77.         board[0][col] = ' ';
  78.      }
  79.      if ( i < N ) {
  80.         col += sprintf( board[1] + col, " + ");
  81.         board[1][col] = ' ';
  82.      }
  83.   }
  84.   board[0][width] = '\0';
  85.   board[1][width] = '\0';
  86.   printf( "(a + b)^%d es:\n\n%s\n%s\n", N, board[0], board[1] );
  87.  
  88.   /* Liberando memoria, y saliendo */
  89.   free( board[0] );
  90.   free( board[1] );
  91.   destroy_pascal( A, N);
  92.   return 0;
  93. }
  94.  
  95. /* Construye una matriz que contiene los numeros del triangulo
  96.  * de Pascal o Tartaglia de orden N > = 0, con N + 1 filas.
  97.  * La matriz es tal que A[i][j] corresponde al binomial (i : j).
  98.  * Se devolverá NULL si N < 0, o si no se pudo asignar memoria
  99.  * para construir la matriz.
  100.  */
  101. int ** pascal( const int N ) {
  102.  
  103.   int **A;
  104.   int i, j;
  105.  
  106.   if ( N < 0 ) return NULL;
  107.  
  108.   if ( ( A = malloc( (N + 1) * sizeof(int *) ) ) == NULL ) return NULL;
  109.   for ( i = 0; i < N + 1; i++ )
  110.      if ( ( A[i] = malloc( (i + 1) * sizeof(int) ) ) == NULL ) return NULL;
  111.  
  112.   for ( i = 0; i < N + 1; i++ ) {
  113.      A[i][0] = 1;
  114.      A[i][i] = 1;
  115.      /* solo se ejecuta si i > 1 */
  116.      for ( j = 1; j < i; j++ )
  117.         A[i][j] = A[i-1][j-1] + A[i-1][j];
  118.   }
  119.  
  120.   return A;
  121. }
  122.  
  123. /* Destruye el objeto creado por la función pascal() */
  124. void destroy_pascal( int ** A, const int N ) {
  125.  
  126.   int i;
  127.  
  128.   if ( N < 0 ) return;
  129.  
  130.   for ( i = N; i >= 0; i-- ) {
  131.      free( A[i] );
  132.      A[i] = NULL;
  133.   }
  134.   free( A );
  135.   A = NULL;
  136. }
  137.  
  138. /* Un sinónimo de pascal( N ) */
  139. int ** tartaglia( const int N ) {
  140.  
  141.   return pascal( N );
  142. }
  143.  
  144. /* Un sinónimo de destroy_pascal( N ) */
  145. void destroy_tartaglia( int ** A, const int N ) {
  146.  
  147.   return destroy_pascal( A, N );
  148. }
  149.  
  150. /* Calcula la cantidad de cifras o digitos que conforman un
  151.  * numero entero no negativo;
  152.  */
  153. int digits( int N ) {
  154.  
  155.   int count = 1;
  156.  
  157.   if ( N < 0 ) return 0;
  158.   if ( N == 0 ) return 1;
  159.  
  160.   while ( ( N = (N / 10) ) > 0 )
  161.      count++;
  162.  
  163.   return count;
  164. }
143  Programación / Programación C/C++ / Re: dudas con strcpy en: 15 Marzo 2014, 20:32 pm
Ok, hay varios aspectos implícitos en tu pregunta. La función

strcpy( char *s1, const char *s2)

copia el contenido de s2 en s1, añadiendo al final de s1 un carácter nulo de terminación '\0'. La única consideración es que s1 contenga el suficiente espacio disponible para copiar todos los caracteres (al menos la longitud de s2 más uno).

Esto por supuesto requiere que se pueda escribir en el espacio asignado a s1. Si declaras

char *cadena = "hola mundo";

entonces cadena se considerará un string constante y ya no podrás escribir nada nuevo en él. Pero la declaración:

char cadena[] = "hola mundo";

sí permite rescribir el contenido de cadena (siempre y cuando la nueva cadena sea de longitud menor o igual a la que tenías primero, de lo contrario no habrá espacio disponible suficiente). Por ejemplo, puedes poner:

strcpy( cadena, "Pepe");
puts( cadena );

y verás como ahora escribe "Pepe".

----------------------------------------------------------------------------------
NOTA. En cuánto a la declaración de string constantes no se con exactitud si la forma de interpretar la sentencia depende del compilador o de la versión de C, o de si es en C ó en C++. Que alguno de los usuarios más versados en el tema por favor nos complemente.
144  Programación / Programación C/C++ / Re: Problema extraño en: 13 Marzo 2014, 19:19 pm
Sólo digo que me parece bien raro ese lenguaje. ¿Quién lo usa? ¿Es algo parecido a los sms?
145  Programación / Programación C/C++ / Re: Leer datos de un cierto formato desde un fichero en: 13 Marzo 2014, 18:58 pm
Aunque ya está solucionado, sólo para mostrar una alternativa un poco bizarra pero que se reduce a un único sscanf(). La idea es leer ambos, el entero y el float como flotantes, y de ser necesario convertir el primero a entero. Lo probé y parece funcionar correctamente:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(void)
  5. {
  6.   char *linea[] = {
  7.      "1970-01-01 1 2.3",
  8.      "1970-01-01 4.5",
  9.      "1980-01-01 1 2.3",
  10.      "1980-01-01 4.5",
  11.      "1990-01-01 1 2.3",
  12.      "1990-01-01 4.5",
  13.   };
  14.   size_t num_elem = sizeof linea / sizeof linea[0];
  15.   size_t i;
  16.  
  17.   unsigned a;
  18.   unsigned m;
  19.   unsigned d;
  20.   int num_ent;
  21.   double num_pf;
  22.  
  23.   int n_args;
  24.   float M, N;
  25.  
  26.   for (i = 0; i < num_elem; i++)
  27.      switch ( n_args = sscanf(linea[i], "%u-%u-%u %f%*[ ]%f", &a, &m, &d, &M, &N) ) {
  28.      case 5:
  29.         num_ent = (int)M;
  30.         num_pf = N;
  31.         printf("%u-%02u-%02u: %d, %.2f\n", a, m, d, num_ent, num_pf);
  32.         break;
  33.      case 4:
  34.         num_pf = M;
  35.         printf("%u-%02u-%02u: %.2f\n", a, m, d, num_pf);
  36.         break;
  37.      default:
  38.         puts("Error");
  39.      }
  40.  
  41.   return EXIT_SUCCESS;
  42. }
  43.  

Salida:

1970-01-01: 1, 2.30
1970-01-01: 4.50
1980-01-01: 1, 2.30
1980-01-01: 4.50
1990-01-01: 1, 2.30
1990-01-01: 4.50
146  Programación / Programación C/C++ / Re: Problema con un programa en C (string.h y funciones) en: 13 Marzo 2014, 18:12 pm
Ah bueno leosansan tienes razón, ya eso depende de la interpretación que demos de palíndromo, si bien la definición formal RAE (que es la oficial de nuestro idioma), o bien una definición más relajada.

A veces en determinada ciencia tomamos definiciones más amplias (o más estrictas) que las lingüísticas, y podría ser ese el caso de la informática. Está bien tu aporte y el de todos, porque así contamos con un abanico de soluciones, adaptadas a las distintas interpretaciones del problema.

Un buen proyecto sería construir una función "múltiple", con un argumento option adicional que especifique el tipo de interpretación que será hecho (omitiendo o no los espacios, diferenciando mayúsculas, etc). Así sería más flexible, amplio y práctico  :D.
147  Programación / Programación C/C++ / Re: copiar una palabra de un archivo en C en: 13 Marzo 2014, 18:02 pm
Ah ok, no problem!  ;D
148  Programación / Programación C/C++ / Re: problemas con long long int en: 13 Marzo 2014, 17:59 pm
También me pareción extraño que no eligió fprintf(). Creo que no se puede usar porque el problema dice "no se pueden usar cadenas", y como fprintf() dirige una salida formateada, de cierta forma está creando una cadena. Está obligado a trabajar "en bruto", o al menos eso es lo que pareciera.

De todos modos, que el autor del post aclare ...
149  Programación / Programación C/C++ / Re: problemas con long long int en: 13 Marzo 2014, 02:01 am
Lo que dijo englex, y además, ¿por qué escribes 12 bytes con el fread()? Si vas a escribir un dígito a la vez, basta con poner un solo carácter. Quedaría:
Código
  1. void escribirNumero(long long int numero, FILE *fd)
  2. {
  3. long long int cociente,residuo;
  4. for(cociente = numero; cociente != 0; cociente = cociente/10)
  5. {
  6.  residuo = cociente % 10;
  7.  residuo += 48; /* convertido a ASCII */
  8.  fwrite( &residuo, sizeof(char), 1, fd);
  9. }
  10. }
Eso sí, va escribiendo el número empezando con la cifra menos significativa, y terminando por la más significativa. Por ejemplo para el número 54.780 lo probé y me escribe 08745 lo cual está bien pero al revés. Tendrías que hacer una rutina para invertir las cifras.

150  Programación / Programación C/C++ / Re: Problema con un programa en C (string.h y funciones) en: 13 Marzo 2014, 01:39 am
Si la intención es procesar la primera mitad de un array incluyendo el elemento pivote (si existe) me parece mas sencillo utilizar la expresión "i < (N + 1) / 2" para controlar el bucle.

Es otra manera, gracias.

Para do-while, la solución que presenté considera que la palabra no contiene espacios, y fue así para mantenerme fiel al enfoque dado inicialmente al tema por parte de su autor. Luego él mencionó el problema de los espacios, y creo que después presentó en un programa capaz de manejar ese problema.

Leosansan ya va tranquilo, calma. Por supuesto que el elemento central de una sucesión de cinco elementos no es el 2.5, sino el 2 (o sea, de índice 2). Se trataba de una condición que pudiera discernir los valores correctos de i a tomar. Al redondear a enteros, la condición i < 2.5 se reduce a i = 0, 1, 2, como queríamos.

O más precisamente, tal como rir3760 y tú dicen la condición i< N/2 es la apropiada si para el caso impar no se toma el elemento central (el caso nuestro), y la condición i < (float)N / 2, o bien i < (N+1)/2 si el elemento central fuera tomado (que no es nuestro caso).

Pero yo tuve un lapsus y por alguna razón incluí el elemento central o pivote, de donde surgió toda la discusión. Conste que incluir este pivote no afecta el resultado del programa, por cuánto estaría comparando dicho elemento consigo mismo y a lo peor incurre en una pequeña falta de eficiencia.
Páginas: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [15] 16 17 18 19 20 21 22 23 24 25 26
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines