Herramientas de usuario

Herramientas del sitio


principios

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
principios [2020/03/09 22:34] – [Ejemplo de programa en C] lmateuprincipios [2022/09/27 13:01] (actual) – [Agrupación de instrucciones] lmateu
Línea 56: Línea 56:
   * Un archivo fuente escrito en el lenguaje C debe llevar la extensión '.c'.   * Un archivo fuente escrito en el lenguaje C debe llevar la extensión '.c'.
   * A partir de C99 un comentario se inicia con %%'//'%% y se extiende hasta el final de la línea.   * A partir de C99 un comentario se inicia con %%'//'%% y se extiende hasta el final de la línea.
-  * El estilo antiguo de los comentarios (antes de C99) sigue siendo válido y se inician con /* y terminan con */.  Pueden extenderse por varias líneas.  Algunos ejemplo en estos apuntes usan ese antiguo estilo.+  * El estilo antiguo de los comentarios (antes de C99) sigue siendo válido y se inician con /* y terminan con */.  Pueden extenderse por varias líneas.  Algunos ejemplos en estos apuntes usan ese antiguo estilo.
   * Las líneas con //#include// cumplen el mismo propósito que los import de Python.  Indican el nombre de un archivo de encabezados.  Por ejemplo //stdio.h// se necesita para poder usar la función //printf// y //stdlib.h// para usar la función //atoi// La extensión .h viene de header (encabezado).  No se preocupe, el compilador sabrá donde encontrar los archivos de encabezado.   * Las líneas con //#include// cumplen el mismo propósito que los import de Python.  Indican el nombre de un archivo de encabezados.  Por ejemplo //stdio.h// se necesita para poder usar la función //printf// y //stdlib.h// para usar la función //atoi// La extensión .h viene de header (encabezado).  No se preocupe, el compilador sabrá donde encontrar los archivos de encabezado.
   * En el archivo se define la función //main//, pero se pueden definir múltiples funciones, una a continuación de la otra.   * En el archivo se define la función //main//, pero se pueden definir múltiples funciones, una a continuación de la otra.
-  * Al ejecutar un programa la primera función que se ejecuta es siempre la función //main//. +  * Al ejecutar un programa la primera función que se invoca es siempre la función //main//. 
-  * El compilador ignora los espacios en blanco, tabs y cambios de línea.  Agréguelos para hacer más legible el programa.  Al contrario de Python la indentación no le indica al compilador la estructura del programa.  Veremos que son las llaves { } son las que definen la estructura del programa.  Pero por legibilidad del programa, es importante que la estructura que entregan las llaves sea consistente con la estructura que sugiere la indentación.+  * El compilador ignora los espacios en blanco, tabs y cambios de línea.  Agréguelos para hacer más legible el programa.  Al contrario de Python la indentación no le indica al compilador la estructura del programa.  Veremos que son las llaves { } las que definen la estructura del programa.  Pero por legibilidad del programa, es importante que la estructura que entregan las llaves sea consistente con la estructura que sugiere la indentación.
  
 ===== El sistema de tipos de C ===== ===== El sistema de tipos de C =====
  
-El lenguaje C posee tipos estáticos.  Esto significa que todas las variables y expresiones poseen un tipo que acota los valores que pueden tomar.  Al contrario, Python posee tipos dinámicos y por lo tanto una variable puede almacenar cualquier tipo de valor.  Los tipos más básicos de C son:+El lenguaje C posee tipos //estáticos//.  Esto significa que para cada variable hay que indicar explícitamente su tipo, el que acota los valores que puede tomar esa variable.  Si una variable es de tipo //int// entonces solo puede almacenar un entero como 0, 3, -5, etc.  No podrá almacenar el real 3.14 o el string "hola que tal".  Al contrario, Python posee tipos //dinámicos// y por lo tanto una variable puede almacenar cualquier tipo de valor.  Algunos tipos muy usados en C son:
  
-  * //int// para los números enteros +  * //int// para los números enteros: 0, 3, -5, etc. 
-  * //char// para enteros pequeños que usualmente corresponden a la codificación en ascii de un caracter +  * //char// para enteros pequeños que usualmente corresponden a la codificación en ascii de un caracter: 'a', '4', '*', '\n', etc.  La notación 'a' significa la codificación en ascii de la letra a y corresponde al entero 97.  El caracter especial \n corresponde al cambio de línea (line feed) y en ascii se representa con el entero 10. 
-  * //double// para números reales +  * //char*// para strings: "hola que tal", "123", "+-*", etc. 
-  * //void// se usa para indicar que una función no entrega ningún valor+  * //double// para números reales: 3.14, 2.71, 1.0, -300.2, 10.3e6, etc. 
 +  * //void// se usa para indicar que una función no entrega ningún valor.
  
-Los tipos dinámicos de Python le otorgan flexibilidad y comodidad.  En cambio los tipos estáticos de C lo hacen eficiente en tiempo de ejecución y además hace que los programas en C sean más fáciles de entender y modificar.+En C también existen los arreglos.  Por ejemplo int[] es el tipo de los arreglos de C y char*[] es el tipo de los arreglos de strings. 
 + 
 +Los tipos dinámicos de Python le otorgan flexibilidad y comodidad.  En cambio los tipos estáticos de C (y también Java) lo hacen eficiente en tiempo de ejecución y además hace que los programas en C sean más fáciles de entender y modificar.
  
 ===== Formato de una función en C ===== ===== Formato de una función en C =====
Línea 77: Línea 80:
 Su formato es: //tipo// //nombre// ( //parámetros// ) { //instrucciones// } Su formato es: //tipo// //nombre// ( //parámetros// ) { //instrucciones// }
  
-  * //tipo// es el tipo de los valores que retorna la función.  Usualmente //int//, //char//, //double// o //void//.+  * //tipo// es el tipo de los valores que retorna la función.  Usualmente //int//, //char//, //char*//, //double// o //void//.
   * //parámetros// indica los parámetros que recibe la función separados por coma.  Cada parámetro viene en el formato: //tipo// //variable//.   * //parámetros// indica los parámetros que recibe la función separados por coma.  Cada parámetro viene en el formato: //tipo// //variable//.
-  * //instrucciones// son una o más instrucciones, una seguida de la otra.  Para ejecutar una función, C ejecuta secuencialmente las instrucciones.+  * //instrucciones// son 0, 1, 2 o más instrucciones.  Para ejecutar una función, C ejecuta secuencialmente las instrucciones.
  
 Por ejemplo el formato para //main//, exceptuando las instrucciones, es: Por ejemplo el formato para //main//, exceptuando las instrucciones, es:
  
 <code C> <code C>
-int main(int argc, char **argv) {+int main(int argc, char *argv[]) {
   ... etc. ...   ... etc. ...
 } }
Línea 90: Línea 93:
  
  
-La función //main// recibe los parámetros //argc// y //argv// Tome esto como un receta por ahora.  El tipo de //argc// es //int// y el de //argv// es //char//%%**%%.  Durante el curso se explicará esto.+La función //main// recibe los parámetros //argc// y //argv// Tome esto como un receta por ahora.  El tipo de //argc// es //int// y el de //argv// es //char//%%*[]%% (arreglo de strings).  Durante el curso se explicará esto.
  
 C posee instrucciones simples como la asignación e instrucciones compuestas como los ciclos, los if/then/else y los grupos de instrucciones encerradas con llaves { }. C posee instrucciones simples como la asignación e instrucciones compuestas como los ciclos, los if/then/else y los grupos de instrucciones encerradas con llaves { }.
Línea 104: Línea 107:
 Su sintaxis es: //tipo// //nombre// = //expresión// ; Su sintaxis es: //tipo// //nombre// = //expresión// ;
  
-//Tipo// especifica el tipo de los valores que almacena la variable.  //Nombre// es el identificador de la variable.  En //expresión// se pueden usar los operadores aritméticos típicos (+ - * /) e incluso invocar otras funciones (siempre y cuando no retornen void).  La parte //= expresión// es opcional.+//Tipo// especifica el tipo de los valores que almacena la variable.  //Nombre// es el identificador de la variable.  La parte //= expresión// es opcional y especifica el valor inicial de la variable.  En //expresión// se pueden usar los operadores aritméticos típicos (+ - * /) e incluso invocar otras funciones (siempre y cuando no retornen void).
  
 En el ejemplo se declara la variable //prev// de tipo //int// con valor inicial 0: En el ejemplo se declara la variable //prev// de tipo //int// con valor inicial 0:
Línea 154: Línea 157:
 Algunas funciones son de tipo void, es decir no retornan ningún valor y por lo tanto no tiene sentido invocarlas como parte de una asignación.  Para invocarlas se usa esta sintaxis: Algunas funciones son de tipo void, es decir no retornan ningún valor y por lo tanto no tiene sentido invocarlas como parte de una asignación.  Para invocarlas se usa esta sintaxis:
  
-//nombre// ( //argumento_1//, //argumento_2//, ... )+//nombre// ( //argumento_1//, //argumento_2//, ... ) ;
  
 En donde //argumento_1//, //argumento_2//, ... son expresiones.  Por ejemplo: En donde //argumento_1//, //argumento_2//, ... son expresiones.  Por ejemplo:
Línea 163: Línea 166:
 </code> </code>
  
-Acá la función se llama //printf// (print formatted) y cumple el mismo propósito que //print// en //Python// Es una función especial en C porque recibe un número variable de argumentos.  En el primer ejemplo recibe un solo argumento que corresponde al string que se desea desplegar en pantalla.  En el segundo ejemplo recibe 3 argumentos. +Acá la función se llama //printf// (print formatted) y cumple el mismo propósito que //print// en //Python// Es una función especial en C porque recibe un número variable de argumentos.  En el primer ejemplo recibe un solo argumento que corresponde al string que se desea desplegar literalmente en pantalla.  En el segundo ejemplo //printf// recibe 3 argumentos.  El primer parámetro de //printf// es siempre el formato.  Debe ser un string que se despliega casi literalmente.  Digo casi, porque la función examina el string buscando el caracter %, dándole un significado especial: el primer %d se reemplaza por el valor de la variable //i// y el segundo %d se reemplaza por el valor de //next// Entonces cuando //i// es 6 y //next// es 8 se reemplaza el primer %d por 6 y el segundo %d por 8 desplegando //f6= 8//.
- +
-El primer parámetro de //printf// es siempre el formato.  Debe ser un string que se despliega casi literalmente.  Digo casi, porque la función examina el string buscando el caracter especial %, dándole un significado especial: el primer %d se reemplaza por el valor de la variable //i// y el segundo %d se reemplaza por el valor de //next// Entonces cuando //i// es 6 y //next// es 8 se reemplaza el primer %d por 6 y el segundo %d por 8 desplegando //f6= 8//.+
  
 En realidad en C la invocación de función es válida porque es válida cualquier instrucción con la sintaxis: //expresión// ; En realidad en C la invocación de función es válida porque es válida cualquier instrucción con la sintaxis: //expresión// ;
  
-De hecho la asignación también es un caso particular de esa sintaxis por = se considera un operador como + y *.+De hecho la asignación también es un caso particular de esa sintaxis porque = se considera un operador como + y *.
  
 ==== Retorno de función ==== ==== Retorno de función ====
  
-Para terminar la ejecución de una función se usa la instrucción return, que usa la siguiente sintaxis:+Para terminar la ejecución de una función se usa la instrucción //return//, que usa la siguiente sintaxis:
  
 **return** //expresión// ; **return** //expresión// ;
  
-El valor retornado es el resultado de evaluar la expresión.  No es necesario que sea la última instrucción de la función, pero cuando se ejecuta //return//, las instrucciones que vienen a continuación no se ejecutarán.+El valor retornado es el resultado de evaluar la expresión.  No es necesario que sea la última instrucción de la función, pero cuando se ejecuta //return//, las instrucciones que vienen a continuación no se ejecutarán.  Por eso nunca verá instrucciones después del //return//, a menos que el //return// sea una de las ramas de un //if//.
  
 ===== Instrucciones compuestas ===== ===== Instrucciones compuestas =====
  
-Se forman a partir de una o más instrucciones (simples o compuestas).  Pueden ser ciclos while, do while, for, o condicionales if/then/else o agrupación de instrucciones con { }.+Se forman a partir de una o más instrucciones (simples o compuestas).  Pueden ser ciclos while, for, o condicionales if/then/else o agrupación de instrucciones con { }.
  
 ==== Ciclo while ==== ==== Ciclo while ====
Línea 195: Línea 196:
 </code> </code>
  
-El último valor que tomará a es 128 porque cuando a sea mayor o igual que 100, ya no se ejecutará la instrucción a=a*2;+El último valor que tomará //a// es 128porque cuando a sea mayor o igual que 100, ya no se ejecutará la instrucción a=a*2;
  
 Observe que la indentación no indica cuantas instrucciones están dentro del while.  Siempre es una sola instrucción.  En el siguiente ejemplo la instrucción a=a+1 está fuera del ciclo: Observe que la indentación no indica cuantas instrucciones están dentro del while.  Siempre es una sola instrucción.  En el siguiente ejemplo la instrucción a=a+1 está fuera del ciclo:
Línea 244: Línea 245:
 </code> </code>
  
-El estilo de la izquierda sí se usa ampliamente y es legible.  El estilo del medio casi no se usa.  El estilo de la derecha es horrible y merece la reprobación.  El principio de la indentación es hacer los programas más legibles.  Pueden haber muchos estilos bonitos y legibles, pero si cada alumno usa estilos distintos, será más dificil que el equipo docente entienda sus programas y por lo tanto podrían recibir una calificación injusta porque no se entiendó su programa.  Por ello urge acordar un solo estilo y este será el de Kernighan.+El estilo de la izquierda sí se usa ampliamente y es legible.  El estilo del medio casi no se usa.  El estilo de la derecha es horrible y merece la reprobación.  El principio de la indentación es hacer los programas más legibles.  Pueden haber muchos estilos bonitos y legibles, pero si cada alumno usa estilos distintos, será más difícil que el equipo docente entienda sus programas y por lo tanto podrían recibir una calificación injusta porque no se entendió su programa.  Por ello urge acordar un solo estilo y este será el de Kernighan.
  
 ==== El ciclo for ==== ==== El ciclo for ====
Línea 297: Línea 298:
  
 Debe realizar el siguiente trabajo personal antes de la segunda clase de este curso (clase del jueves): Debe realizar el siguiente trabajo personal antes de la segunda clase de este curso (clase del jueves):
-estudie y complete los ejercicios de la parte //Learn the Basics// de este [[https://www.learn-c.org/|tutorial del lenguaje C]].  Es un tutorial muy corto y los ejercicios le ayudarán repasar lo visto hasta ahora. +estudie y complete los ejercicios de la parte //Learn the Basics// de este [[https://www.learn-c.org/|tutorial del lenguaje C]].  No haga la última sección //Static// y tampoco la parte //Advanced//.  Es un tutorial muy corto que va un poco más allá de lo que contiene esta sección.  Además la misma página compila ejecuta las soluciones que Ud. dará para cada ejercicio, ayudándole consolidar lo aprendido.
 ===== Ejemplo con varias funciones: quicksort ===== ===== Ejemplo con varias funciones: quicksort =====
  
Línea 357: Línea 357:
   - Esto se denomina declaración de encabezado de función.  Se requiere porque la función //swap// se usa en la función //quicksort// antes de su definición.  Sin este encabezado el compilador reclamaría.  El encabezado es similar a una definición de función, pero la parte { instrucciones } se reemplaza por punto y coma.   - Esto se denomina declaración de encabezado de función.  Se requiere porque la función //swap// se usa en la función //quicksort// antes de su definición.  Sin este encabezado el compilador reclamaría.  El encabezado es similar a una definición de función, pero la parte { instrucciones } se reemplaza por punto y coma.
   - Se usa la instrucción //return// para anticipar el retorno de una función.  Como la función es //void//, no se especifica el valor retornado.   - Se usa la instrucción //return// para anticipar el retorno de una función.  Como la función es //void//, no se especifica el valor retornado.
-  - Acá es donde se usa la función //swap// Por eso se incluyo la declaración de su encabezado en la nota 1.+  - Acá es donde se usa la función //swap// Por eso se incluyó la declaración de su encabezado en la nota 1.
   - Observe que las llaves no son necesarias acá.  Pero su uso le entrega legibilidad al programa.   - Observe que las llaves no son necesarias acá.  Pero su uso le entrega legibilidad al programa.
   - C es recursivo.  La invocación recursiva de funciones es igualmente eficiente que cualquier otra función.   - C es recursivo.  La invocación recursiva de funciones es igualmente eficiente que cualquier otra función.
   - Esta es la definición de //swap//, que fue usada antes en la nota 3, por lo que se necesitó la declaración de su encabezado en la nota 1.   - Esta es la definición de //swap//, que fue usada antes en la nota 3, por lo que se necesitó la declaración de su encabezado en la nota 1.
-  - Esa es la sintaxis para declarar un arreglo de //n// elementos de tipo //double// Los arreglos son de tamaño fijo, lo que significa que una vez que se declaran no pueden crecer.  El primer elemento es a[0] y el último a[n-1].  ¡Cuidado!  Se no verifica el correcto uso de los índice si Ud. accede a //a[n]// el resultado puede ser cualquiera.  O peor aún, si modifica //a[n]// el programa podría terminar en //segmentation fault//.+  - Esa es la sintaxis para declarar un arreglo de //n// elementos de tipo //double// Los arreglos son de tamaño fijo, lo que significa que una vez que se declaran no pueden crecer.  El primer elemento es a[0] y el último a[n-1].  ¡Cuidado!  No se verifica el correcto uso de los índices.  Si Ud. accede a //a[n]// el resultado puede ser cualquiera.  O peor aún, si modifica //a[n]// el programa podría terminar en //segmentation fault//.
   - Use el formato %g para desplegar reales con //printf//.   - Use el formato %g para desplegar reales con //printf//.
-  - La función //main// debe retornar obligatoriamente un entero. Este se llama el código de retorno del programa y se puede mostrar en el shell echo el comando echo %%$?%%.  Por convención un valor 0 indica que el programa tuvo éxito.  Un valor distinto de 0 significa que ocurrió algún problema.+  - La función //main// debe retornar obligatoriamente un entero. Este se llama el código de retorno del programa y se puede mostrar en el shell con el comando echo %%$?%%.  Por convención un valor 0 indica que el programa tuvo éxito.  Un valor distinto de 0 significa que ocurrió algún problema.
  
 He aquí cómo compilar y un ejemplo de ejecución con el resultado del programa: He aquí cómo compilar y un ejemplo de ejecución con el resultado del programa:
Línea 383: Línea 383:
 ===== Ejercicio final: factorial ===== ===== Ejercicio final: factorial =====
  
-  * Escriba en una archivo //fact.c// un programa que calcule recursivamente el factorial de un entero.+  * Escriba en un archivo //fact.c// un programa que calcule recursivamente el factorial de un entero.
   * El resultado debe ser un número real.   * El resultado debe ser un número real.
-  * Despliegue el resultado en pantalla con printf.+  * Despliegue el resultado en pantalla con //printf//.
  
 Ejemplo de uso: Ejemplo de uso:
principios.1583793249.txt.gz · Última modificación: 2020/03/09 22:34 por lmateu