| Ver tema anterior :: Ver siguiente tema | | Autor | Mensaje |
|---|
rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 16/04/2006 7:44 am | | | Título: Compendio de errores, notas y comentarios |
| Curso de C de Gorka Urrutia -- errata/notas/recomendaciones
2006/04/12 - 2006/11/26
Antes que nada por favor no respondan directamente en este tema ya que tengo planeado utilizarlo solo para el desglose de los errores, notas y comentarios con relacion al curso de C de Gorka Urrutia.
Me he tomado la libertad de realizar este compendio esperando que sea de utilidad para aquellos que siguen el curso de Gorka y tambien para su autor si el decide (eventualmente) agregar estas correciones y sugerencias a su curso, por supuesto sobra decir que esta decision es un asunto exclusivo de Gorka Urrutia.
Cada capitulo se desglosa en un mensaje y este a su vez en secciones etiquetadas como:
---- Error: Ortografia: Nota:
Me parece que esas secciones no requieren de mayor explicacion. ----
* Las secciones marcadas como "Recomendacion" son exactamente eso: una recomendacion que en el personal (y no tan subjetivo) punto de vista de su servidor seria una mejora al curso.
* Las secciones marcadas como "Nota tecnica" requieren una mayor explicacion: el espiritu del curso es enfocarse en el principiante en C con pocos (o nulos) conocimientos de programacion en otros lenguajes.
Por lo mismo no seria bueno en mi opinion sobrecargar al estudiante con todos los detalles tecnicos del porque de ciertas caracteristicas del lenguaje C.
En su lugar lo mejor es dar solo la informacion suficiente (y correcta) para que el estudiante pueda seguir el curso y si este desea mayor informacion podria revisar estas "notas tecnicas" donde se describirian con detalle ciertas caracteristicas en relacion con el estandar de C (ISO-C90).
Un saludo _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 10:28 am; editado 2 veces |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 16/04/2006 7:57 am | | | Título: Capitulo 1 -- Introduccion |
| Recomendacion:
"Algunos capítulos tienen apartados dedicados a algún Sistema Operativo en concreto y está indicado en el título entre paréntesis. Por ejemplo en el Capítulo 2 hay un apartado titulado 'Gotoxy: Posicionando el cursor (DOS)'. El DOS entre paréntesis indica que sólo tiene validez en DOS."
Me parece mejor cambiar el enfoque de sistema operativo (MS-DOS) a biblioteca (conio). En otras palabras seria mejor etiquetar esos ejemplos con una etiqueta como "requiere soporte de conio", con esto se indicaria que el ejemplo es valido (y compila correctamente) solo con aquellos compiladores que incluyan (o pueden configurarse con) soporte para la mencionada biblioteca como MinGW (Dev-C++) y Lcc-win32 entre otros.
-------------------------------------------------------------------- Recomendacion:
"Siguiendo la filosofía de mi página los compiladores que usaremos serán gratuítos. Si vas a programar en Windows te recomiendo usar el Dev-C++, de fácil instalación y manejo."
* Seria bueno colocar inmediatamente despues de este parrafo vinculos a la pagina principal de Dev-C++ y a las dos FAQs de este IDE (los tres por desgracia en ingles):
Pagina principal Dev-C++ 4 FAQ Dev-C++ 5 FAQ
* Instalacion de Dev-C++
Para esto solo se necesita descargar la ultima version de ese IDE y que al momento de escribir este mensaje es Dev-C++ 5 Beta 9 (4.9.9.2). Su instalacion es similar e igual de facil que cualquier otra aplicacion para los sistemas operativos MS Windows.
-------------------------------------------------------------------- Recomendacion:
Agregar una mini-FAQ con las tres preguntas mas frecuentes de los principiantes de C utilizando Dev-C++ las cuales son:
1) Error debido a que GCC requiere que TODAS las lineas terminen con el caracter de 'linea nueva' (el generado por la tecla {ENTER}):
| Código: | "8:2 C:\Dev\User\C\Hello_world\HelloWorld.c [Warning] no newline at end of file" |
Solucion: la forma mas sencilla de solucionar este error es colocando el cursor de texto al final del archivo de codigo fuente y despues de esto simplemente presionamos la tecla {ENTER}.
2) No hay "pausa automatica" cuando se ejecuta una aplicacion de consola desde Dev-C++.
Por ejemplo este programa:
| Código: | #include <stdio.h>
int main(void) { printf("Hello, world\n"); return 0; } |
Aparece y desaparece en un instante.
Esto se debe a que a diferencia de otros IDEs Dev-C++ no soporta la generacion automatica de esta pausa. La unica solucion es que los usuarios de este IDE hagan una peticion para que eventualmente se añada esta caracteristica.
Una "solucion a medias" pero que funciona es utilizar la funcion getchar en esta forma:
| Código: | #include <stdio.h>
int main(void) { printf("Hello, world\n"); getchar(); return 0; } |
3) Dev-C++ no soporta (reconoce) las funciones como gotoxy y getch
Por ejemplo este programa:
| Código: | #include <stdio.h> #include <conio.h>
int main() { gotoxy( 20, 10 ); printf( "Hola" ); getch(); return 0; } |
Al ser compilado genera este error:
| Código: | "[Linker error] undefined reference to `gotoxy'" |
Esto se debe a que esa biblioteca debe instalarse aparte y como un "dev-pack". Para esto se debe estar conectado a Internet y en Dev-C++ se selecciona el menu "Tools" (Herramientas), "Check for updates/packages" (Verificar actualizaciones/paquetes).
En ese cuadro de dialogo:
1) En "Select devpack server" seleccionamos como servidor a "devpacks.org Community Devpacks".
2) Le damos click al boton "Check for updates" ("Revisar si hay actualizaciones").
3) Seleccionamos el devpack "CONIO" y le damos click al boton "Download selected" (descargar seleccionados).
Despues de esto aparece otro cuadro de dialogo donde debemos darle click al boton "Install" (Instalar).
Por ultimo debemos seleccionar el menu "Tools" (Herramientas), "Compiler options" (Opciones del compilador) y en el cuadro de texto "Adds these commands to the linker command line" y que en español seria mas o menos "Agregar estos comandos a la linea de comandos del enlazador" agregamos:
Despues de esto el programa debe compilar correctamente.
-------------------------------------------------------------------- Recomendacion:
"Nota: Hay mucha gente que programa en Windows que se queja de que cuando ejecuta el programa no puede ver el resultado. Para evitarlo se puede añadir antes de return 0; la siguiente línea:
Si esto no funciona prueba a añadir getch();"
* Tomando en consideracion que este es el primer programa que compila el lector y que: A) system requiere la inclusion de stdlib.h B) getch require la inclusion de conio.h
Seria mejor recomendar el uso de la funcion getchar ya que esta es la que requiere de menos cambios al codigo fuente:
| Código: | #include <stdio.h>
int main() { printf("Hola mundo\n"); getchar(); /* pausa */ return 0; } |
-------------------------------------------------------------------- Ortografia:
"Cuando en compilador se encuentra con esta directiva la sustituye por el archivo indicado."
Deberia ser: "Cuando el compilador se encuentra con esta directiva la sustituye por el archivo indicado."
-------------------------------------------------------------------- Recomendacion:
"int main()"
Esta es una forma correcta de definir a la funcion 'main' pero seria incluso mejor utilizar la forma "int main(void)" ya que esta tambien es una forma correcta y algunos compiladores como Lcc-win32 y Pelles C al ser utilizados en su modo mas estricto "se quejan" de la forma "int main()".
-------------------------------------------------------------------- Ortografia:
"Este valor se suele usar para saber cómo ha terminado el prorama."
Deberia ser: "Este valor se suele usar para saber cómo ha terminado el programa."
-------------------------------------------------------------------- Error:
"Si estamos usando DJGPP (ver información sobre instalación y uso de DJGPP): tenemos que llamarlo desde la línea de comando:
| Código: | gcc -c primero.c -o primero.exe" |
* Cuando se ejecuta gcc desde la linea de comandos la opcion "-c" indica que solo se debe compilar pero sin realizar la vinculacion y, por lo mismo, producir el ejecutable.
Deberia ser:
| Código: | gcc primero.c -o primero.exe |
_________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 27/11/2006 12:18 am; editado 3 veces |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 17/04/2006 1:43 am | | | Título: Capitulo 2 -- Mostrando Informacion por pantalla |
| Recomendacion:
* Casi al final de la primera seccion "Printf: Imprimir en pantalla":
| Cita: | "Pero ¿qué pasa si queremos imprimir el símbolo " en pantalla? Por ejemplo imaginemos que queremos escribir:
|
El uso de caracteres como las vocales acentuadas o, como en este caso la 'ñ' puede resultar problematico ya que no forman parte del codigo ASCII sino del "Extended ASCII character set".
Y debido a que los caracteres que componen este "character set" dependen de como este configurado el SO del lector me parece mejor evitar (por lo menos en esta etapa del curso) los caracteres que no formen parte del juego de caracteres ASCII.
-------------------------------------------------------------------- Recomendacion:
* Casi al final de la primera seccion "Printf: Imprimir en pantalla":
| Cita: | "Esta contrabarra se usa en C para indicar al compilador que queremos meter símbolos especiales. Pero ¿Y si lo que queremos es usar '\' como un carácter normal y poner por ejemplo Hola\Adiós? Pues muy fácil, volvemos a usar '\':
| Código: | printf( "Hola\\Adiós" ); |
y esta doble '\' indica a C que lo que queremos es mostrar una '\'." |
Seria bueno colocar despues de este parrafo una lista de los caracteres especiales en el lenguaje C y que deben ir precedidos por una '\':
| Código: | \a alert alerta o campana \b backspace retroceso \f formfeed ??? \n newline nueva linea \r carriage return retorno de carro \t horizontal tab tabulador horizontal \v vertical tab tabulador vertical \\ backslash diagonal invertida \? question mark signo de interrogacion \' single quote comilla sencilla \" double quote comilla doble |
-------------------------------------------------------------------- Error:
"Este método sólo vale para compiladores que incluyan el fichero stdio.h."
Deberia ser: "Este método sólo vale para compiladores que incluyan el fichero conio.h." _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 8:17 am; editado 2 veces |
| | Volver arriba | |  | | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 18/04/2006 4:59 pm | | | Título: Capitulo 3 -- Tipos de Datos |
| Recomendacion:
En todos los ejemplos de este capitulo falta indicar el valor de retorno de la funcion "main" y seria mejor utilizar la forma:
| Código: | int main(void) { /* ... */ }
|
-------------------------------------------------------------------- Nota:
En el anexo del curso falta la lista de las palabras reservadas o keywords, estas son segun el estandar ISO-C90:
| Código: | auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while |
-------------------------------------------------------------------- Error de ortografia:
"Vamos a ir u poco más allá con la función printf."
Deberia ser: "Vamos a ir un poco más allá con la función printf."
-------------------------------------------------------------------- Error:
En el primer ejemplo en la seccion "Asignar valores a variables de tipo int" la primera llamada a la funcion printf tiene un error de sintaxis:
| Código: | prinft( "El valor inicial de x es %i\n", x ); |
Deberia ser:
| Código: | printf( "El valor inicial de x es %i\n", x ); |
-------------------------------------------------------------------- Recomendacion:
Este capitulo se debe modificar de forma significativa ya que tiene algunos errores y tambien varias omisiones: faltan las descripciones de los tipos short int, long int y long double.
Algunas notas que espero sean de utilidad para actualizar este capitulo:
1) En C los tipos utilizados para almacenar numeros se conocen como tipos aritmeticos y se dividen en dos grupos: tipos enteros y tipos de punto flotante.
2.1) Los tipos enteros son char, short int, int y long int. Los tipos short int y long int se pueden abreviar a solo short y long.
2.2) Los indicadores de signo signed y unsigned solo pueden aplicarse a los tipos enteros. El primero indica que el tipo puede almacenar tanto valores positivos como negativos y el segundo indica que solo se admiten valores no negativos, esto es, solo se admite el cero y valores positivos.
2.3) Si se declara una variable de tipo short, int o long sin utilizar un indicador de signo esto es equivalente a utilizar el indicador de signo signed. Por ejemplo:
signed int i; int j;
Declara dos variables de tipo signed int.
2.4) La excepcion es el tipo char. Cuando se declara una variable de tipo char sin utilizar un indicador de signo si esta variable es equivalente a signed char o a unsigned char depende del compilador que estemos utilizando.
Por lo mismo si debemos tener total certeza de que nuestras variables de tipo char puedan almacenar (o no) valores negativos es mejor indicarlo explicitamente utilizando ya sea signed char o unsigned char.
2.5) El numero de valores posibles y unicos que pueden almacenarse en un tipo entero depende del numero de bits que lo componen y esta dado por la expresion 2^N donde N es el numero de bits. Por ejemplo si en nuestro caso el tipo short esta compuesto por 16 bits el numero de valores posibles es 65,536.
2.6) En los tipos sin signo el valor minimo que puede almacenarse es 0 y el maximo esta dado por 2^N - 1.
2.7) En los tipos con signo el valor minimo esta dado por la expresion -(2^(N - 1) - 1) y el valor maximo por 2^(N - 1) - 1. Por ejemplo si en nuestro caso el tipo signed char esta constituido por 8 bits entonces su valor minimo es -127 y su valor maximo 127.
2.8) El tipo short esta constituido por al menos 16 bits y el tipo long por al menos 32 bits. El tipo int "flota en medio" y usualmente tiene el mismo numero de bits que el tipo short o el tipo long.
2.9) El numero de bits que componen a los tipos short, int y long siempre cumple esta regla:
short <= int <= long
2.10) El numero exacto de bits que componen a los tipos short, int y long depende de la implementacion que estemos utilizando.
"Implementacion" es la combinacion de software y hardware que estemos utilizando.
2.11) El numero de bits por byte es usualmente 8 pero esto no esta garantizado, para conocer este valor podemos utilizar la macro CHAR_BIT que esta definida en limits.h
2.12) Los tipos enteros sin signo no pueden desbordarse.
2.13) Los tipos enteros con signo si pueden desbordarse y esto produce "undefined behaviour". En español: si una variable de tipo entero con signo se desborda cualquier cosa puede pasar: resultados incorrectos, el programa simplemente revienta, etc.
3.1) Los tipos de punto flotante son float, double y long double.
3.2) La relacion entre los tipos float, double y long double es:
float <= double <= long double
3.3) Los rangos posibles de estos tres tipos depende de la implementacion pero los tres estan garantizados a poder almacenar numeros en el rango -10^37 a 10^37. _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 8:48 am; editado 2 veces |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 19/04/2006 5:47 am | | | Título: Capitulo 4 -- Constantes (uso de #define) |
| Recomendacion:
Cambiar en todos los ejemplos la definicion de main de "int main()" a "int main(void)" y eliminar las vocales acentuadas de los dos primeros ejemplos.
-------------------------------------------------------------------- Recomendacion:
En ambos ejemplos y debido a que se manejan numeros de tipo double (en el primer ejemplo la constante 3.1416) seria mejor cambiar el tipo de las variables del tipo int al tipo double.
En el caso del primer ejemplo:
| Código: | #include <stdio.h>
int main(void) { double radio; double perimetro;
radio = 20.0; perimetro = 2.0 * 3.1416 * radio; printf("El perímetro es: %f\n", perimetro); return 0; } |
Tambien me parece que este es el capitulo indicado para describir el tipo de las constantes:
-------------------------------------------------------------------- 1) Las constantes en base 10 (decimal) y sin fraccion ni exponente son de tipo signed int.
Algunos ejemplos:
| Código: | a = 100; b = 200; c = 300; d = 400; |
Nota tecnica:
Para indicar de una forma explicita el tipo de una constante entera se pueden utilizar los sufijos 'U' y/o 'L' ya sea en minusculas o mayusculas. El primero indica que es un tipo sin signo (unsigned) y el segundo que es de tipo 'long int'.
Algunos ejemplos:
| Código: | a = 100; /* 100 es de tipo signed int */ b = 200U; /* 200U es de tipo unsigned int */ c = 300L; /* 300L es de tipo signed long */ d = 400UL; /* 400UL es de tipo unsigned long */ |
¿Y que pasa si una constante "no cabe" en el tipo indicado? Supongamos que (en nuestro caso) el valor maximo que se puede almacenar en el tipo int es 32767 y (por poner un ejemplo) en nuestro programa tenemos:
| Código: | int a = 32768; /* 32768 "no cabe" en un int */ |
¿Que es lo que sucede?
Bueno, en realidad las constantes enteras *Y* en base 10 son del tipo mas pequeño que pueda almacenar el numero en cuestion y el tipo de la constante se selecciona en este orden:
1) int 2) long 3) unsigned long
Debido a que en nuestro ejemplo 32768 no cabe en un int se revisa el tipo signed long y si en este tampoco cabe el tipo de la constante es unsigned long.
Y si la constante en cuestion tiene uno de los dos sufijos 'U' o 'L' el tipo a utilizar se restringe (limita) y selecciona en este orden:
A) En el caso de utilizar 'U': 1) unsigned int 2) unsigned long
B) En el caso de utilizar 'L': 1) signed long 2) unsigned long
-------------------------------------------------------------------- 2) Las constantes en base 10 y con un punto decimal y/o exponente son de tipo double.
Algunos ejemplos:
| Código: | a = 100.0; /* 100.0 es de tipo 'double' */ b = 10E2; /* 10E2 es de tipo 'double' */ |
Nota tecnica:
Las constantes de punto flotante son de tipo double a menos que se utilize uno de estos sufijos ya sea en minusculas o mayusculas:
A) El sufijo 'F' indica que la constante es de tipo float. B) El sufijo 'L' indica que la constante es de tipo long double.
Solo se debe utilizar uno de estos sufijos pero no ambos.
Algunos ejemplos:
| Código: | a = 100.0F /* 100.0F es de tipo float */ b = 200.0 /* 200.0 es de tipo double */ c = 300.0L /* 300.0L es de tipo long double */ |
_________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 9:10 am; editado 1 vez |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 06/05/2006 8:20 am | | | Título: Capitulo 5 -- Manipulando datos (Operadores) |
| * Nota:
En el primer parrafo de la seccion "Operadores aritméticos":
"Los operadores aritméticos son aquellos que sirven para realizar operaciones tales como suma, resta, división y multiplicación."
Deberia ser (por ejemplo):
"Los operadores aritméticos son aquellos que sirven para realizar operaciones tales como suma, resta, división, multiplicación y modulo (o residuo).
Con excepcion del operador de modulo (el '%') los operandos de estos operadores pueden ser numeros enteros, numeros de tipo flotante o una combinacion de ambos.
El operador de modulo solo acepta como operandos a numeros enteros.
En el lenguaje C la division por cero no es valida y debido a esto no se debe utilizar como segundo operando:
A) El valor 0 con los operadores de division y modulo. B) El valor 0.0 con el operador de division."
-------------------------------------------------------------------- * Recomendacion:
En todos los ejemplos y ejercicios de este capitulo no se utiliza la palabra reservada "return" para indicar el valor de retorno de la funcion "main" lo que puede ocasionar que algunos compiladores al ser utilizados en su modo mas estricto posible emitan una advertencia.
Por lo mismo seria mejor utilizar la forma:
| Código: | /* ... */
int main(void) { /* ... */
return 0; } |
-------------------------------------------------------------------- * Error logico:
En el segundo ejemplo de la seccion "Operador (+) : Suma" se utiliza la funcion printf para imprimir el valor de la variable "c" cuando se deberia imprimir el valor de la variable "d".
-------------------------------------------------------------------- * Nota:
En el segundo parrafo de la seccion "Operadores de comparación":
"Cuando se evalúa una condición el resultado que se obtiene es 0 si no se cumple y un número distinto de 0 si se cumple. Normalmente cuando se cumplen devuelven un 1."
Deberia ser (por ejemplo):
"El resultado de los operadores de relacion (">", "<", ">="y"<=") e igualdad ("=="y"!=") es 1 si la expresion es verdadera y 0 en caso contrario."
-------------------------------------------------------------------- * Error logico:
En el unico ejemplo de la seccion "Operadores de comparación" la primera y segunda llamada a la printf son identicas.
Supongo que la intencion es imprimir el resultado de las expresiones "10 > 5" y "10 < 5", por lo mismo deberia ser:
| Código: | #include <stdio.h>
int main(void) { printf("10 > 5 da como resultado %i\n", 10 > 5); printf("10 < 5 da como resultado %i\n", 10 < 5); printf(" 5 == 5 da como resultado %i\n", 5 == 5); printf("10 == 5 da como resultado %i\n", 10 == 5); return 0; } |
-------------------------------------------------------------------- * Nota tecnica:
Seccion "Operadores lógicos"
Descripcion mas detallada de las caracteristicas especiales de los operadores logicos AND y OR las cuales son:
1) Estos dos operadores garantizan el orden de evaluacion: primero se evalua el operando a su izquierda y solo despues de esto (y si es necesario) el operando a su derecha.
2) A estos dos operadores se les conoce como "operadores de corto circuito" o "short circuit operators" debido a la forma particular en la que operan:
* En el caso del operador AND su resultado es 0 si la primera expresion es falsa (igual a 0), la segunda expresion no se evalua.
* En el caso del operador OR su resultado es 1 si la primera expresion es verdadera (diferente de 0), la segunda expresion no se evalua.
Estos dos operadores son particularmente utiles cuando se debe evaluar (o no) una expresion dependiendo de la evaluacion de una expresion anterior.
Por ejemplo supongamos que tenemos dos numeros enteros (a y b) y tenemos que verificar si el primero (a) es un multiplo del segundo (b).
Para esto solo tenemos que verificar si el modulo o residuo de la division de a entre b es igual a cero siempre y cuando b, para empezar, no sea igual a cero.
Esto se puede implementar facilmente con el operador logico AND:
| Código: | if ((b != 0) && (a % b == 0)) /* b es multiplo de a */ |
Aqui el operador AND primero evalua la expresion a su izquierda y solo si esta es verdadera (b es diferente de cero) se evalua la expresion a su derecha (¿el residuo de a entre b es cero?).
-------------------------------------------------------------------- * Nota tecnica:
"Introducción a los bits y bytes"
En C en lugar de utilizarse el byte la unidad de medicion es el (equivalente) unsigned char y si bien el numero de bits por byte (o por caracter) es usualmente ocho este (el numero de bits) puede ser mayor.
Para estar seguros del numero de bits por caracter lo mejor es verificar el valor de la macro CHAR_BIT, esta se define en el header limits.h.
-------------------------------------------------------------------- * Nota:
En los ejemplos sobre el uso de los operadores a nivel de bits se utiliza el caracter con acento en "operación" lo que deberia evitarse ya que el caracter que se imprima depende de la implementacion:
| Código: | printf( "El resultado de la operación 235 | 143 es: %i\n", 235 | 143 ); |
-------------------------------------------------------------------- * Recomendacion y nota tecnica:
La seccion "Operador ~ (Complemento a uno)" me parece el mejor lugar para indicar que los operandos de TODOS los operadores a nivel de bits como AND, OR, etc. son afectados por las promociones integrales o integral promotions:
La promocion integral es la conversion de un operando de tipo char o short al tipo int.
Por ejemplo si en nuestro caso el numero de bits por caracter es ocho y declaramos una variable de tipo signed char:
| Código: | signed char ch = 0; |
En este caso y si el numero de bits por caracter (CHAR_BIT) es igual a ocho tenemos que el patron de bits de la variable 'ch' es:
Pero cuando se realiza la operacion:
| Código: | printf("El complemento a uno es %d\n", ~ch); |
Antes de ejecutarse la operacion de complemento a uno el valor almacenado en la variable ch se "promociona" a int y el patron de bits del valor resultado de esta conversion es:
A) En el caso de que el numero de bits por int sea 16:
| Código: | 0000 0000 0000 0000 |
B) En el caso de que el numero de bits por int sea 32:
| Código: | 0000 0000 0000 0000 0000 0000 0000 0000 |
C) etc.
Es en este patron de bits donde se realiza la operacion de complemento a uno y el resultado es, en el caso de que el numero de bits por int sea 16:
| Código: | 1111 1111 1111 1111 |
Hay que recalcar que si bien el valor de la variable ch y el valor resultado de la promocion integral es el mismo (cero en ambos casos) el tipo y por lo mismo el numero de bits no lo es.
-------------------------------------------------------------------- * Error:
En el unico ejemplo sobre el operador de complemento a uno para obtener el valor 103 como resultado se deben "filtrar" los primeros ocho bits, por ejemplo utilizando el operador AND:
| Código: | printf( "El resultado de la operación ~152 es: %i\n", ~152 & 0xFF); |
-------------------------------------------------------------------- * Nota tecnica:
En la seccion "Operador >> (Desplazamiento a la derecha)" se debe indicar que los "bits de relleno" son ceros siempre y cuando el valor que se desplaze sea un tipo entero sin signo. Por ejemplo:
| Código: | 255U >> 4 /* El resultado es 15 */ |
En caso de que el desplazamiento se efectue sobre un valor entero con signo depende de la implementacion si los bits de relleno son ceros o unos. Por ejemplo:
| Código: | -1 >> 4 /* No se puede predecir el resultado */ |
Tambien hay que indicar que el rango valido para el desplazamiento va desde 0 hasta (sizeof(int) * CHAR_BIT) - 1.
-------------------------------------------------------------------- * Error:
En el unico ejemplo sobre el operador de desplazamiento a la derecha (">>") la operacion no es la correcta, el codigo fuente de ese ejemplo deberia ser:
| Código: | #include <stdio.h>
int main(void) { printf("El resultado de 150U >> 2 es %u\n", 150U >> 2); return 0; } |
-------------------------------------------------------------------- * Ortografia:
En la nota de la seccion "Operador >> (Desplazamiento a la derecha)" la oracion: "NOTA: Un desplazamiento a la izquierda equivale a dividir por dos."
Deberia ser: "NOTA: Un desplazamiento a la derecha equivale a dividir por dos."
-------------------------------------------------------------------- * Error:
En los ejemplos de la seccion "Operador Sizeof" se utiliza el indicador de tipo "%i" para imprimir el resultado del operador sizeof cuando el resultado de este es de tipo size_t.
Ahora bien, lo unico que el estandar de C garantiza sobre este tipo (size_t) es que es un "tipo entero sin signo".
Debido a esto lo mejor que se puede hacer en ISO-C90 para imprimir un valor de este tipo es convertirlo a unsigned long e imprimirlo como tal, por ejemplo:
| Código: | #include <stdio.h>
int main(void) { printf( "Las variables tipo int ocupan %lu bytes\n", (unsigned long) sizeof(int) ); return 0; } |
-------------------------------------------------------------------- * Error:
En el primer ejemplo de la seccion "Orden de evaluación de Operadores" el valor de ambas variables (a y b) esta garantizado y es 6 y 5, respectivamente.
-------------------------------------------------------------------- Nota:
En el tercer ejercicio se declara el array 'palabra' y no se utiliza, seria mejor eliminar esa declaracion. _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 9:25 am; editado 1 vez |
| | Volver arriba | |  | | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 28/05/2006 7:17 am | | | Título: Capitulo 6 -- Introducir datos por teclado |
| Recomendacion:
Ya que este capitulo describe el uso de las funciones scanf, getch y getche se deberia cambiar el parrafo:
"Nosotros en este capítulo vamos a estudiar la primera, usando las funciones de la biblioteca estándar. Pero veamos por encima las otras posibilidades."
A, por ejemplo:
"Nosotros en este capítulo vamos a estudiar la primera opcion (biblioteca estandar) mediante el uso de la funcion scanf y tambien la tercera opcion (bibliotecas de terceros) mediante el uso de las funciones getch y getche. Estas ultimas solo funcionan con los compiladores que soporten la biblioteca conio de Borland."
-------------------------------------------------------------------- Ortografia:
El cuarto parrafo inicia con: "La más coplicada es ..."
Debe cambiarse a: "La más complicada es ..."
-------------------------------------------------------------------- Recomendacion:
La mayoria de los programas y ejercicios de este capitulo utilizan letras acentuadas y esto deberia evitarse ya que el caracter que se presente en pantalla no esta garantizado. Bien podria ser la vocal acentuado o tal vez no.
-------------------------------------------------------------------- Recomendacion:
En los tres primeros ejemplos de este capitulo se utiliza con la funcion scanf el indicador de tipo "%i" para convertir el contenido de la entrada estandar en un numero entero.
Esto puede llevar a ciertos errores logicos debido a que este indicador acepta tanto numeros en base 10 como en base 8 (octal) y 16 (hexadecimal).
Por ejemplo si por accidente (o casualidad) se introduce el numero "0123" este no se interpreta (como es de esperarse) como un numero decimal sino como un numero octal. Por ejemplo el resultado del primer programa es:
| Código: | Introduce un numero 0123 Has tecleado el numero 83 |
Por todo esto me parece mejor utilizar el indicador de tipo "%d" ya que este solo acepta numeros en base 10.
-------------------------------------------------------------------- Nota:
En los tres primeros ejemplos de este capitulo se utiliza la funcion printf para enviar el texto "Introduce ..." a la salida estandar. Debido a que esta cadena no termina con el caracter '\n' no se puede tomar por garantizado que el texto se envie inmediatamente a stdout.
Para estar seguros de que esto asi suceda debemos utilizar:
Inmediatamente despues de la llamada a printf.
Por lo mismo seria recomendable mover la introduccion y descripcion de la funcion fflush inmediatamente despues del primer ejemplo de este capitulo.
-------------------------------------------------------------------- Nota:
En los ejemplos sobre las funciones getch y getche:
1) Falta la directiva:
| Código: | #include <conio.h> |
2) La variable "letra" utilizada para almacenar el valor de retorno de las funciones getch y getche se declara como tipo "char" cuando deberia ser de tipo "int". _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 9:32 am; editado 1 vez |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 15/07/2006 9:03 am | | | Título: Capitulo 7 -- Sentencias de control de flujo |
| * Recomendacion:
Algunos de los programas de ejemplo de este capitulo incluyen caracteres que no forman parte del juego de caracteres ASCII como vocales acentuadas. Debido a que no esta garantizado que estos caracteres se impriman "correctamente" seria mejor evitar su uso.
-------------------------------------------------------------------- * Ortografia:
En el unico parrafo de la primera seccion ("Introduccion") hay un punto de mas:
"Comenzaban por la primera instrucción y acababan por la última, ejecutándose todas una sola vez. ."
Deberia ser:
"Comenzaban por la primera instrucción y acababan por la última, ejecutándose todas una sola vez."
-------------------------------------------------------------------- * Recomendacion:
En todos los ejemplos de este capitulo falta indicar el valor de retorno de la funcion "main" mediante la palabra reservada "return".
Estos ejemplos deberian modificarse a, por poner un ejemplo con los dos primeros programas localizados en la seccion "Bucles":
Primer programa:
| Código: | #include <stdio.h>
int main(void) { printf("Hola\n"); /* 1 */ printf("Hola\n"); /* 2 */ printf("Hola\n"); /* 3 */ /* ... (y así hasta 100 veces) */ return 0; }
|
Segundo programa:
| Código: | #include <stdio.h>
int main(void) { int i; for (i = 0; i < 100; i++) printf("Hola\n"); return 0; }
|
-------------------------------------------------------------------- * Recomendacion:
Al final de la seccion "El bucle For" se indica que todas las secciones de este tipo de bucle pueden omitirse:
"Se puede omitir cualquiera de las secciones (inicialización, condiciones o incrementos)."
Seria bueno extender esta descripcion indicando que en caso de omitirse la condicion este bucle se toma como un bucle infinito, por poner un ejemplo:
"Se puede omitir cualquiera de las secciones (inicialización, condiciones o incrementos). En caso de omitirse la condicion el bucle se ejecuta continuamente sin detenerse, a este tipo de bucle se le conoce como 'endless loop' o 'bucle infinito'."
-------------------------------------------------------------------- * Nota:
En el primer y unico ejemplo de la seccion "If" se envia mediante la funcion printf una cadena a la salida estandar sin que esta cadena termine con el caracter '\n':
| Código: | printf("Introduce un número "); scanf("%i", &num); |
Esa cadena no esta garantizada a presentarse antes de que se pida el numero en cuestion (mediante la funcion scanf). Para asegurarnos de que esto suceda se debe vaciar el bufer de la salida estandar mediante la funcion fflush:
| Código: | #include <stdio.h>
int main(void) { int num; printf("Introduce un número "); fflush(stdout); scanf("%i", &num); if (num == 10){ printf("El número es correcto\n"); } return 0; }
|
Este error se repite en varios de los programas de ejemplo de las secciones posteriores como "If - Else" e "if else if".
-------------------------------------------------------------------- * Error:
En el primer y unico ejemplo de la seccion "If - Else" hay una comilla doble de mas en la linea:
| Código: | printf ( "Pero si no has escrito un ocho!!!"\n" ); |
El codigo fuente del programa completo deberia ser:
| Código: | #include <stdio.h>
int main(void) { int a; printf("Introduce un numero "); fflush(stdout); scanf("%i", &a); if (a == 8){ printf("El numero introducido era un ocho.\n"); }else { printf("Pero si no has escrito un ocho!!!\n"); } return 0; }
|
-------------------------------------------------------------------- * Error:
En el primer y unico ejemplo de la seccion "if else if" hay dos errores importantes:
El primero es un error logico: considerando la explicacion del programa el primer "else if":
| Código: | else if ( a>10 && a<100 ) |
Deberia utilizar los operadores "mayor o igual que" (el operador '>=') y el operador menor o igual que (el operador '<='):
| Código: | else if (a >= 10 && a <= 100) |
El segundo es un error de sintaxis: una comilla doble de mas en la linea:
| Código: | printf ( "El número está entre 10 y 100"\n" ); |
Despues de realizar las correciones el codigo fuente del programa deberia ser:
| Código: | #include <stdio.h>
int main(void) { int a; printf("Introduce un numero "); fflush(stdout); scanf("%i", &a); if (a < 10){ printf("El numero introducido era menor de 10.\n"); }else if (a >= 10 && a <= 100){ printf("El numero esta entre 10 y 100\n"); }else if (a > 100){ printf( "El numero es mayor que 100\n" ); } printf("Fin del programa\n"); return 0; }
|
-------------------------------------------------------------------- Error:
En la seccion "? (el otro if-else)" justo despues del primer programa de ejemplo, en el parrafo:
"Si el valor que tecleamos al ejecutar es menor que 10 entonces b=1, en cambio si tecleamos un número mayor que 10 'b' será igual a 2."
Deberia ser:
"Si el valor que tecleamos al ejecutar es menor que 10 entonces la variable 'b' sera igual a 1, en cambio si tecleamos un número mayor o igual que 10 'b' será igual a 4."
-------------------------------------------------------------------- Recomendacion:
En la seccion "Notas sobre las condiciones" se deberia indicar de una forma explicita que solo pueden utilizarse como condiciones las expresiones cuyo resultado sea de algun tipo entero como char, int, long, etc., por ejemplo esta expresion no seria valida como una condicion:
Ya que ambos operandos y el resultado de la expresion son de tipo 'double'.
Tambien seria bueno indicar que tambien pueden utilizarse como condiciones las expresiones relacionadas con punteros pero esto se trata mas adelante en el capitulo correspondiente (sobre punteros).
-------------------------------------------------------------------- Error:
En la seccion "Notas sobre las condiciones", casi al final de esta en el parrafo:
"Se pueden poner más de dos condiciones:
if ( a>10 && a<100 && b>200 && b<500 ) /* Se deben cumplir las cuatro condiciones */
Esto se cumple si a está entre 10 y 100 y b está entre 200 y 500."
Tomando en cuenta la descripcion "a está entre 10 y 100 y b está entre 200 y 500" la sentencia if deberia ser:
| Código: | if (a >= 10 && a <= 100 && b >= 200 && b <= 500) |
_________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 9:37 am; editado 1 vez |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 16/07/2006 7:13 am | | | Título: Capitulo 8 -- Introduccion a las Funciones |
| * Recomendacion:
Varios de los programas de ejemplo de este capitulo usan caracteres que no son parte de juego de caracteres ASCII (como las vocales acentuadas) y por lo mismo estos tal vez no se imprimam correctamente.
-------------------------------------------------------------------- * Nota:
Tambien en varios de los programas de ejemplo se envia una cadena de texto a la salida estandar sin que esta termine con el caracter '\n' por lo que no esta garantizado que esta cadena se envie inmediatamente.
La primera ocasion en que esto ocurre es en el segundo ejemplo de este capitulo, dentro de la funcion "main":
| Código: | printf("Introduzca dos números: "); scanf("%i %i", &num1, &num2); |
Para asegurarnos de esto debemos vaciar el bufer de la salida estandar mediante la funcion fflush. En el caso antes mencionado la unica modificacion seria:
| Código: | printf("Introduzca dos números: "); fflush(stdout); scanf("%i %i", &num1, &num2); |
-------------------------------------------------------------------- * Ortografia:
Al final del segundo parrafo de la primera seccion " Introducción":
"Ya hemos visto en el curso algunas funciones como printf, gotoxy, scanf y clrscr. Algunas de éstas están definidas en una biblioteca (la biblioteca estándar de C). No tenemos que preocuparnos de ella porque el compilador se encarga de ella automáticamente."
Seria mejor utilizar como ultima oracion:
"Ya hemos visto en el curso algunas funciones como printf, gotoxy, scanf y clrscr. Algunas de éstas están definidas en una biblioteca (la biblioteca estándar de C). No tenemos que preocuparnos de ellas porque el compilador se encarga automáticamente."
-------------------------------------------------------------------- * Error:
En el cuarto parrafo de la seccion "Definición de una función":
"También podemos usar el tipo void. Este nos permite que podamos devolver cualquier tipo de variable o ninguna."
Deberia ser, por ejemplo:
"También podemos usar el tipo void. Este nos permite indicar que la funcion no devuelve ningun valor, cuando este sea el caso la palabra reservada 'return' se utiliza sola, sin ningun valor a continuacion de esta."
-------------------------------------------------------------------- * Nota tecnica:
Estrictamente hablando las funciones pueden ser llamadas ante de su declaracion y definicion, cuando esto ocurre se toma por sentado lo siguiente:
1) La funcion recibe el numero exacto de argumentos indicado por la llamada a funcion. 2) Su valor de retorno es de tipo 'int'.
Si esta conclusion es correcta el programa funcionara sin ningun fallo o error. Por ejemplo en este programa falta el prototipo de la funcion 'system' pero este funciona correctamente debido a que el uso de esta funcion coincide exactamente con su definicion:
| Código: | #include <stdio.h>
int main(void) { puts("Hola, mundo"); /* Genera una pausa en MS Windows */ system("pause"); return 0; }
|
Sin embargo esta practica no es para nada recomendable.
-------------------------------------------------------------------- * Nota:
En el primer ejemplo de este capitulo falta el valor de retorno de la funcion 'main'.
-------------------------------------------------------------------- * Recomendacion:
Para evitar "malos habitos" seria bueno que en este capitulo se hiciera especial enfasis en la forma "politicamente correcta" de estructurar un programa que incluya funciones colocando primero todas las directivas del preprocesador que sean necesarias, esto seguido de los prototipos de las funciones y por ultimo la definicion de estas sin importar su orden.
Un ejemplo de esta aproximacion utilizando el primer ejemplo de este capitulo:
| Código: | #include <stdio.h> #include <conio.h>
/* Prototipo o 'firma' de la funcion */ void prepara_pantalla(void);
int main(void) { prepara_pantalla(); /* Llamamos a la función */ return 0; }
/* Definicion de la funcion */ void prepara_pantalla(void) { clrscr(); printf("La pantalla está limpia\n"); /* ** No hace falta devolver ningún valor, ** mucha gente ni siquiera pone este return */ return; }
|
-------------------------------------------------------------------- * Error logico:
En el segundo ejemplo de este capitulo el bloque if .. else en la funcion 'compara':
| Código: | if (a > b) printf("%i es mayor que %i\n" , a, b); else printf("%i es mayor que %i\n", b, a);
|
Deberia ser:
| Código: | if (a > b) printf("%i es mayor que %i\n" , a, b); else if (b > a) printf("%i es mayor que %i\n", b, a); else printf("%i es igual que %i\n", a, b);
|
Tambien hay que hacer notar que no es necesario incluir el header conio, en otras palabras esta linea seria mejor eliminarla:
| Código: | #include <conio.h> |
-------------------------------------------------------------------- * Error:
En la funcion 'main' del tercer ejemplo faltan los operadores 'direccion de' (el caracter '&') en la llamada a scanf:
| Código: | scanf("%i %i", num1, num2); |
Deberia ser:
| Código: | scanf("%i %i", &num1, &num2); |
Aqui tambien se deberia eliminar la linea:
| Código: | #include <conio.h> |
-------------------------------------------------------------------- * Ortografia:
El tercer parrafo de la seccion "Dónde se definen las funciones": "Esto nos permite luego poner las fucniones en cualquier orden. Ejemplos:"
Deberia ser: "Esto nos permite luego poner las funciones en cualquier orden. Ejemplos:"
-------------------------------------------------------------------- *Error:
En el primer y unico ejemplo de la seccion "Dónde se definen las funciones" hay dos errores importantes.
El primero es declarar a la funcion 'compara' con un tipo de retorno 'void':
| Código: | void compara( int a, int b ); |
Deberia ser:
| Código: | int compara(int a, int b); |
El segundo es la falta del operador 'direccion de' (el '&') al llamar a la funcion scanf:
| Código: | scanf("%i %i", num1, num2); |
Deberia ser:
| Código: | scanf("%i %i", &num1, &num2); |
Tambien se deberia eliminar esta linea ya que no es necesaria:
| Código: | #include <conio.h> |
_________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 9:44 am; editado 1 vez |
| | Volver arriba | |  | | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 16/07/2006 11:57 pm | | | Título: Capitulo 9 -- Punteros |
| * Recomendacion:
En los programas de ejemplo de este capitulo falta indicar el valor de retorno de la funcion "main" y tambien se utilizan caracteres que no forman parte del juego de caracteres ASCII (vocales acentuadas).
-------------------------------------------------------------------- * Recomendacion:
En el segundo parrafo de la seccion "Direcciones de variables":
"Por ejemplo si declaramos un char, el ordenador nos reserva 1 byte (8 bits)."
Si bien usualmente un caracter (char) esta constituido por ocho bits esto no lo garantiza el estandar (el numero exacto esta dado por la macro CHAR_BIT) y por lo mismo seria mejor cambiar esa linea a:
"Por ejemplo si declaramos un char, el ordenador nos reserva 1 byte (usualmente 8 bits)."
-------------------------------------------------------------------- * Error:
Al llamar a la funcion printf el indicador de tipo "%p" se utiliza para imprimir un valor de tipo "void *". Debido a esto cuando se llama a esa funcion para imprimir el valor de un puntero este debe ser convertido al tipo "void *" mediante una conversion explicita o casting.
Este casting falta en todos los programas de ejemplo de este capitulo. Por poner un ejemplo, el primer programa de ejemplo seria, una vez realizados los cambios necesarios:
| Código: | #include <stdio.h>
int main(void) { int a; a = 10; printf("Direccion de a = %p, valor de a = %i\n", (void *) &a, a); return 0; }
|
-------------------------------------------------------------------- * Error:
En la seccion "Que son los punteros":
"El * (asterisco) sirve para indicar que se trata de un puntero, debe ir justo antes del nombre de la variable, sin espacios."
Deberia ser:
"El * (asterisco) sirve para indicar que se trata de un puntero, debe ir justo antes del nombre de la variable."
Esto debido a que el lenguaje C es un lenguaje de "formato libre" y la declaracion de la variable "punt" podria realizarse en cualquiera de estas formas, todas ellas validas:
| Código: | int* punt;
/* -O- */
int * punt;
/* -O- */
int *punt;
/* -O- */
int*punt;
/* -O- */
int * punt; |
-------------------------------------------------------------------- * Error logico:
En el segundo programa de ejemplo de la seccion "Punteros como argumentos de funciones" se imprime el mensaje de texto mediante printf:
| Código: | printf("La suma es: %i y a vale: %i\n", resultado, var1); |
Deberia ser:
| Código: | printf("La suma es: %i y var1 vale: %i\n", resultado, var1); |
-------------------------------------------------------------------- * Ortografia:
Al final de la seccion "Punteros como argumentos de funciones":
"Es posible que primero almacene el varlor de var1 antes de evaluar suma."
Deberia ser:
"Es posible que primero almacene el valor de var1 antes de evaluar suma."
-------------------------------------------------------------------- * Ortografia:
En la seccion "Ejercicios":
"..., al darle un valor estamos encribiendo en un lugar desconocido de la memoria."
Deberia ser:
"..., al darle un valor estamos escribiendo en un lugar desconocido de la memoria." _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 9:57 am; editado 3 veces |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 30/07/2006 5:06 pm | | | Título: Capitulo 10 -- Arrays (Matrices) |
| Recomendacion:
En todos los ejemplos de este capitulo falta indicar el valor de retorno de la funcion "main".
-------------------------------------------------------------------- Ortografia:
En la seccion "¿Que es un array?", en el tercer parrafo despues del primer ejemplo:
| Cita: | | En ejemplo recorremos la matriz mediante un bucle for y vamos ... |
Deberia ser:
| Cita: | | En este ejemplo recorremos la matriz mediante un bucle for y vamos ... |
O tal vez:
| Cita: | | En el ejemplo anterior recorremos la matriz mediante un bucle for y vamos ... |
-------------------------------------------------------------------- Recomendacion:
En la seccion "Inicializar un array" se introduce el concepto de "listas de valores" en la forma:
| Código: | tipo_del_array array[N] = {A, B, C}; |
Seria bueno aclarar que estas listas solo pueden consistir de valores literales como, por poner un ejemplo:
| Código: | int array[3] = {1, 2, 3}; |
y constantes simbolicas definidas mediante la directiva "define":
| Código: | #define ELEMENTOS 24
...
int array[3] = {1, ELEMENTOS, 3}; |
-------------------------------------------------------------------- Error:
En el tercer ejemplo de la seccion "Inicializar un array" se procesan 24 elementos cuando el cambio en la declaracion del array lo deja a este solo con 21 elementos.
La forma mas sencilla de corregir este error es utilizando la lista de valores del primer programa de ejemplo de la seccion, lo que resultaria en este programa:
| Código: | #include <stdio.h>
int main(void) { int hora; int temperaturas[] = { 15, 18, 20, 23, 22, 24, 22, 25, 26, 25, 24, 22, 21, 20, 18, 17, 16, 17, 15, 14, 14, 14, 13, 12 }; for (hora = 0; hora < 24; hora++) printf( "La temperatura a las %i era de %i grados.\n", hora, temperaturas[hora]); return 0; }
|
-------------------------------------------------------------------- Error:
En el ultimo programa de ejemplo de la seccion " Inicializar un array", en la primera llamada a la funcion printf esta mal escrito el nombre de variable "temperaturas":
| Código: | printf("La temperatura a las %i era de %i grados.\n", hora, temperas[hora]); |
Deberia ser:
| Código: | printf("La temperatura a las %i era de %i grados.\n", hora, temperaturas[hora]); |
-------------------------------------------------------------------- Error:
En el primer ejemplo de la seccion "Recorrer un array" se deberia eliminar el comentario:
| Código: | /* Faltan los tres últimos elementos */ |
Ya que el array se declara e inicializa correctamente (es el comentario el que esta errado).
-------------------------------------------------------------------- Error:
En el primer ejemplo de la seccion "Punteros a arrays" para imprimir la direccion en memoria de cada uno de los elementos del array se debe convertir explicitamente el puntero resultante al tipo "void *".
En otras palabras la llamada a la funcion printf:
| Código: | printf("La dirección del elemento %i es %p.\n", i, &temp[i]); |
Se debe cambiar a:
| Código: | printf("La dirección del elemento %i es %p.\n", i, (void *) &temp[i]); |
-------------------------------------------------------------------- Error:
En el segundo ejemplo de la seccion "Punteros a arrays" cuando se llama a la funcion printf se deben convertir explicitamente los dos punteros al tipo "void *".
La linea:
| Código: | printf("La dirección de temp[%i] es %p y la de punt es %p.\n", i, &temp[i], punt); |
Deberia cambiarse a:
| Código: | printf("La dirección de temp[%i] es %p y la de punt es %p.\n", i, (void *) &temp[i], (void *) punt); |
-------------------------------------------------------------------- Recomendacion:
En el tercer y cuarto ejemplo de la seccion "Punteros a arrays" seria mejor cambiar la definicion de la funcion "main" de:
| Código: | int main(int argc,char *argv[]) { /* ... */ }
|
A:
| Código: | int main(void) { /* ... */ }
|
Ya que los argumentos de la linea de comandos no se utilizan en esos dos programas. _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 10:01 am; editado 1 vez |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 31/07/2006 4:57 am | | | Título: Capitulo 11 -- Arrays Multidimensionales |
| * Recomendacion:
El segundo programa de este capitulo utiliza acentos y estos caracteres no estan garantizados a imprimirse correctamente.
-------------------------------------------------------------------- * Nota tecnica:
Cuando se declara un array de arrays (mejor conocido como array bidimensional o matriz), por ejemplo:
Los elementos de este tipo de array pueden inicializarse de dos formas ligeramente distintas (y funcionales) utilizando listas de valores.
La primera consiste en utilizar una sola lista de valores, siguiendo nuestro ejemplo:
| Código: | int tabla[4][3] = { 1, 2, 3, 11, 12, 13, 21, 22, 23 }; |
En este caso la lista de valores se utiliza para inicializar todos los elementos de la primera fila, despues la segunda fila, despues la tercera fila y asi sucesivamente. Si la lista contiene menos valores de los necesarios los elementos faltantes se inicializan con el valor 0:
| Código: | tabla[0][0] tiene el valor 1 tabla[0][1] tiene el valor 2 tabla[0][2] tiene el valor 3 ... tabla[2][2] tiene el valor 23 |
Debido a que esta lista solo contiene 9 valores los elementos restantes, esto es, tabla[3][0] hasta tabla[3][2] se inicializan con el valor 0:
| Código: | tabla[3][0] tiene el valor 0 tabla[3][1] tiene el valor 0 tabla[3][2] tiene el valor 0 |
La segunda forma es la que se describe en el curso y consiste en una lista "doble". Siguiendo nuestro ejemplo:
| Código: | int tabla[4][3] = { { 1, 2}, {11, 12}, {21, 22}, {31, 32} }; |
En este caso los valores de la primera lista se utilizan para inicializar la primera fila, los valores de la segunda lista se utilizan para inicializar la segunda fila, los valores de la tercera lista se utilizan para inicializar los elementos de la tercera fila y asi sucesivamente. Si alguna lista contiene menos valores de los necesarios los elementos faltantes de la fila se inicializan a 0.
En este ejemplo cada "sub-lista" solo contiene dos elementos lo que produce como resultado que el tercer elemento de cada fila se inicialize automaticamente a 0:
| Código: | tabla[0][0] tiene el valor 1 tabla[0][1] tiene el valor 2 tabla[0][2] tiene el valor 0
...
tabla[3][0] tiene el valor 31 tabla[3][1] tiene el valor 32 tabla[3][2] tiene el valor 0 |
_________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 10:06 am; editado 1 vez |
| | Volver arriba | |  | | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 16/09/2006 7:56 am | | | Título: Capitulo 12 -- Strings (Cadenas de texto) |
| Nota tecnica y recomendacion:
En la primera seccion "Introducción" se deberia enfatizar la diferencia entre un array de caracteres y una cadena:
Un array de caracteres como este:
Puede utilizarse para varios fines dependiendo por supuesto del programa donde se utilize, uno de los usos mas comunes de un array de caracteres como este es servir como contenedor de una cadena.
Por otra parte una cadena es una secuencia de cero o mas caracteres seguidos del caracter '\0'. Si bien este caracter (el '\0') no se considera parte de la cadena de texto debe existir para delimitarla o, en otras palabras, indicar donde termina la cadena.
De nuevo se debe resaltar la diferencia entre contenedor (array de caracteres) y contenido (cadena de texto).
-------------------------------------------------------------------- Recomendacion:
En algunos de los ejemplos de este capitulo se utilizan caracteres que no forman parte del juego de caracteres ASCII, estos caracteres deberian evitarse.
Tambien todos los ejemplos de este capitulo les falta indicar el valor de retorno de la funcion "main". Esto puede solucionarse con solo agregar:
Como ultima linea de esa funcion.
-------------------------------------------------------------------- Nota tecnica:
El operador sizeof y algunas funciones de la biblioteca estandar de C como strlen devuelven un valor de tipo size_t y la impresion de un valor de este tipo es problematica debido a que lo unico que podemos tomar por garantizado es que size_t es un tipo entero sin signo. Este puede ser en realidad cualquiera de estos tipos:
unsigned short int unsigned int unsigned long int
Y esto es algo que depende de la implementacion.
Para imprimir un valor de tipo size_t una aproximacion posible es convirtiendo el valor mediante una conversion explicita o casting al tipo "unsigned long int":
| Código: | char cadena[] = "Texto de prueba";
/* ... */
printf("Capacidad: %lu\n", (unsigned long) sizeof cadena); |
-------------------------------------------------------------------- Recomendacion:
En el tercer ejemplo de este capitulo se define a la funcion "main" en la forma:
| Código: | int main(int argc, char *argv[]) { /* ... */ } |
Ya que los argumentos de la linea de comandos no se utilizan seria mejor utilizar la forma:
| Código: | int main(void) { /* ... */ } |
-------------------------------------------------------------------- Error:
En el primer ejemplo de la funcion strlen el valor de retorno de esta funcion se almacena en una variable de tipo "int" cuando deberia ser de tipo "size_t".
-------------------------------------------------------------------- Ortografia:
En el parrafo a continuacion del primer ejemplo sobre strcpy:
"Además en este ejemplo vemos que la cadena origen es sustituida por la cadena destino totalmete."
Deberia ser:
"Además en este ejemplo vemos que la cadena origen es sustituida por la cadena destino totalmente."
-------------------------------------------------------------------- Error:
En la seccion "toupper() y tolower() - Convertir a mayúsculas y minúsculas" la descripcion de estas funciones no es correcta: estas funciones permiten convertir a mayusculas (toupper()) y minusculas (tolower()) un unico caracter.
Sus prototipos se encuentran en ctype.h y estos son:
| Código: | int toupper(int ch); int tolower(int ch); |
El valor de retorno de estas funciones es el caracter 'ch' en mayusculas/minusculas o el caracter 'ch' sin cambio alguno si este no es un caracter alfabetico.
-------------------------------------------------------------------- Error:
En el primer ejemplo de la seccion "Qué son los buffer y cómo funcionan" los arrays "apellido" y "telefono" no se utilizan y debido a esto seria mejor eliminarlos.
-------------------------------------------------------------------- Error:
En el segundo ejemplo de la seccion "Qué son los buffer y cómo funcionan" el array "telefono" no se utiliza y por lo mismo seria mejor eliminarlo.
-------------------------------------------------------------------- Nota:
En el ejemplo de la seccion "Arrays de cadenas" falta incluir el archivo de inclusion o header <stdlib.h> ya que en este se encuentra el prototipo de la funcion exit.
-------------------------------------------------------------------- Error:
En el unico ejemplo de la seccion "Ordenar un array de cadenas" el bucle interno tiene un error en la inicializacion de la variable "j" (j = 0), esta deberia ser "j = i + 1":
| Código: | for (i = 0; i < ELEMENTOS-1; i++) for (j = i + 1; j < ELEMENTOS; j++) if (strcmp(dichos[i], dichos[j]) > 0){ temp = dichos[i]; dichos[i] = dichos[j]; dichos[j] = temp; } |
-------------------------------------------------------------------- Nota:
En las dos soluciones de la seccion "Ejercicios" falta incluir el archivo de inclusion o header <stdlib.h> ya que en este se encuentra el prototipo de la funcion system. _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 10:14 am; editado 2 veces |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 18/09/2006 6:26 am | | | Título: Capitulo 13 -- Funciones (Avanzado) |
| Recomendacion:
En el primer ejemplo falta indicar el valor de retorno de la funcion main. Esto se soluciona colocando como ultima linea de esta funcion la sentencia:
-------------------------------------------------------------------- Error y recomendacion:
En el segundo ejemplo falta indicar el valor de retorno de la funcion main y tambien existe la posibilidad de que el programa reviente en caso de que no se pasen los argumentos necesarios. El programa se podria modificar para que tuviera en cuenta esta posibilidad a, por poner un ejemplo:
| Código: | #include <stdio.h> /* printf */ #include <stdlib.h> /* atoi y EXIT_SUCCESS */
int main(int argc,char *argv[]) { int par1, par2; if (argc == 3){ par1 = atoi(argv[1]); par2 = atoi(argv[2]); printf("%d + %d = %d\n", par1, par2, par1 + par2); } return EXIT_SUCCESS; /* "salida con exito" del programa */ }
|
_________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language
Ultima edición por rir3760 el 26/11/2006 10:16 am; editado 1 vez |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 7516 Ubicación: Mexico
| Publicado: 16/11/2006 7:39 am | | | Título: Capitulo 14 -- Estructuras |
| Nota:
Los ejemplos de este capitulo utilizan caracteres que no forman parte del juego de caracteres ASCII como las vocales acentuadas, seria mejor evitar el uso de estos caracteres ya que su disponibilidad no esta garantizada (depende del entorno de ejecucion).
Tambien falta el valor de retorno de la funcion "main", si bien tecnicamente esto no es un error el resultado es un programa cuyo valor de retorno es "no definido".
-------------------------------------------------------------------- Error:
En el primer ejemplo de este capitulo, en las tres llamadas a la funcion scanf no se debe utilizar el operador "direccion de" (el '&') ya que al ser arrays los tres campos estos generan el puntero de forma automatica.
-------------------------------------------------------------------- Ortografia:
En el primer parrafo de la seccion " Punteros a estructuras":
"La diferencia está en que al declara la variable de tipo estructura debemos ponerle el operador '*' para indicarle que es un puntero."
Deberia ser:
"La diferencia está en que al declarar la variable de tipo estructura debemos ponerle el operador '*' para indicarle que es un puntero. "
Y en el parrafo inmediatamente despues del cuarto ejemplo del capitulo:
"Has la definición del puntero p_amigo vemos que todo era igual que antes."
Deberia ser:
"Hasta la definición del puntero p_amigo vemos que todo era igual que antes."
-------------------------------------------------------------------- Nota:
En los dos ejemplos de la seccion "Paso de estructuras a funciones" es recomendable incluir el header <stdlib.h> antes de llamar a la funcion "system".
-------------------------------------------------------------------- Error:
En el apartado "Pasar sólo miembros de la estructura" de la seccion "Paso de estructuras a funciones" se comenta e indica que el campo "edad" es de tipo char cuando en el primer ejemplo de esa seccion este campo se declara como tipo int. _________________ C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. -- Kernighan & Ritchie, The C programming language |
| | Volver arriba | |  | | |
| No puede crear mensajes No puede responder temas No puede editar sus mensajes No puede borrar sus mensajes No puede votar en encuestas
|
|
| |