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

 

 


Tema destacado: Estamos en la red social de Mastodon


  Mostrar Mensajes
Páginas: 1 ... 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [23] 24 25 26
221  Programación / Programación C/C++ / Re: es posible concatenar un array byte? en: 8 Febrero 2014, 15:57 pm
;-) ;-) ;-) ;-) ;-)

Me encantan las soluciones simples y de pura lógica.

Me duele que no se me haya ocurrido antes. :rolleyes:

Enhorabuena amigo yoel_alejandro


Gracias amigo leosasan!!!! Lo que pasa es que también soy aficionado a las matemáticas, y suelo enfocar estos problemillas aritméticos por su base teórico-algebraica, jeje
222  Programación / Programación C/C++ / Re: Programa que identifique que tipo de dato se introduce C++ en: 8 Febrero 2014, 15:30 pm
Leosasan, estas discusiones sobre el comportamiento del compilador ante ciertas situaciones irregulares en los programas son sumamente enriquecedoras tanto para nosotros como para los usuarios menos experimentados de la comunidad  :)

Respecto a que no crees que el compilador informe un error siempre que encuentre una referencia a una variable que no se ha definido con anterioridad, ..... bueno dependerá del tipo de compilador, y lo estricto que éste sea.

Yo uso gcc de GNU para Linux y siempre me informa esta situación y lo cataloga como error (no Warning). Ello significa que el proceso de compilación se detiene y no genera un ejecutable. Por ejemplo, quise poner la sentencia de asignación x = 1 sin antes haber declarado la x y aquí el mensaje obtenido:

Código:
test1.c: In function ‘main’:
test1.c:18: error: ‘x’ undeclared (first use in this function)
test1.c:18: error: (Each undeclared identifier is reported only once
test1.c:18: error: for each function it appears in.)

Ni siquiera (considerando que C99 define "int por defecto") se le ocurrió tomar la variable x como int y seguir con la compilación. Claro, esto quizá dependerá del tipo de compilador, a lo mejor algunos son más flexibles, o pueden ser configurados sobre cómo responder en situaciones como ésta.

En todo caso, creo que un compilador estricto es mejor (el de GNU lo es), porque te enseña desde el principio a programar como es debido, y ceñirte mejor a la norma ISO/IEC 9899:1999, mejor llamada ANSI C99 !!!

============================
Por otra parte, respecto a lo de convertir "1.23" en 1, y "12as" como 12, a eso precisamente me refiero con "las reglas de conversión implícita de tipo de C". Ya que es un lenguaje tipado, él posee protolocos internos que le dicen cómo convertir un valor dado a otro tipo esperado.

Ahora, SUPONEMOS que cadenas como "12as" se convertirán a 12, pero en general de la forma exacta de conversión yo no estoy seguro, pero eso debe estar claramente definido en la norma ANSI C99. Por algo C es un lenguaje que ha sido absolutamente normado, y al tener una duda sólo hay que consultar lo que dice la norma al respecto.

Yo no he investigado profundamente la conversión a entero de cadenas que incluyen caracteres no numéricos, preferiría validar el dato por mí mismo, tal como lo propone leosasan en su código.

Al usuario que inició este post le recuerdo que C tiene normas internas de conversión de tipo, y serán SÓLO esas, las que especifica el estándar oficial, y no las que tú creas, o las que crea el usuario. En tales situaciones "anómalas", nada te garantiza que el comportamiento de la función scanf será como tú supones que será. Pero como programador debes mantener tu programa siempre "bajo control", por eso debes confeccionar una rutina de validación de los datos que introduce el usuario según tus propias normas y preferencias. Eso te recomiendo  :) :)

======================
Continuando el tema, y para que minari02 te acostumbres a la buen práctica de validar los datos de entrada (nunca confíes en el buen juicio del usuario de tu programa) he aquí una humilde contribución que preparé hace tiempo. Esta función isnumeric recibe una cadena y devuelve True si corresponde a un número válido, y False si no. Admite los caracteres 0-9, además de +-., y el espacio. Los espacios al inicio y al final de la cadena serán despreciados, y además filtra la cadena de una forma más sofisticada que sólo ver si está compuesta de caracteres permitidos. Por ejemplo, permite el '+' o el '-', pero sólo uno de ellos, y antecediendo a cualquier carácter numérico. O sea, que por ejemplo rechazará expresiones como "++354", ó "3-456". El signo decimal '.' sólo podrá aparecer una vez.

Aquí el código, para que lo incluyas en tu programa. Se aceptan con agrado sugerencias y mejoras  ;-)

Código
  1. /* No cero si la cadena apuntada por s representa un número real decimal.
  2. La cadena deberá contener sólo los caracteres "+-0123456789. ".
  3.  
  4. - El carácter de punto decimal es el punto '.', es opcional y sólo puede aparecer
  5.  una vez en la cadena.
  6. - El carácter de signo '+' o '-' es opcional, sólo puede aparecer una vez y como
  7.  primer carácter no blanco de la cadena.
  8. - Se admiten secuencias de espacios ' ' al principio o al final de la cadena, pero
  9.  son ignoradas. No se admiten espacios en el medio de la cadena.
  10.  
  11. Esta definición es acorde con la configuración regional estándar en Español, pero
  12. pudiera adaptarse para la configuración en Inglés (la coma ',' antes que el punto '.').
  13.  
  14. No admitimos en esta implementación representaciones en punto flotante con mantisa y
  15. exponente, sólo mantisa.
  16. */
  17. int isnumeric(const char *s) {
  18.  
  19. const char *allowed_chars = "0123456789."; /* caracteres permitidos */
  20. char c;
  21. int i, j, N;
  22. bool exists_point = false, exists_sign = false;
  23. bool pre_space = false, post_space = false;
  24.  
  25. N = strlen(allow_chars);
  26. for (i = 0; i < INT_MAX && s[i]!='\0'; i++) {
  27. c = s[i];
  28.  
  29. // sólo se admite un carácter opcional '+' ó '-' y como primer
  30. // no blanco de la cadena
  31. if (c == '+' || c == '-') {
  32. if (exists_sign == true)
  33. return 0;
  34. else {
  35. exists_sign = 1;
  36. if (i>0)
  37. if (s[i-1] != ' ') return 0;
  38. }
  39. continue;
  40. }
  41.  
  42. if (c == ' ') {
  43. if (pre_space == false) pre_space = 1;
  44. if (i > 0 && s[i-1] != ' ') post_space = 1;
  45. continue;
  46. }
  47. if (post_space == true && c != ' ') return 0;
  48.  
  49. // buscando caracteres permitidos
  50. for (j=0; j<N; j++)
  51. if (c == allowed_chars[j]) break;
  52. if (j == N) return 0;
  53.  
  54. // no puede haber más de un carácter '.'
  55. if (c == '.') {
  56. if (exists_point == 1)
  57. return 0;
  58. else
  59. exists_point = 1;
  60. }
  61. }
  62.  
  63. // si no detecta error, sale con valor 1
  64. return 1;
  65. }
223  Programación / Programación C/C++ / Re: problemas con fseeks en: 8 Febrero 2014, 14:59 pm
rir3760, gracias por la explicación. Se me ocurre también otra forma en que la verificación manual sería necesaria (aparte de si el fichero se abre en binario), si por ejemplo el usuario que creó el txt dejó dos saltos de línea sucesivos (o sea, con una línea en blanco), entonces el programa lee '\n' y se detiene. La otra línea será sólo '\n' por lo que devolverá búfer vacío.

Si verificamos con CR-LF no pasa esto porque al encontrar la secuencia CR+LF+CR+LF él recorrerá hasta el último LF antes de salir.

Claro, otra forma de hacerlo sería incorporar la instrucción *buffer = '\0'; al inicio de la función readLine, de modo esté programado para devuelver un búfer vacío por defecto. Entonces, si devuelve vacío sabemos que había una línea en blanco (o saltos de línea repetidos), e invocamos otra vez a readLine

No se ..... tengo la sensación de que preguntar por '\n' y que fgetc se encargue de la conversión en cada tipo de sistema hará el programa más portable, pero por otra parte decodificar a mano hará el programa más seguro ...

¿Qué tal si alguien llenó el txt manualmente y puso una secuencia extraña tal como CR + LF + CR (o sea, una cantidad impar, ni dos ni cuatro)? ¿Qué me garantiza que fgetc() sabrá hacer "lo correcto" en este caso?
224  Programación / Programación C/C++ / Re: problemas con fseeks en: 8 Febrero 2014, 14:52 pm
Jaja, la verdad es que tengo tiempo programando (varios años), y no sólo en C, también he hecho scripts en Matlab, Assembler, VisualBasic y aplicaciones en el mini-VB que viene integrado con el Excel (estos últimos los dejé por lo limitado que eran).

Pero recién ahora fue que decidí ingresar a un foro para interacturar con otros miembros de la comunidad.

Respecto a los proyectos en C ¿te has animado a hacer alguna biblioteca/librería COMPLETA y lista para usar, y liberarla en la comunidad? Los fuentes por supuesto, más las instrucciones para su compilación e integración al sistema del usuario.

Yo estoy trabajando en una sencilla biblioteca de matrices bidimensionales numéricas, con clases y métodos predefinidas, donde el usuario declare el tamaño y ya se cree la matriz, además pueda redimensionarla en tiempo de ejecución (no que sea estática). Y de regalo, las operaciones algebraicas de sumar y multiplicar matrices, y quizás ....... resolver sistemas de ecuaciones jeje.

Yo doy por sentado que eso ya debe existir, y quizá muchas versiones de lo mismo, pero yo quiero hacer la mía y además con fines didácticos, liberar el código a la comunidad y explicar por qué se escribe esto y lo otro, etc  :)
225  Programación / Programación C/C++ / Re: problemas con fseeks en: 8 Febrero 2014, 04:26 am
Escribir los include's y lib's siempre no te parece que es simplemente una perdida de tiempo?, Yp sé que al inicio es una forma para
saber como realmente funciona el proceso de compilación, qué tipo de archivos y como son procesados por el compilador y el linker
esta bien, pero escribirlos por toda la vida, en todos tus programas simplemente lo veo una perdida de tiempo (...) crees que es siempre
conveniente escribir siempre los include's y lib's talvez nos puedes explicar el ¿porqué?

Bueno, una razón es básicamente para saber. Otra es porque generalmente cuando se está desarrollando un trabajo grande, uno crea clases que llevan ficheros include personalizados, y si lo vuelves una biblioteca, tendrás directorios de lib. Estos claro no son los de la biblioteca estándar de C que los incluye el compilador sino los directorios personalizados que uno crea.

En mi caso, normalmente paso por fases experimentales de prueba donde las bibliotecas van a un directorio "temporal" donde son probadas y luego a su lugar definitivo. Así que estoy creado, moviendo y eliminando directorios todo el tiempo  :)

Con una IDE de desarrollo de C++ se puede "editar" el proyecto para añadir o eliminar estos ficheros, pero como es una interfaz gráfica que se maneja con ratón, en lo personal siento que me manejo mucho más rápido con el teclado que con el ratón (me gusta usar puro Alt+Tab, Alt+Repag, Ctrl+AvPag, Shitf+F10 y cosas por el estilo). Por eso es que todo lo hago por la cónsola y por supuesto compilar mis proyectos de C es una de esas actividades.

Por otra parte, ¿qué son las IDE's gráficas sino una interfaz con un script o conjunto de comandos corriendo detrás? Siendo así, prefiero ir de una vez a los comandos y saltarme lo visual, jeje :laugh:

Aquí mismo para meter texto en negrita, o hacer los codes, prefiero escribir las etiquetas a mano (\[ b \], \[i\], etc) que pulsar el iconito, no se ... me parece maś rápido ....

Ahora, en lo de hacer scripts de compilación tienes razón, últimamente he estado preparando ficheros Make para facilitar la tarea ...

Pero hasta para compilar un ejemplo pequeñito (como problemas pequeños que plantean usuarios de aquí y quiero probar compilando en realidad) apelo a mi gcc/g++ y cónsola, no se ..... es un hábito que se me ha quedado.

Es la ventaja de Linux, que todo lo puedes hacer con el teclado, incluso configurar tu fichero fstab para montar y desmontar las unidades externas usb manualmente. La última vez le quité los permisos de ejecución al nautilus para obligarme a navegar por directorios usando exclusivamente la consola y dejar de usar el explorador gráfico que ya me fastidia (jeje), ...... Quién sabe, a lo mejor un día te quedas sin escritorio gráfico (una vez me pasó) y luego ¿cómo vas a hacer?  :o

Bueno pero como decimos son cosas de gustos y filosofías, cada quién tiene la suya  :)

Creo haber explicado la razón por la que hago las cosas de ese modo, y al mismo tiempo he tomado tiempo para describir una parte de mí, no se si en este foro hay una sección para los usuarios hablar de sí mismos, sus gustos, formas de trabajo, etc ...
226  Programación / Programación C/C++ / Re: Programa que identifique que tipo de dato se introduce C++ en: 8 Febrero 2014, 03:48 am
No se puede!!. C es un lenguaje "tipado", al contrario de otros lenguajes donde una variable puede alegremente cambiar de un tipo a otro.

Como te contestó otro usuario, esto significa que a cada variable que uses en C debes haberle definido previamente un tipo, de lo contrario el compilador te informará un error. Recuerda que distintos tipos ocupan distinto espacio en memoria, así que el compilador debe saber previamente el tipo de cada variable para calcular correctamente cuántos bytes asignarle dentro de la memoria de datos del programa.

Si un usuario mete un valor por la consola (teclado), aún así debes declarar un tipo esperado en la cadena de control de formato de scanf (posiblemente distinto al que el usuario esperaba, pero aún así es un tipo fijo declarado previamente en el programa). Por otra parte, la variable a la que será asignado este valor tiene un tipo previamente declarado, por tanto será ese tipo y no otro.

Ten en cuenta algo muy importante. Si por ejemplo declaras:

Código
  1. int x;

y luego haces algo como

Código
  1. scanf( "%d", &x);

pues ya dijiste que se esperaba un tipo entero. No importa que el usuario meta un valor decimal a través del teclado, el valor será convertido forzosamente a un entero (según las reglas implícitas de conversión de C).
227  Programación / Programación C/C++ / Re: Hola Soy nuevo[DUDA] en: 8 Febrero 2014, 03:31 am
Lo otro que preguntaste "parámetros pasados por valor", significa que en C todas las variables se pasan "por valor" (se pueden simular llamadas por referencia usando punteros pero ese es un tema más avanzado).

Esto quiere decir que cuando una función recibe una variable como argumento, ella saca una copia de este valor y lo usa internamente. Pero el valor externo de la varible queda sin alterar. En C existen distintos "ámbitos" o espacio de trabajo, y cada función tiene su espacio de trabajo privado lo cual significa que las variables dentro del cuerpo de una función son locales, o sea, la función en cuestión es la única que las ve y nadie más.

Vamos con un ejemplo. Tienes una función f la cual toma una variable x como argumento y hace lo siguiente:

Código
  1. void f( int x ) {
  2.  
  3.    x = x + 1;
  4. }

es decir, incrementa su valor en una unidad. Ahora, esa función va dentro de un main donde existe la variable x:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. /* aquí prototipo de f */
  5. int f( int x, int y );
  6.  
  7. /* aquí viene el main */
  8. int main ( ) {
  9.  
  10.   int x;
  11.  
  12.   x = 2;
  13.   f( x );    /* llamamos a la función f */
  14.   printf( "El valor de x es: %d\n", x );
  15.   return 0;
  16. }
  17.  
  18. /* aquí la definición de f */
  19. void f( int x ) {
  20.  
  21.    x = x + 1;
  22. }

¿Qué valor de x imprime el programa al ser ejecutado? Pues, el valor 2, ¡y no 3!

Lo que ocurre es que la función f agarra la variable x le saca una "copia" y la usa en su espacio de trabajo interno. Este valor copia de x será 2, y durante el "tiempo de vida" de la función su valor es cambiado a 3. Pero al retornar la función, sus variables internas se destruyen ..... físicamente. Sí, son físicamente borradas de la memoria del programa, luego ya no existen más. Ese valor de x = 3 ya no existe más al retornar la función f por lo tanto el valor que ve printf es el valor 2 que existe dentro del aḿbito del main().

Espero haya quedado claro el tema de los parámetros por valor, y siempre ten en cuenta que las variables definidas dentro de una función tienen un ámbito local, y por lo tanto una vida temporal. Saber esto bien te evitará dolores de cabeza en el futuro.

........... Espero sigas incursionando en el apasionante mundo de C, y cualquier cosa vuelve a preguntar ........  :)
228  Programación / Programación C/C++ / Re: Hola Soy nuevo[DUDA] en: 8 Febrero 2014, 03:14 am
Continuando con este mini-tutorial (considera que es apeeeeeenas una introducción al fascinante mundo de C, del cual una vez entras no quieres salir jeje), seguro ahora querrás saber cómo incluir una función que tome argumentos. Por ejemplo, quieres una función que dado "x" y dado "y" calcule "x+y" y lo devuelva al usuario. Suponemos que "x" e "y" son de tipo entero. El tema de los "tipos" es C es algo que obligatoriamente debes empezar a leer, ya que C es un lenguaje fuertemente tipado, y si esto no se maneja bien puedes tener muchos errores.

Sigamos pues, esta función que llamaremos f1 debe tener el prototipo:

Código
  1. int f1( int x, int y)

Esto es, toma dos argumentos de tipo entero, y devuelve un entero. Ya sabiendo esto, y habiendo entendido el ejemplo anterior, te doy el código del programa completo para que lo analices  ;-)

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. /* aquí prototipo de hola */
  5. int f1( int x, int y );
  6.  
  7. /* aquí viene el main */
  8. int main ( ) {
  9.  
  10.    int x, y, s;
  11.  
  12.    x = 3;
  13.    y = 4;
  14.    s = f1(x, y);
  15.    printf( "La suma de %d y %d es: %d\n", x, y, s );
  16.    return 0;
  17. }
  18.  
  19. /* aquí la definición de f1 */
  20. int f1( int x, int y ) {
  21.  
  22.   return x + y;
  23. }

Este programa al ser ejecutado debería imprimir en pantalla el mensaje "La suma de 3 y 4 es: 7". Observa que en el main() primero hemos asignado el valor 3 a "x", y el valor 4 a "y", luego calculamos "s" como el valor devuelto por la función f1 con sus argumentos x, y; es decir, la suma x+y (que será 7).

En el printf verás unos simbolitos %d, %d, %d. Eso se llama "especificadores de control de formato". Ellos dicen que serán sustituidos por el valor de ciertas variables de tipo entero dadas al final del printf. El primer %d será sustituido por el valor del primer argumento que sigue a la cadena de control de formato dentro de printf, el cual es x. El segundo %d será sustituido por y, el tercero por s. Como ves es fácil de entender, pero ojo que hay varios especificadores de formarto aparte de %d, así como banderas de espacio, de signo, etc, que hacen de printf una función muy versátil y potente, y si la usas bien podrás escribir casi cualquier mensaje en la pantalla.
229  Programación / Programación C/C++ / Re: Hola Soy nuevo[DUDA] en: 8 Febrero 2014, 03:01 am
Una función es una porción de programa (le llamamos "rutina") que puede tomar argumentos de entrada, y devolver un valor de salida.

Una función que es obligatoria en cualquier programa de C es main(). Ya que estás comenzando, y para que aprendas a hacerlo bien desde el principio, te digo que cualquiera de los programas en C que vayas a hacer (espero sean muchos  :) ) deberá seguir más o menos la siguiente estructura:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. int main( ) {
  6.  
  7.    /* aquí va lo que quieres que haga el programa */
  8.  
  9.    return 0;
  10. }
  11.  

Te explico. Las primeras tres líneas que llevan #include son para incluir las bibliotecas básicas de C, sin ellas no podrás hacer casi nada. Existen muchas bibliotecas, pero con esas tres que te indico podrás recibir datos desde el teclado, imprimir datos en la pantalla, y manipular cadenas. Luego viene el main() que como te dije es obligatorio, y el return 0. Este return es para especificar lo que devuelve (o "retorna") la por ahora única función que existe en tu programa, que main(). Generalmente en un main() se devolverá cero si el programa se ejecutó satisfactoriamente, y un valor negativo (-1 por ejemplo) si ocurrió un error durante el programa. Por último, lo que va entre un /* y un */ es un comentario de C, o sea, algo que el programador pone para explicar su programa pero que no es tomado en cuenta para generar el ejecutable.

Ahora, supón que quieres incluir una segunda función "hola" que imprima "Hola usuario" [en el argot de la informática esta típica bienvenida suele ponerse como "Hola mundo", jeje]. Pues, TODAS funciones que crees en tu programa deben ser llamadas desde la función principal main() ¿comprendes?.

Una segunda cosa que debes saber es que cualquier función que crees deberá llevar su "prototipo", por cierto antes de main(). El prototipo dice el tipo y número de argumentos de la función, así el tipo del valor de retorno si hubiera alguno. Si no lleva argumentos se escribe "void". Vamos con un ejemplo, tu función "hola" no lleva argumentos de entrada ni de salida, por ello se puede declarar:

Código
  1. void hola ( main );
  2.  

o:

Código
  1. void hola ( );
  2.  

sin poner nada entre los paréntesis. La primera forma es la "correcta" en C, aunque la segunda se admite. No olvides el punto y coma después de la declaración de función, así como al final de cualquier línea de instrucción de C.

Lo otro que debes hacer es escribir la definición de la función. En otras palabras, escribir el código que indique lo que tú quieres que la función haga. Eso sería, como ya lo hiciste:

Código
  1. void hola( void) {
  2.    printf( "Hola mundo\n" );
  3.  

pero mira que lo correcto es que pongas la definición de hola después del main(), y no antes!! Es decir, el prototipo de hola va antes de main() (los prototipos siempre son lo primer del programa después de los #include), pero la definición de cualquier función hecha por tí debe ir después de main(). Como te dije, debes acostumbrarte a hacerlo bien desde el principio para que llegues a ser un gran programador de C.

Bueno, ahora te voy a dar el código final de TODO el programa, listo para que lo compiles y lo pruebes. Debe quedar así:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. /* aquí prototipo de hola */
  5. void hola( void );
  6.  
  7. /* aquí viene el main */
  8. int main ( ) {
  9.  
  10.    hola( );
  11.    return 0;
  12. }
  13.  
  14. /* aquí la definición de hola */
  15. void hola( void ) {
  16.  
  17.    printf( "Hola mundo");
  18. }

Nota por cierto que en el código de la función hola no va ningún return porque esta función no devuelve nada.

Esta es una mini guía con la que puedes empezar, y espero leas y te instruyas para que llegues a conocer mucho de C.
230  Programación / Programación C/C++ / Re: ¿Algun buen libro para afianzar y ampliar conocimientos sobre C++? en: 7 Febrero 2014, 03:28 am
En cuánto a libros en físico yo recomendaría Deitel & Deitel, escrito por profesores con muchos años de experiencia programando y enseñando C.

Te explican muy bien las bases del lenguaje, e incluso algunos aspectos sobre cómo trabaja el lenguaje "a fondo" (en bajo nivel), en cuestiones de memoria y eso. Un texto muy académico y sobre todo explica el C "genuino" normado por ANSI.

Si lo logras descargar perfecto, pero no se si está disponible. De todos modos no creo que tengas problema en conseguirlo físico.
Páginas: 1 ... 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