6.3) Acceso y argumentos de funciones. Prototipos.
     
     

    a) Acceso a una función:
     

     Se puede acceder ( llamar )a una función especificando su nombre, seguido de una lista de argumentos cerrados entre paréntesis y separados por comas. Si la llama a la función no requiere ningún argumento, se debe escribir a continuación del nombre de la función un par de paréntesis vacíos. La llamada a la función puede aparecer sola (esto es, puede formar una expresión simple), o puede ser uno de los operandos de una expresión más compleja.
     
     
     

    Ejemplo.
     
     
     
     
     

    b) Argumentos de una función. Prototipos:

     

     Los argumentos que aparecen en la llamada a la función se denominan argumentos actuales, mientras que los argumentos formales son los que aparecen en la primera línea de definición de la función. (También se llaman los argumentos actuales, a veces, argumentos simplemente, o parámetros actuales). En una llamada normal a una función, habrá un argumento actual por cada argumento formal. Los argumentos actuales pueden ser constantes, variables simples, o expresiones más complejas. No obstante, cada argumento actual debe ser del mismo tipo de datos que el argumento formal correspondiente.
     
     

     Los parámetros formales son variables locales a una función, ya que son creados al entrar en la función (se crean en la pila) y destruidos cuando ésta termina. El tipo de variable declarado para cada parámetro formal debe ser el  mismo que se utilice cuando se llama a la función Si esto no sucede, pueden introducirse errores, ya que el compilador no verificará los tipos. Para prevenir estos errores se emplean los prototipos de las funciones. Los prototipos consisten en declarar al principio del programa (de cada módulo si el programa contiene varios módulos) las funciones que se utilizan y los tipos de sus argumentos. De esta forma el compilador puede reconocer una incongruencia entre el prototipo de una función y su llamada.
     Los prototipos, también nos pueden solveltar los errores que se pueden dar al hacer una llamada a una función func2 (que no devuelve un entero), y que aparece implementada debajo de func1, siendo llamada desde func1, por tanto, para resolver el problema de orden de definición son útiles igualmente los prototipos o declaraciones por adelantado. Veamos como sería todo esto:
     
     

     

 
 
 
 
 
     

     Los parámetros son siempre pasados por valor. Por tanto, el parámetro de la función recibe el valor de la variable que se utiliza como argumento. Cualquier modificación sobre estos parámetros no afecta a las variables que se utilizan para llamar a la función, puesto que el parámetro en estos casos es una copia de esas variables.
     
     

    Ejemplos.
     
     

     

    Veamos un ejemplo en el que se modifica el valor de su argumento.
     


     

     Se visualiza el valor original de a (a=2) cuando comienza la ejecución de main. Este valor se pasa a la función modificar, en donde se multiplica por 3 y se visualiza el nuevo valor. Nótese que se altera el valor del argumento formal que se visualiza en la función. Finalmente, el valor de a en main (el argumento actual) se vuelve a visualizar, después de haberse devuelto el control a main desde modificar.
     
     

    Se genera la siguiente salida:

    a = 2     (desde main, antes de llamar a la función)

    a = 6     (desde la función, después de modificar el valor)

    a = 2     (desde main, después de llamar a la función)

     
     
     
     Pasar los argumentos por valor tiene sus ventajas y sus desventajas. Algo positivo es que los valores hallados dentro de la función no son vistos fuera de ella. Su desventaja es que impide que se transfiera información desde la función hasta el punto de llamada mediante los argumentos. Por tanto, el paso por valor implica que la transferencia de información sólo puede realizarse en un sentido.
     

     Cuando sea necesario modificar el valor de la variable utilizada para llamar a la función hay que pasar la dirección de dicha variable. Por tanto, los parámetros deben ser declarados como punteros (se verán en temas sucesivos). El único caso en el que sin necesidad de especificarlo explícitamente se pasa la dirección de una variable como argumento es cuando se pasa una matriz.
     
     

     Las dos formas descritas anteriormente serían:
     
     
     

       
       
      Paso por valor
      Paso por variable
      Prototipo
      fun(int,int)
      fun(int *, int *)
      Llamada
      fun(arg1,arg2)
      fun(&arg1, &arg2)
      Implementación
      fun(int par1,int par2)
      fun(int *par1, int *par2)

       
       
       


     
     
     
     
     
    Ejemplo de acceso a una función:
     
     
     

     Leer un carácter y convertirlo a mayúscula utilizando una función definida por el programador que sea llamada desde el programa principal ( main() ).

    #include <stdio.h>

    main()
    {

      char minus, mayus;
      char minus_a_mayus (char);    /* declaración de función  (lo veremos en el apartado 6.3) b))*/

      printf("Por favor introduce una letra: ");
      scanf("%c", &minus);
      mayus=minus_a_mayus(minus);
      printf("\nLa mayúscula equivalente es: %c\n\n",mayus);

    }

    char minus_a_mayus( char c1)    /* definición de función */
    {

      char c2;

      c2= (c1>='a' && c1<='z') ? ('A' + c1 - 'a'): c1;
      return(c2);

    }
     
     
     
     Este programa contiene una llamada a la función definida por el programador minus_a_mayus. La llamada es una parte de la expresión mayus=minus_a_mayus(minus).
    Activar la función mediante la llamada a ésta hace que se transfiera el valor de minus a la función. Este valor es representado por c1 dentro de la función, con return(c2) devolvemos el valor de la mayúscula que lo hemos introducido anteriormente en la variable carácter c2.
     
     
     
     
     

    Ejemplos de argumentos de una función:
     
     
     

    Ejemplo 1:
     
     

     Estas dos formas son equivalentes:
     
     

     
    int cabeceras(char *mensaje, int fila, int columna) {
    if (fila>25 || fila<1 || columna<1 ||
    columna>80)
      return(0);
    gotoxy(fila,columna);
    printf(mensaje);
    return(1);
    }
    int cabeceras(mensaje, fila, columna) 
    char *mensaje;
    int fila;
    int columna;
    {
    if (fila>25 || fila<1 || columna<1 ||
    columna>80)
      return(0);
    gotoxy(fila,columna);
    printf(mensaje);
    return(1);
    }
     

     Para esta función se declararía el prototipo:
     

      int cabeceras (char *, int, int);