Está en la página 1de 8

Instituto Politécnico Nacional

Unidad Profesional Interdisciplinaria en Ingeniería y


Tecnologías Avanzadas

Introducción a la programación
1MM2

Glosario 8

Adrián David García Mendoza


N° de boleta: 2021640002

Viernes 14 de mayo de 2021


Glosario 8

Paso de parámetros por valor.

Los parámetros por valor permiten pasar datos entre el programa principal y las funciones, e incluso entre
las mismas funciones. En el parámetro se escribe una copia de la variable original. Si el parámetro sufre
una alteración en la función que lo recibe, la variable original no se ve afectada.

#include <stdio.h>
/* El programa calcula el cubo de los 10 primeros números naturales con la
ayuda de una función y utilizando parámetros por valor. */

int cubo(int); /* Prototipo de función. El parámetro es de tipo entero. */

void main(void)
{
int I;
for (I = 1; I <= 10; I++)
printf(“\nEl cubo de I es:%d”, cubo(I));
/* Llamada a la función cubo. El paso del parámetro es por valor. */
}

int cubo(int K) /* K es un parámetro por valor de tipo entero. */


/* La función calcula el cubo del parámetro K. */
{
return (K*K*K);
}

Observa que la instrucción:


int cubo(int);
es un prototipo de función que informa al compilador que el parámetro que se utilizará es por valor y de
tipo entero.
La siguiente instrucción permite escribir el resultado de la función. Observa que el parámetro que se utiliza
es una copia de la variable I.
printf(“\nEl cubo de %d es: %d”, cubo(I));
Finalmente, ya en la función cubo, la instrucción:
return (K*K*K);
regresa el resultado obtenido al programa principal.
Paso de parámetros por referencia.

Los parámetros por referencia también permiten la comunicación entre el programa principal y las
funciones, o entre las mismas funciones. Sin embargo, en este caso, en lugar de escribir una copia de la
variable en el parámetro se escribe la dirección de la misma. Si el parámetro sufre una alteración en la
función que lo recibe, la variable original también se ve afectada. En C, las llamadas por referencia se
realizan mediante apuntadores.

#include <stdio.h>
/* Prueba de parámetros por referencia. */

void f1(int *);


/* Prototipo de función. El parámetro es de tipo entero y por referencia
—observa el uso del operador de indirección. */

void main(void)
{
int I, K = 4;
for (I = 1; I <= 3; I++)
{
printf(“\n\nValor de K antes de llamar a la función: %d”, ++K);
printf(“\nValor de K después de llamar a la función: %d”, f1(&K));
/* Llamada a la función f1. Se pasa la dirección de la variable K, por
medio del operador de dirección: &. */
}
}

void f1(int *R)


/* La función f1 recibe un parámetro por referencia. Cada vez que el parámetro se
utiliza en la función debe ir precedido por el operador de indirección. */
{
*R += *R;
}

La instrucción:
void f1(int *);
es un prototipo de función que informa al compilador que el parámetro que se va a utilizar es por referencia
y de tipo entero. Se utiliza el operador de indirección: *. La siguiente instrucción permite escribir el
resultado de la función. Observa que en la llamada a la función se utiliza un parámetro por referencia. La
dirección de la variable se pasa mediante el operador de dirección: &.
printf(“\nValor de K después de llamar a la función: %d”, f1(&K));
Finalmente, ya en la función f1, cada vez que se utiliza el parámetro por referencia,
se debe anteponer al mismo el operador de indirección.
Diseño de funciones que regresan más de un cálculo.

// Esta función calcula el factorial de un número entero no negativo, usando el


concepto // de 'recursividad' o 'funciones recursivas'.
int factorial_recursiva (int n) // El parámetro que le proporcionamos a esta
función // es 'n', del cual se calculará su factorial.
{
int fact; // La variable que usaremos como valor de retorno.
if(n == 0){
return 1;
} else {
return n * factorial_recursiva(n - 1);
}
// Podemos retornar un solo valor a la vez (al llamar a la función), pero las
condiciones // que determinan cuál será el valor de la variable de retorno pueden ser
múltiples. // Dicho de otro modo, podemos tener cuantas sentencias 'return' como
necesitemos, // dentro de estructuras de selección o de control (como if, switch,
for, while, etc), // tal que el valor que retornemos sea distinto según determinada
condición.
}

Uso de memoria dinámica.

C permite una gestión dinámica de la memoria, es decir, solicitar memoria para albergar el contenido de
estructuras de datos cuyo tamaño exacto no conocemos hasta que se ha iniciado la ejecución del
programa.

¿Por qué usar estructuras dinámicas? En ocasiones necesitaremos manejar estructuras de datos que
“cambien”, es decir, cuyo tamaño no sea siempre el mismo. La solución suele ser crear estructuras
dinámicas, que puedan ir creciendo o disminuyendo según nos interesen. Ejemplos de este tipo de
estructuras son:
 Las pilas. Como una pila de libros: vamos apilando cosas en la cima, o cogiendo de la cima.
 Las colas. Como las del cine (en teoría): la gente llega por un sitio (la cola) y sale por el opuesto
(la cabeza).
 Las listas, en las que se puede añadir elementos, consultarlos o borrarlos en cualquier posición.
Y la cosa se va complicando: en los árboles cada elemento puede tener varios sucesores, etc. Todas
estas estructuras tienen en común que, si se programan bien, pueden ir creciendo o decreciendo según
haga falta, al contrario que un array, que tiene su tamaño prefijado. En todas ellas, lo que vamos haciendo
es reservar un poco de memoria para cada nuevo elemento que nos haga falta, y enlazarlo a los que ya
teníamos. Cuando queramos borrar un elemento, enlazamos el anterior a él con el posterior a él (para que
no "se rompa" nuestra estructura) y liberamos la memoria que estaba ocupando.

Investigue el protocolo para gestión de memoria dinámica.

Se utiliza para ello cuatro funciones de la biblioteca estándar (disponibles incluyendo la cabecera stdlib.h):

 malloc (abreviatura de memory allocate), que podemos traducir por “reservar memoria“): solicita un
bloque de memoria del tamaño que se indique (en bytes);
 free (que en inglés significa “liberar”): libera memoria obtenida con malloc, es decir, la marca como
disponible para futuras llamadas a malloc.
 calloc: funciona de modo similar a malloc, pero además de reservar memoria, inicializa a 0 la
memoria reservada. Se usa comúnmente para arreglos y matrices. Está definida de esta forma:
void *calloc(size_t nmemb, size_t size);
El parámetro nmemb indica el número de elementos a reservar, y size el tamaño de cada
elemento.
 realloc: redimensiona el espacio asignado de forma dinámica anteriormente a un puntero. Tiene la
siguiente definición:
void *realloc(void *ptr, size_t size);
Donde ptr es el puntero a redimensionar, y size el nuevo tamaño, en bytes, que tendrá. Si el
puntero que se le pasa tiene el valor nulo, esta función actúa como malloc. Si la reasignación no
se pudo hacer con éxito, devuelve un puntero nulo, dejando intacto el puntero que se pasa por
parámetro. Al usar realloc, se debería usar un puntero temporal. De lo contrario, podríamos tener
una fuga de memoria, si es que ocurriera un error en realloc.
Uso del operador sizeof.

El operador llamado "sizeof" (tamaño de); ejemplo de su uso:


int main()
{
float f;
short int i;
printf("El tamaño de mi float es %d", sizeof f);
printf(" y lo normal para un float es %d", sizeof(float) );
printf(" pero un entero corto ocupa %d", sizeof i);
return 0;
}
// Al ejecutarlo se mostraría lo siguiente: El tamaño de mi float es 4 y lo
normal // para un float es 4 pero un entero corto ocupa 2.

Uso de función malloc().

La función malloc presenta un prototipo similar a éste:


void * malloc(int bytes);

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
int * a;
int talla, i;
printf ("Numero de elementos: ");
scanf ("%d", &talla);
a = malloc( talla * sizeof(int) );
for (i=0; i<talla; i++)
a[i] = i;
free(a);
a = NULL;
return 0;
}

El vector a se ha definido (línea 6) como int * a, es decir, como puntero a entero. No se trata de un puntero
a un entero, sino de un puntero a una secuencia de enteros. Ambos conceptos son equivalentes en C,
pues ambos son meras direcciones de memoria. La variable a es un vector dinámico de enteros, pues su
memoria se obtiene dinámicamente, esto es, en tiempo de ejecución y según convenga a las necesidades.
No sabemos aún cuántos enteros serán apuntados por a, ya que el valor de talla no se conocerá hasta
que se ejecute el programa y se lea por teclado.
La línea 10 reserva memoria para talla enteros y guarda en a la dirección de memoria en la que empiezan
esos enteros. La función espera recibir como argumento un número entero: el número de bytes que
queremos reservar. Si deseamos reservar talla valores de tipo int, hemos de solicitar memoria para talla *
sizeof(int) bytes. Hay que tener en cuenta que sizeof(int) es la ocupación en bytes de un dato de tipo int (y
que estamos asumiendo que es de 4). Finalmente, la línea 13 del programa libera la memoria reservada y
la línea 14 guarda en a un valor especial: NULL.

La función free tiene un prototipo similar a éste:


void free(void * puntero);

Como se ve, free recibe un puntero a cualquier tipo de datos: la dirección de memoria en la que empieza
un bloque previamente obtenido con una llamada a malloc. Lo que hace free es liberar ese bloque de
memoria, es decir, considerar que pasa a estar disponible para otras posibles llamadas a malloc.
Preferentemente, un programa debe efectuar una llamada a free por cada llamada a malloc. Conviene que
después de hacer free se asigne al puntero el valor NULL, especialmente si la variable sigue “viva” durante
bastante tiempo. NULL es una constante definida en stdlib.h. Si un puntero vale NULL, se entiende que no
apunta a un bloque de memoria.
BIBLIOGRAFÍA

Cabanes, N. (2013). Fundamentos de programación en C. Recuperado de


http://www.nachocabanes.com/c/

Cairó, O. (2006). Fundamentos de programación. Piensa en C. Naucalpan de Juárez, Estado de


México: Pearson Educación.

Marzal, A. & Gracia, I. (s.f.). Introducción a la programación con C. Castellón de la Plana,


Castellón: Universitat Jaume I.

También podría gustarte