Herramientas de usuario

Herramientas del sitio


introduccion2

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
introduccion2 [2020/03/09 02:37] – [Ejemplo con varias funciones: quicksort] lmateuintroduccion2 [2020/03/09 23:44] (actual) lmateu
Línea 1: Línea 1:
 ===== Introducción ===== ===== Introducción =====
  
-¿Qué es la programación de //software de sistemas//? (fuente: [[http://www.dcc.uchile.cl/docs/2010/CC3301_2009-2-ADD_2010.pdf|wikipedia]])+¿Qué es la //programación de software de sistemas//? (fuente: [[http://www.dcc.uchile.cl/docs/2010/CC3301_2009-2-ADD_2010.pdf|wikipedia]])
  
-La alternativa es el //software de aplicaciones// que busca producir programas que proveen servicios al usuario directamente.  Por ejemplo un procesador de texto como word, un navegador para la web como chrome, un editor de fotografías como photoshop, etc.  En cambio el software de sistemas busca producir programas o plataformas que: +La alternativa es la //programación de software de aplicaciones// que busca producir programas que proveen servicios al usuario directamente.  Por ejemplo un procesador de texto como word, un navegador para la web como chrome, un editor de fotografías como photoshop, etc.  En cambio el software de sistemas busca producir programas o plataformas que: 
-  * Proveen servicios a otro software: un motor para juegos de video, un administrador de bases de datos, un intérprete de Python, etc.+  * Proveen servicios a otro software: un motor para juegos de video, un administrador de bases de datos, el intérprete de Python, etc.
   * Poseen requisitos especiales en cuanto a desempeño: el sistema operativo, resolución numérica de ecuaciones diferenciales, sistemas de control de maquinarias, etc.   * Poseen requisitos especiales en cuanto a desempeño: el sistema operativo, resolución numérica de ecuaciones diferenciales, sistemas de control de maquinarias, etc.
   * Usualmente ambas.   * Usualmente ambas.
- 
- 
  
 Programa de curso: Programa de curso:
Línea 16: Línea 14:
 ¿Por qué estudiar el lenguaje C? ¿Por qué estudiar el lenguaje C?
  
-Cuando se requiere alto desempeño el mejor lenguaje es C o su sucesor C++.  Por eso hay una enorme cantidad de software escrito en C y es probable que Ud. tenga que hacer mejoras a programa en C cuando se desempeñe como profesional.+Cuando se requiere alto desempeño el mejor lenguaje es C o su sucesor C++.  Por eso hay una enorme cantidad de software escrito en C y es probable que Ud. tenga que hacer mejoras a programas en C cuando se desempeñe como profesional.  También podría requerir programar en C si los requisitos de desempeño son elevados, por ejemplo los decodificadores de video se programan en C. 
 + 
 +Por esta razón el sitio //stackify.com// señala a C entre [[https://stackify.com/popular-programming-languages-2018|los lenguajes más populares]] entre los programadores.
  
 ¿Cual es la principal desventaja de C? ¿Cual es la principal desventaja de C?
  
-Al contrario de Python y JavaC no es robusto.  Por razones de eficiencia no se verifica que las operaciones que se ejecutan sean válidas.  Por ejemplo no se chequea que el índice sea válido al acceder a un arreglo.  El resultado es que prácticamente el único mensaje de error que entrega es //segmentation fault//, que significa que se accedió a una dirección de memoria no atribuida al programa.  Ud. va a tener pesadillas con este mensaje de error.  Esto se traduce también en que es mucho más difícil depurar un programa en C que sus contraparte en Python o Java.+Ud. ya sabe programar en Python y aprenderá el lenguaje Java en Metodologías de Diseño y Programación.  Estos lenguajes son robustos: verifican que cada operación realizada sea válida en tiempo de ejecución.  En cambio //no es robusto//.  Por razones de eficiencia no se verifica la validez de las operaciones.  Por ejemplo no se chequea que el índice sea válido al acceder a un arreglo, lo que desencadena frecuentemente una sucesión de errores que lleva al programa a acceder a memoria que no fue atribuida por el sistema operativo, arrojando el mensaje //segmentation fault//.  Prácticamente es el único mensaje de error que se entrega durante la ejecución.  Ud. va a tener pesadillas con este mensaje de error.  Esto se traduce también en que es mucho más difícil depurar un programa en C que su contraparte en Python o Java y por lo tanto la productividad en C es inferior a la de Java, la que ya es inferior a la de Python.  Por eso el uso de C se reserva solo a la programación de software de sistemas. 
 + 
 +¿Por qué estudiar los threads? 
 + 
 +Hasta ahora Ud. solo a escrito programas secuenciales: corren en un solo thread y por lo tanto usan un solo core del procesador.  Cuando su programa resulta muy lento, en el curso de algoritmos Ud. aprendió a reprogramar usando algoritmos más eficientes, pasando por ejemplo de O(n^2) a O(n log n).  Pero a veces el algoritmo que usó es el mejor y no se puede mejorar.  Para hacerlo más rápido puede recurrir al paralelismo, es decir usar múltiples threads que ejecutan en paralelo en distintos cores las operaciones requeridas para resolver el problema.  Esta paralelización no es automática: Ud. aprenderá en este curso cómo reescribir los programas para usar múltiples threads.
  
 ¿Por qué estudiar Unix y/o Linux? ¿Por qué estudiar Unix y/o Linux?
  
-La mayoría de los servidores que entregan las páginas de la web corren Linux, una variante de Unix.  Se necesitan expertos que trabajen en Linux para programar el software que hay detrás de esos servidores.  Por otra parte MacOsel sistema operativos de los computadores de Apple, Android e iOSlos sistemas operativos que usan los smartphones son variantes de Unix.  Lo que aprenda en este curso también es válido para esas variantes de Unix.+La mayoría de los servidores que entregan las páginas de la web corren Linux, una variante de Unix.  Se necesitan expertos que trabajen en Linux para programar el software que hay detrás de esos servidores.  Por otra parte MacOs (el sistema operativo de los computadores de Apple), Android e iOS  (los sistemas operativos que usan los smartphonesson variantes de Unix.  Lo que aprenda en este curso también es válido para esas variantes de Unix
 + 
 +¿Por qué estudiar los sockets? 
 + 
 +Muchos sistemas son del tipo cliente/servidor.  En estos una parte del problema se resuelve con un programa que se ejecuta en el computador del usuario (el cliente) y otro programa que corre en un computador lejano (el servidor) que almacena los datos requeridos.  Por ejemplo la web funciona de esta forma: el cliente es el navegador (como firefox) y el servidor es el programa que accede a las páginas web (usualmente apache).  Los sockets son la herramienta que usan cliente y servidor para comunicarse y constituyen la base de la internet.  En este curso aprenderá a usar los sockets para programar aplicaciones cliente/servidor. 
 + 
 +También usaremos los sockets como herramienta de paralelización: para lograr que un problema sea resuelto en paralelo usando múltiples computadores conectados a la internet.
  
 ¿Por qué no se enseña C++? ¿Por qué no se enseña C++?
Línea 30: Línea 40:
 Por restricciones de tiempo.  C++ es un lenguaje mucho más complejo que C.  Da para un curso completo.  Por otra parte los conceptos que aprenderá en este curso le servirán para aprender C++.  Si está interesado en C++, estoy seguro que no tendrá problemas para convertirse en un experto en C++ leyendo estos [[http://www.cplusplus.com/doc/|tutoriales]]. Por restricciones de tiempo.  C++ es un lenguaje mucho más complejo que C.  Da para un curso completo.  Por otra parte los conceptos que aprenderá en este curso le servirán para aprender C++.  Si está interesado en C++, estoy seguro que no tendrá problemas para convertirse en un experto en C++ leyendo estos [[http://www.cplusplus.com/doc/|tutoriales]].
  
-===== Historia de los lenguajes de programación más usados =====+===== Historia de los lenguajes de programación más influyentes =====
  
   * En los 50's nace Fortran, el primer lenguaje de programación "de alto nivel" El objetivo era bastante modesto, ya que solo se buscaba poder escribir fórmulas algebraicas cómodamente sin tener que programarlas en lenguaje ensamblador.  Sin embargo todavía no hay while ni if/else: se usa if ... goto.  La programación es no estructurada.  Por eso su sigla significa //Formula Translator//.   * En los 50's nace Fortran, el primer lenguaje de programación "de alto nivel" El objetivo era bastante modesto, ya que solo se buscaba poder escribir fórmulas algebraicas cómodamente sin tener que programarlas en lenguaje ensamblador.  Sin embargo todavía no hay while ni if/else: se usa if ... goto.  La programación es no estructurada.  Por eso su sigla significa //Formula Translator//.
Línea 41: Línea 51:
   * En los 90's James Gosling concibe Java como una forma de darle robustez a C++.  Es menos complejo que C++.   * En los 90's James Gosling concibe Java como una forma de darle robustez a C++.  Es menos complejo que C++.
  
-===== Ejemplo de programa en C ===== 
- 
-El programa de más abajo muestra los primeros //n// números de la serie de Fibonacci.  El programa se encuentra almacenado en el archivo //fib.c// Para poder ejecutarlo se requiere compilarlo previamente con el comando gcc (el compilador de C).  Esto se hace en Linux en una ventana de comandos (o shell de comandos) mediante: 
- 
-<code> 
-$ gcc --std=c99 fib.c -o fib 
-$ 
-</code> 
- 
-Que no aparezca ningún mensaje de diagnóstico significa que el programa está bien escrito.  La opción //--std=c99// especifica que la versión de C requerida es C99, un estándar que data de 1999.  La opción //-o fib// le indica al compilador el nombre del archivo en donde debe almacenar la versión binaria del mismo programa codificada en lenguaje de máquina.  Usualmente no se usa una extensión para los archivos en lenguaje de máquina. 
- 
-El programa se ejecuta por ejemplo en el shell de comandos con: 
- 
-<code> 
-$ ./fib 8 
-f0= 0 
-f1= 1 
-f2= 1 
-f3= 2 
-f4= 3 
-f5= 5 
-f6= 8 
-f7= 13 
-$ 
-</code> 
- 
-Este es el archivo //fib.c//: 
- 
-<code C> 
-// Calcula los primeros n numeros de fibonacci 
- 
-#include <stdio.h> 
-#include <stdlib.h> 
- 
-int main(int argc, char **argv) { 
-  int n= atoi(argv[1]); 
-  int prev= 0; 
-  printf("f0= 0\n"); 
-  int curr= 1; 
-  int next; 
-  printf("f1= 1\n"); 
-  for (int i= 2; i<n; i++) { 
-    next= prev+curr; 
-    printf("f%d= %d\n", i, next); 
-    prev= curr; 
-    curr= next; 
-  } 
-  return 0; 
-} 
-</code> 
- 
-Ejercicio: copie este mismo programa en un archivo //fib.c// en algún computador con Linux.  Compílelo y ejecútelo exactamente como se indica más arriba. 
- 
-===== Formato de un programa en 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. 
-  * 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. 
-  * 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. 
-  * Al ejecutar un programa la primera función que se ejecuta 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 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: 
- 
-  * //int// para los números enteros 
-  * //char// para enteros pequeños que usualmente corresponden a la codificación en ascii de un caracter 
-  * //double// para números reales 
-  * //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. 
- 
-===== Formato de una función en C ===== 
- 
-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//. 
-  * //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. 
- 
-Por ejemplo el formato para //main//, exceptuando las instrucciones, es: 
- 
-<code C> 
-int main(int argc, char **argv) { 
-  ... etc. ... 
-} 
-</code> 
- 
- 
-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. 
- 
-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 { }. 
- 
-===== Instrucciones simples ===== 
- 
-Las instrucciones simples siempre terminan con un punto y coma.  Una instrucción puede abarcar varias líneas  o también se pueden colocar varias instrucciones en una misma línea, porque recuerde que los cambios de línea son ignorados por el compilador.  Sin embargo por legibilidad se recomienda colocar a lo más una sola instrucción por línea. 
- 
-En el programa de ejemplo observamos 4 categorías de instrucciones simples: declaración de variables, asignación, invocación de funciones y retorno de función. 
- 
-==== Declaración de variables ==== 
- 
-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 e incluso invocar otras funciones (siempre y cuando no retornen void).  La parte //= expresión// es opcional. 
- 
-En el ejemplo se declara la variable //prev// de tipo //int// con valor inicial 0: 
- 
-<code C> 
-int prev = 0; 
-</code> 
- 
-Se observa que para la variable //next// no se indica un valor inicial: 
- 
-<code C> 
-int next; 
-</code> 
- 
-En tal caso hay un valor inicial desconocido.  Usar esta variable antes de asignarle un valor concreto es típicamente un error y algunos compiladores hacen un esfuerzo por diagnosticar el problema. 
- 
-Es posible declarar varias variables en una misma instrucción separando las variables con una coma.  Por ejemplo se pudo declarar //prev//, //curr// y //next// en una sola instrucción: 
- 
-<code C> 
-int prev = 0, curr= 1, next; 
-</code> 
- 
-Yo suelo declarar varias variables en una sola instrucción, aunque algunos expertos opinan que  es menos legible.  Después veremos que tiene sus riesgos. 
- 
-Otro ejemplo de declaración es la de la variable //n// de tipo //int//: 
- 
-<code C> 
-int n= atoi(argv[1]); 
-</code> 
- 
-El valor inicial es la expresión //atoi(argv[1])// La variable //argv// es un arreglo de strings que contiene los parámetros especificados en el shell de comandos.  Es decir es el "8" que viene a continuación de //./fib// en la línea de comandos.  En este caso es solo el string "8" Por razones que se explicarán más tarde en el curso, este se encuentra en el elemento con índice 1.  Si hubiesen más parametros, se ocuparían los índices 2, 3, etc.  El número concreto de parámetros + 1 se almacena en la variable entera //argc//. Por lo tanto argv[1] es el string "8" La función //atoi// convierte el string "8" al entero 8, que se convierte en el valor inicial de //n//. 
- 
-Ejercicio: ¿Como declararía una variable que almacena el número PI? 
-==== Asignación ==== 
- 
-Sintaxis: //variable// = //expresión// ; 
- 
-Sirve para cambiar el valor de una variable.  En el ejemplo: 
- 
-<code C> 
-next= prev+curr; 
-</code> 
- 
-El lado derecho del igual puede ser una expresión complicada con múltiples operadores e invocaciones de otras funciones. 
-Recuerde que las instrucciones simples siempre terminan con un ;.  El cambio de línea no le dice nada al compilador. 
- 
-==== Invocación de una función ==== 
- 
-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//, ... ) 
- 
-En donde //argumento_1//, //argumento_2//, ... son expresiones.  Por ejemplo: 
- 
-<code C> 
-printf("f0= 0\n"); 
-printf("f%d= %d\n", i, next); 
-</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. 
- 
-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// ; 
- 
-De hecho la asignación también es un caso particular de esa sintaxis por = se considera un operador como + y *. 
- 
-==== Retorno de función ==== 
- 
-Para terminar la ejecución de una función se usa la instrucción return, que usa la siguiente sintaxis: 
- 
-**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. 
- 
-===== 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 { }. 
- 
-==== Ciclo while ==== 
- 
-La sintaxis es: **while** (//condición//) //instrucción// 
- 
-Es como el while de Python: se evalúa la condición, si es verdadera se ejecuta la instrucción.  Esto se repite hasta que la condición sea falsa.  Por ejemplo: 
- 
-<code C> 
-int a= 1; 
-while ( a < 100 ) 
-  a = a * 2; 
-</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; 
- 
-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: 
- 
-<code C> 
-int a= 1; 
-while ( a < 100 ) 
-  a = a * 2; 
-  a = a + 1;  // ¡No haga esto por favor! 
-</code> 
- 
-El valor final de //a// será 129.  La asignación a=a+1 se ejecuta una sola vez después de que a sea 128.  Este código está mal escrito porque está mal indentado.  La indentación no refleja la estructura entendida por el compilador.  Dependiendo de las opciones de compilación, el compilador podría entregar una advertencia del problema, pero no está obligado a hacerlo.  Ud. no lo haga.  La indentación correcta del programa es: 
- 
-<code C> 
-int a= 1; 
-while ( a < 100 ) 
-  a = a * 2; 
-a = a + 1;  // ¡Bien! 
-</code> 
- 
-Esta es una ventaja de Python.  Dado que la indentación señala a Python cuál es la estructura del programa no puede haber inconsistencia. 
- 
-==== Agrupación de instrucciones ==== 
- 
-Sintaxis: { //instrucción// //instrucción// ... etc. } 
- 
-Se usa para colocar varias instrucciones en instrucciones compuestas que aceptan solo una instrucción.  Para ejecutar una agrupación, sus instrucciones se ejecutan secuencialmente en el orden en que aparecen.  Por ejemplo si realmente se necesita que a=a+1 esté dentro del while se debe agrupar las 2 asignaciones con las llaves: 
- 
-<code C> 
-int a= 1; 
-while ( a < 100 ) { 
-  a = a * 2; 
-  a = a + 1;  // ¡Bien! 
-} 
-</code> 
- 
-Ejercicio: indique en donde se usa agrupación de instrucciones en el programa para fibonacci. 
- 
-La indentación usada es importante, aunque al compilador le de lo mismo.  Esta es la indentación de Kernighan y es la que Ud. debe usar obligatoriamente en este curso: el símbolo { debe ir al final de la línea del while y el } en una línea aparte, en la misma columna de la w del while.  Los siguientes estilos de indentación serán penalizados con décimas menos en controles y tareas: 
- 
-<code C> 
-// ¡No use estos estilos de indentación! 
-while ( a < 100 )        while ( a < 100 )      while ( a < 100 ) { 
-{                          {                      a = a * 2; 
-  a = a * 2;               a = a * 2;             a = a + 1; } 
-  a = a + 1;               a = a + 1; 
-}                          } 
-</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 ciclo for ==== 
- 
-Sintaxis: for ( inicio; condición ; expresión ) instrucción 
- 
-Se usa mucho para hacer ciclos.  Es equivalente a: 
- 
-<code C> 
-{ 
-  inicio; 
-  while ( condición ) { 
-    instrucción 
-    expresión; 
-  } 
-} 
-</code> 
- 
-Ejemplo: 
- 
-<code C> 
-  for (int i= 2; i<n; i++) 
-    next= prev+curr; 
-</code> 
- 
-Ejercicio: reescriba la instrucción equivalente usando while. 
- 
-==== Ejecución condicional ==== 
- 
-Sintaxis 1: **if** ( //condición// ) //instrucción// 
- 
-Significado: //instrucción// se ejecuta cuando //condición// es verdadera.  Si es falsa, no se ejecuta ninguna instrucción. 
- 
-Sintaxis 2: **if** ( //condición// ) //instrucción_1// **else** //instrucción_2// 
- 
-Significado: //instrucción_1// se ejecuta cuando la condición es verdadera.  En tal caso no se ejecuta //instrucción_2// Si la condición es falsa, solo se ejecuta //instrucción_2//. 
- 
-Ejemplo: 
- 
-<code C> 
-int a= 15, b= 35; 
-if (a<b) 
-  b = b-a; 
-else 
-  a = a-b; 
-</code> 
-   
- 
-Ejercicio: ¿Qué debe hacer cuando debe ejecutar varias instrucciones cuando la condición es verdadera? 
- 
-===== Trabajo personal ===== 
- 
-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 a repasar lo visto hasta ahora. 
- 
-===== Ejemplo con varias funciones: quicksort ===== 
- 
-Cree el archivo qsort.c con el siguiente contenido: 
- 
-<code C> 
-#include <stdio.h> 
-#include <stdlib.h> 
- 
-void swap(double v[], int i, int j); // nota 1: encabezado de funcion 
- 
-void quicksort(double a[], int left, int right) { 
-  if (left>=right) 
-    return;  // nota 2: retorno de funcion de tipo void 
- 
-  swap(a, left, (left+right)/2); // nota 3: uso previo a definicion 
-  int last= left; 
- 
-  //  +--+-----------+--------+--------------+ 
-  //  |  |///////////|\\\\\\\\|              | 
-  //  +--+-----------+--------+--------------+ 
-  //  left        last                 right 
- 
-  for (int i= left+1; i<=right; ++i) { // nota 4: legibilidad 
-    if (a[i]<a[left]) 
-      swap(a, ++last, i); 
-  } 
-  swap(a, left, last); 
- 
-  quicksort(a, left, last-1);  // nota 5: recursividad 
-  quicksort(a, last+1, right); 
-} 
- 
-void swap(double v[], int i, int j) { // nota 6: definicion posterior 
-  double tmp= v[i]; 
-  v[i]= v[j]; 
-  v[j]= tmp; 
-} 
- 
-int main(int argc, char *argv[]) { 
-  int n= argc-1; 
-  double a[n]; // nota 7: declaracion de arreglo 
- 
-  for (int i= 0; i<n; i++) 
-    a[i]= atof(argv[i+1]); 
- 
-  quicksort(a, 0, n-1); 
- 
-  for (int i= 0; i<n; i++) 
-    printf("%g ", a[i]); // nota 8: despliegue de reales 
-  printf("\n"); 
- 
-  return 0; // nota 9: retorno de función no //void// 
-} 
-</code> 
- 
-Notas: 
-  - 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. 
-  - Acá es donde se usa la función //swap// Por eso se incluyo 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. 
-  - 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. 
-  - 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//. 
-  - 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. 
- 
-He aquí cómo compilar y un ejemplo de ejecución con el resultado del programa: 
- 
-<code> 
-$ gcc -std=c99 qsort.c -o qsort 
-$ ./qsort 3 1 5 7 4 
-1 3 4 5 7  
-$ echo $? 
-0 
-$ 
-</code> 
- 
-Ejercicios: 
-  * Modifique el programa de modo que muestre los números descendentemente (ahora son mostrados ascendentemente). 
-  * Modifique el programa de modo que cada número se muestre en una línea independiente. 
-  * Modifique el programa de modo que el código de retorno sea 1 cuando el usuario olvidó especificar los elementos a ordenar 
- 
-===== Opcional ===== 
- 
-En el curso Metodologías de Diseño y Programación deberá estudiar el lenguaje Java.  Se puede considerar Java como un sucesor de C y por lo tanto gran parte de lo que estudie en este curso le servirá también para aprender Java.  Los tipos y la sintaxis son parecidos.  Opcionalmente puede leer este [[CvsJava|comparativo]] entre C y Java. 
  
introduccion2.1583721464.txt.gz · Última modificación: 2020/03/09 02:37 por lmateu