C
Tutorial C: Memoria estática vs dinámica
Aprende en C las diferencias entre memoria estática y dinámica, gestión con malloc, calloc, realloc y el uso de stack y heap para optimizar tus programas.
Aprende C y certifícateMemoria estática: tamaño fijo en compilación
La memoria estática es aquella cuyo tamaño se determina durante la fase de compilación del programa y permanece fijo durante toda la ejecución. Cuando escribimos código en C, podemos declarar variables que ocuparán un espacio predefinido en la memoria del ordenador.
Características de la memoria estática
La memoria estática en C tiene varias características importantes:
- Tamaño conocido: El compilador sabe exactamente cuánta memoria necesita reservar.
- Asignación automática: No necesitamos solicitar esta memoria explícitamente.
- Duración predecible: Dependiendo de dónde se declare, puede durar toda la ejecución del programa o solo mientras se ejecuta una función.
Variables estáticas en C
En C, las variables con asignación estática de memoria incluyen:
- Variables globales: Declaradas fuera de cualquier función
- Variables locales estáticas: Declaradas dentro de funciones con la palabra clave
static
- Arrays de tamaño fijo: Declarados con un tamaño constante
Veamos un ejemplo sencillo de memoria estática con un array:
#include <stdio.h>
int main() {
// Array con asignación estática de memoria
int numeros[5] = {10, 20, 30, 40, 50};
printf("El array ocupa %lu bytes en memoria\n", sizeof(numeros));
// Accediendo a los elementos del array
for(int i = 0; i < 5; i++) {
printf("numeros[%d] = %d\n", i, numeros[i]);
}
return 0;
}
En este ejemplo, numeros
es un array de 5 enteros que ocupa un espacio fijo en memoria (20 bytes en sistemas donde cada int
ocupa 4 bytes). Este tamaño se determina en tiempo de compilación y no puede cambiar durante la ejecución.
Limitaciones de la memoria estática
La memoria estática, aunque sencilla de usar, presenta algunas limitaciones importantes:
- Tamaño fijo: No podemos cambiar el tamaño de un array estático una vez declarado.
- Conocimiento previo: Necesitamos saber de antemano cuánta memoria vamos a necesitar.
- Posible desperdicio: Si reservamos más memoria de la necesaria, el resto queda inutilizada.
Por ejemplo, si declaramos un array para almacenar hasta 100 nombres pero solo usamos 10, estamos desperdiciando memoria:
#include <stdio.h>
int main() {
// Reservamos espacio para 100 nombres, aunque solo usaremos unos pocos
char nombres[100][50]; // 100 nombres de hasta 50 caracteres cada uno
// Solo usamos los primeros 3 espacios
strcpy(nombres[0], "Ana");
strcpy(nombres[1], "Carlos");
strcpy(nombres[2], "Elena");
// Mostramos los nombres utilizados
for(int i = 0; i < 3; i++) {
printf("Nombre %d: %s\n", i+1, nombres[i]);
}
return 0;
}
En este caso, hemos reservado estáticamente memoria para 100 nombres (5000 bytes en total), pero solo estamos utilizando 3 espacios, lo que resulta en un desperdicio de recursos.
Variables globales y estáticas
Las variables globales y las variables locales declaradas como static
también utilizan memoria estática:
#include <stdio.h>
// Variable global (memoria estática)
int contador_global = 0;
void incrementar() {
// Variable estática local (memoria estática)
static int contador_local = 0;
contador_global++;
contador_local++;
printf("Global: %d, Local: %d\n", contador_global, contador_local);
}
int main() {
for(int i = 0; i < 3; i++) {
incrementar();
}
return 0;
}
En este ejemplo, tanto contador_global
como contador_local
ocupan memoria estática, pero tienen diferentes ámbitos de visibilidad. La variable local estática mantiene su valor entre llamadas a la función, a diferencia de las variables locales normales.
Matrices multidimensionales estáticas
Las matrices multidimensionales también pueden declararse de forma estática:
#include <stdio.h>
int main() {
// Matriz 3x3 con asignación estática
int matriz[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Recorremos la matriz
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
printf("%d ", matriz[i][j]);
}
printf("\n");
}
return 0;
}
Esta matriz ocupa un espacio fijo en memoria (9 enteros), determinado en tiempo de compilación.
Constantes y memoria estática
Las constantes en C también utilizan memoria estática:
#include <stdio.h>
#define MAX_ESTUDIANTES 30
int main() {
const double PI = 3.14159;
// Array de tamaño fijo basado en una constante
int calificaciones[MAX_ESTUDIANTES];
printf("Valor de PI: %f\n", PI);
printf("Tamaño del array: %lu bytes\n", sizeof(calificaciones));
return 0;
}
Tanto PI
como MAX_ESTUDIANTES
son valores que no cambian durante la ejecución, y el array calificaciones
tiene un tamaño fijo determinado por la constante.
Cuándo usar memoria estática
La memoria estática es ideal para:
- Datos de tamaño conocido que no cambiarán durante la ejecución
- Constantes y valores predefinidos
- Pequeñas estructuras de datos con tamaño limitado
- Variables globales que necesitan mantener su valor durante toda la ejecución
Es importante elegir adecuadamente entre memoria estática y dinámica según las necesidades de nuestro programa, considerando factores como el tamaño de los datos, la duración requerida y la flexibilidad necesaria.
Memoria dinámica: tamaño en ejecución
A diferencia de la memoria estática, la memoria dinámica permite asignar espacio durante la ejecución del programa según las necesidades que vayan surgiendo. Esta característica resulta fundamental cuando no conocemos de antemano el tamaño exacto de los datos que vamos a manejar o cuando necesitamos estructuras de datos que crezcan o disminuyan.
Funciones para gestión de memoria dinámica
En C, disponemos de varias funciones de la biblioteca estándar para trabajar con memoria dinámica:
- malloc(): Asigna un bloque de memoria del tamaño especificado
- calloc(): Asigna e inicializa a cero un bloque de memoria
- realloc(): Cambia el tamaño de un bloque de memoria previamente asignado
- free(): Libera un bloque de memoria previamente asignado
Todas estas funciones requieren incluir la cabecera <stdlib.h>
.
Asignación básica con malloc()
La función malloc()
(memory allocation) es la más utilizada para solicitar memoria dinámica:
#include <stdio.h>
#include <stdlib.h>
int main() {
// Solicitamos memoria para 5 enteros
int *numeros = (int*) malloc(5 * sizeof(int));
// Verificamos si la asignación fue exitosa
if (numeros == NULL) {
printf("Error: No se pudo asignar memoria\n");
return 1;
}
// Usamos la memoria asignada
for (int i = 0; i < 5; i++) {
numeros[i] = i * 10;
}
// Mostramos los valores
for (int i = 0; i < 5; i++) {
printf("numeros[%d] = %d\n", i, numeros[i]);
}
// Liberamos la memoria cuando ya no la necesitamos
free(numeros);
return 0;
}
En este ejemplo:
- Solicitamos memoria para almacenar 5 enteros
- Comprobamos si la asignación fue exitosa (siempre es recomendable)
- Utilizamos la memoria como si fuera un array normal
- Finalmente liberamos la memoria con
free()
Inicialización con calloc()
La función calloc()
(clear allocation) asigna memoria e inicializa todos los bits a cero:
#include <stdio.h>
#include <stdlib.h>
int main() {
// Solicitamos memoria para 5 enteros e inicializamos a cero
int *numeros = (int*) calloc(5, sizeof(int));
if (numeros == NULL) {
printf("Error: No se pudo asignar memoria\n");
return 1;
}
// Mostramos los valores (todos serán 0)
printf("Valores inicializados por calloc:\n");
for (int i = 0; i < 5; i++) {
printf("numeros[%d] = %d\n", i, numeros[i]);
}
free(numeros);
return 0;
}
La diferencia principal entre malloc()
y calloc()
es que esta última inicializa la memoria a cero, mientras que malloc()
simplemente la asigna sin inicializar.
Redimensionamiento con realloc()
Una de las ventajas clave de la memoria dinámica es la posibilidad de cambiar su tamaño durante la ejecución:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 5;
// Asignamos memoria inicialmente para 5 enteros
int *datos = (int*) malloc(n * sizeof(int));
if (datos == NULL) {
printf("Error en la asignación inicial\n");
return 1;
}
// Llenamos el array
for (int i = 0; i < n; i++) {
datos[i] = i + 1;
}
// Decidimos ampliar el array a 8 elementos
n = 8;
datos = (int*) realloc(datos, n * sizeof(int));
if (datos == NULL) {
printf("Error en la reasignación\n");
return 1;
}
// Añadimos valores a las nuevas posiciones
for (int i = 5; i < n; i++) {
datos[i] = i + 1;
}
// Mostramos todos los valores
for (int i = 0; i < n; i++) {
printf("datos[%d] = %d\n", i, datos[i]);
}
free(datos);
return 0;
}
La función realloc()
intenta ampliar o reducir el bloque de memoria manteniendo los datos originales. Si es necesario, puede mover los datos a una nueva ubicación con más espacio.
Arrays dinámicos de tamaño variable
Una aplicación común de la memoria dinámica es crear arrays cuyo tamaño se determina durante la ejecución:
#include <stdio.h>
#include <stdlib.h>
int main() {
int tamano;
int *array;
// El usuario decide el tamaño
printf("Introduce el tamaño del array: ");
scanf("%d", &tamano);
// Asignamos memoria según el tamaño indicado
array = (int*) malloc(tamano * sizeof(int));
if (array == NULL) {
printf("Error: No hay suficiente memoria\n");
return 1;
}
// Llenamos el array con valores
for (int i = 0; i < tamano; i++) {
array[i] = i * i;
}
// Mostramos el contenido
for (int i = 0; i < tamano; i++) {
printf("array[%d] = %d\n", i, array[i]);
}
free(array);
return 0;
}
Este enfoque es mucho más flexible que usar arrays estáticos, ya que podemos adaptar el tamaño a las necesidades reales del programa.
Matrices dinámicas
También podemos crear matrices (arrays bidimensionales) de forma dinámica:
#include <stdio.h>
#include <stdlib.h>
int main() {
int filas = 3;
int columnas = 4;
// Asignamos memoria para las filas (array de punteros)
int **matriz = (int**) malloc(filas * sizeof(int*));
if (matriz == NULL) {
printf("Error al asignar memoria para filas\n");
return 1;
}
// Asignamos memoria para cada columna
for (int i = 0; i < filas; i++) {
matriz[i] = (int*) malloc(columnas * sizeof(int));
if (matriz[i] == NULL) {
printf("Error al asignar memoria para columnas\n");
// Liberamos la memoria ya asignada
for (int j = 0; j < i; j++) {
free(matriz[j]);
}
free(matriz);
return 1;
}
}
// Llenamos la matriz
for (int i = 0; i < filas; i++) {
for (int j = 0; j < columnas; j++) {
matriz[i][j] = i * columnas + j;
}
}
// Mostramos la matriz
for (int i = 0; i < filas; i++) {
for (int j = 0; j < columnas; j++) {
printf("%2d ", matriz[i][j]);
}
printf("\n");
}
// Liberamos memoria (importante: primero las filas, luego la matriz)
for (int i = 0; i < filas; i++) {
free(matriz[i]);
}
free(matriz);
return 0;
}
Crear matrices dinámicas requiere más cuidado, especialmente al liberar la memoria para evitar fugas de memoria.
Gestión de cadenas dinámicas
La memoria dinámica es ideal para manejar cadenas de texto de longitud variable:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *nombre;
int longitud;
printf("¿Cuántos caracteres tiene tu nombre? ");
scanf("%d", &longitud);
// Consumimos el salto de línea pendiente
getchar();
// Asignamos memoria para la cadena (+1 para el carácter nulo)
nombre = (char*) malloc((longitud + 1) * sizeof(char));
if (nombre == NULL) {
printf("Error: No se pudo asignar memoria\n");
return 1;
}
printf("Introduce tu nombre: ");
fgets(nombre, longitud + 1, stdin);
// Eliminamos el posible salto de línea capturado por fgets
if (nombre[strlen(nombre) - 1] == '\n') {
nombre[strlen(nombre) - 1] = '\0';
}
printf("Hola, %s!\n", nombre);
free(nombre);
return 0;
}
Errores comunes al usar memoria dinámica
Al trabajar con memoria dinámica, es importante evitar estos errores frecuentes:
- Fugas de memoria: Olvidar liberar memoria con
free()
- Acceso después de liberar: Usar memoria después de llamar a
free()
- Desbordamiento de buffer: Acceder más allá de los límites asignados
- Doble liberación: Llamar a
free()
dos veces sobre el mismo puntero
#include <stdio.h>
#include <stdlib.h>
// Ejemplo de código con errores comunes (NO HACER ESTO)
void ejemploConErrores() {
int *array = (int*) malloc(5 * sizeof(int));
// Error 1: No verificamos si malloc falló
array[0] = 10;
array[1] = 20;
// Error 2: Acceso fuera de límites
array[10] = 100; // ¡Peligroso! Fuera del espacio asignado
// Error 3: Olvidar liberar memoria (fuga de memoria)
// free(array) falta aquí
}
// Versión corregida
void ejemploCorrecto() {
int *array = (int*) malloc(5 * sizeof(int));
// Verificamos si malloc tuvo éxito
if (array == NULL) {
printf("Error: No se pudo asignar memoria\n");
return;
}
// Accedemos solo dentro de los límites
for (int i = 0; i < 5; i++) {
array[i] = i * 10;
}
// Liberamos la memoria cuando terminamos
free(array);
// Evitamos usar el puntero después de liberarlo
array = NULL;
}
int main() {
ejemploCorrecto();
return 0;
}
Ventajas de la memoria dinámica
La memoria dinámica ofrece varias ventajas importantes:
- Flexibilidad: Podemos ajustar el uso de memoria según las necesidades reales
- Eficiencia: Solo utilizamos la memoria que realmente necesitamos
- Adaptabilidad: Podemos responder a requisitos cambiantes durante la ejecución
- Estructuras de datos avanzadas: Permite implementar listas enlazadas, árboles, grafos, etc.
Comparación con memoria estática
Veamos un ejemplo que ilustra la diferencia entre usar memoria estática y dinámica:
#include <stdio.h>
#include <stdlib.h>
void enfoqueEstatico() {
// Enfoque estático: tamaño fijo, posible desperdicio
int numeros[100]; // Reservamos 100 espacios aunque quizás necesitemos menos
int n = 0;
printf("¿Cuántos números quieres introducir? (máx 100): ");
scanf("%d", &n);
if (n > 100) {
printf("Error: no puedes introducir más de 100 números\n");
return;
}
for (int i = 0; i < n; i++) {
numeros[i] = i;
}
}
void enfoqueDinamico() {
// Enfoque dinámico: tamaño exacto según necesidad
int n = 0;
int *numeros;
printf("¿Cuántos números quieres introducir? (sin límite): ");
scanf("%d", &n);
numeros = (int*) malloc(n * sizeof(int));
if (numeros == NULL) {
printf("Error: No se pudo asignar memoria\n");
return;
}
for (int i = 0; i < n; i++) {
numeros[i] = i;
}
free(numeros);
}
int main() {
// Prueba ambos enfoques
enfoqueEstatico();
enfoqueDinamico();
return 0;
}
El enfoque dinámico nos permite adaptarnos a cualquier cantidad de datos sin desperdiciar memoria ni imponer límites artificiales.
Stack vs Heap explicado simple
Cuando programamos en C, nuestro programa utiliza dos áreas principales de memoria para almacenar datos: el stack (pila) y el heap (montículo). Estas áreas tienen características muy diferentes y entender cómo funcionan nos ayudará a escribir programas más eficientes.
¿Qué es el Stack?
El stack es una región de memoria que funciona como una pila de platos: el último elemento que colocas es el primero que puedes retirar. Esta región tiene las siguientes características:
- Organización automática: El sistema gestiona automáticamente la asignación y liberación de memoria
- Tamaño limitado: Tiene un tamaño máximo predefinido (generalmente algunos MB)
- Acceso rápido: Las operaciones en el stack son muy rápidas
- Estructura ordenada: Los datos se almacenan de forma contigua y ordenada
En el stack se guardan:
- Variables locales (las que declaramos dentro de funciones)
- Parámetros de funciones
- Dirección de retorno de las funciones
- Variables estáticas (aunque con un comportamiento especial)
#include <stdio.h>
void funcionEjemplo() {
// Estas variables se almacenan en el stack
int numero = 42;
char letra = 'A';
float precio = 9.99;
printf("Variables en el stack: %d, %c, %.2f\n", numero, letra, precio);
// Al terminar la función, estas variables desaparecen automáticamente
}
int main() {
funcionEjemplo();
return 0;
}
¿Qué es el Heap?
El heap es una región de memoria más flexible que funciona como un gran almacén donde podemos solicitar y devolver espacio según lo necesitemos. Sus características son:
- Gestión manual: Nosotros debemos solicitar y liberar la memoria explícitamente
- Tamaño flexible: Puede crecer según las necesidades (limitado por la memoria disponible)
- Acceso más lento: Las operaciones son algo más lentas que en el stack
- Estructura menos ordenada: Los datos pueden estar dispersos
En el heap se guardan:
- Datos creados con
malloc()
,calloc()
orealloc()
- Estructuras de datos de tamaño variable
- Objetos grandes o que necesitan existir más allá del ámbito de una función
#include <stdio.h>
#include <stdlib.h>
int* crearArray(int tamano) {
// Esta memoria se asigna en el heap
int* array = (int*)malloc(tamano * sizeof(int));
// Inicializamos el array
if (array != NULL) {
for (int i = 0; i < tamano; i++) {
array[i] = i * 10;
}
}
// Devolvemos el puntero a la memoria del heap
return array;
}
int main() {
int* numeros = crearArray(5);
if (numeros != NULL) {
printf("Array creado en el heap: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numeros[i]);
}
printf("\n");
// Importante: debemos liberar la memoria manualmente
free(numeros);
}
return 0;
}
Analogía: La oficina y el almacén
Para entender mejor la diferencia entre stack y heap, podemos usar una analogía:
El stack es como tu escritorio de trabajo: un espacio limitado donde colocas los documentos con los que estás trabajando ahora mismo. Es fácil y rápido acceder a ellos, pero cuando terminas una tarea, retiras esos documentos para hacer espacio para la siguiente tarea.
El heap es como un almacén grande: puedes guardar muchas cosas y mantenerlas allí por mucho tiempo. Tienes que pedir espacio específicamente, recordar dónde pusiste las cosas y, cuando ya no las necesitas, debes indicar que ese espacio puede ser utilizado para otras cosas.
Diferencias clave entre Stack y Heap
Característica | Stack | Heap |
---|---|---|
Gestión | Automática | Manual (malloc/free) |
Tamaño | Limitado | Flexible (más grande) |
Velocidad | Muy rápido | Más lento |
Fragmentación | No ocurre | Puede fragmentarse |
Orden de datos | Contiguo | Puede estar disperso |
Duración | Temporal (ámbito) | Hasta que se libere |
Uso típico | Variables locales | Datos dinámicos |
¿Cuándo usar cada uno?
Usa el stack cuando:
Trabajas con datos pequeños de tamaño conocido
Necesitas variables que solo existan dentro de una función
Buscas el mejor rendimiento para operaciones simples
Usa el heap cuando:
No conoces el tamaño de los datos de antemano
Necesitas que los datos persistan después de salir de una función
Trabajas con estructuras de datos grandes o que cambian de tamaño
Visualizando Stack y Heap en acción
Veamos un ejemplo que utiliza ambas regiones de memoria:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void procesarDatos() {
// Variables en el stack
int contador = 0;
char bufferPequeno[50];
// Datos en el heap
char* textoGrande = (char*)malloc(1000 * sizeof(char));
if (textoGrande == NULL) {
printf("Error: No se pudo asignar memoria\n");
return;
}
// Usamos ambas áreas de memoria
strcpy(bufferPequeno, "Datos en el stack");
strcpy(textoGrande, "Datos más grandes almacenados en el heap");
printf("Stack: %s\n", bufferPequeno);
printf("Heap: %s\n", textoGrande);
// Liberamos la memoria del heap
free(textoGrande);
// No necesitamos liberar bufferPequeno, se libera automáticamente
}
int main() {
procesarDatos();
return 0;
}
En este ejemplo:
contador
ybufferPequeno
se almacenan en el stack y se liberan automáticamente al salir de la funcióntextoGrande
apunta a memoria en el heap que debemos liberar manualmente confree()
Errores comunes relacionados con Stack y Heap
Desbordamiento del Stack (Stack Overflow)
Ocurre cuando intentamos usar más memoria de la disponible en el stack:
#include <stdio.h>
// Esta función puede causar stack overflow
void funcionRecursivaPeligrosa(int n) {
// Array grande en el stack
char granArray[1000000]; // ¡Peligro! Ocupa mucho espacio en el stack
// Llamada recursiva sin condición de salida adecuada
if (n > 0) {
funcionRecursivaPeligrosa(n - 1);
}
}
// Versión segura usando el heap
void funcionRecursivaSegura(int n) {
if (n > 0) {
// Usamos el heap para datos grandes
char* granArray = (char*)malloc(1000000);
if (granArray != NULL) {
// Hacemos algo con el array...
// Liberamos antes de la llamada recursiva
free(granArray);
funcionRecursivaSegura(n - 1);
}
}
}
int main() {
// Esto probablemente causará un error
// funcionRecursivaPeligrosa(10);
// Esta versión es más segura
funcionRecursivaSegura(10);
return 0;
}
Fugas de memoria (Memory Leaks)
Ocurren cuando asignamos memoria en el heap pero olvidamos liberarla:
#include <stdio.h>
#include <stdlib.h>
// Función con fuga de memoria
void funcionConFuga() {
int* datos = (int*)malloc(100 * sizeof(int));
if (datos != NULL) {
// Hacemos algo con los datos...
// ¡Error! Olvidamos liberar la memoria
// free(datos);
}
}
// Función corregida
void funcionCorrecta() {
int* datos = (int*)malloc(100 * sizeof(int));
if (datos != NULL) {
// Hacemos algo con los datos...
// Liberamos correctamente
free(datos);
}
}
int main() {
// Si llamamos a esta función muchas veces, perderemos memoria
// funcionConFuga();
// Esta versión es correcta
funcionCorrecta();
return 0;
}
Consejos prácticos
- Usa el stack para variables pequeñas y temporales
- Usa el heap para datos grandes o de larga duración
- Siempre verifica el resultado de
malloc()
y funciones similares - Libera la memoria del heap cuando ya no la necesites
- Establece a NULL los punteros después de liberarlos para evitar accesos incorrectos
- Evita arrays muy grandes en el stack para prevenir desbordamientos
- Mantén un equilibrio: el stack es más rápido, pero el heap es más flexible
#include <stdio.h>
#include <stdlib.h>
int main() {
// Buena práctica: verificar malloc y establecer NULL después de free
int* datos = (int*)malloc(10 * sizeof(int));
if (datos == NULL) {
printf("Error: No se pudo asignar memoria\n");
return 1;
}
// Usamos la memoria...
for (int i = 0; i < 10; i++) {
datos[i] = i;
}
// Liberamos y establecemos a NULL
free(datos);
datos = NULL; // Buena práctica
// Ahora es seguro verificar
if (datos == NULL) {
printf("La memoria ha sido liberada correctamente\n");
}
return 0;
}
Entender la diferencia entre stack y heap te ayudará a tomar mejores decisiones sobre cómo organizar la memoria en tus programas, lo que resultará en código más eficiente y con menos errores.
Todas las lecciones de C
Accede a todas las lecciones de C y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A C
Introducción Y Entorno
Primer Programa En C
Introducción Y Entorno
Estructura Básica De Un Programa En C
Sintaxis
Operadores Y Expresiones
Sintaxis
Control De Flujo
Sintaxis
Arrays Y Manejo De Cadenas
Sintaxis
Arrays Unidimensionales
Sintaxis
Ámbito De Variables
Sintaxis
Paso De Parámetros
Sintaxis
Entrada Y Salida Básica
Sintaxis
Variables Y Tipos De Datos
Sintaxis
Recursividad
Sintaxis
Control Iterativo
Sintaxis
Control Condicional
Sintaxis
Funciones
Punteros
Punteros
Punteros
Gestión De Memoria Dinámica
Punteros
Aritmética De Punteros
Punteros
Punteros Y Arrays
Punteros
Punteros A Punteros
Punteros
Punteros Y Funciones
Punteros
Memoria Estática Vs Dinámica
Gestión De Memoria
Gestión Segura De Memoria
Gestión De Memoria
Arrays Dinámicos
Gestión De Memoria
Estructuras En C
Estructuras Y Uniones
Uniones Y Enumeraciones
Estructuras Y Uniones
Typedef Y Y Organización De Código
Estructuras Y Uniones
Uniones
Estructuras Y Uniones
Creación De Structs
Estructuras Y Uniones
Enumeraciones
Estructuras Y Uniones
Estructuras Anidadas
Estructuras Y Uniones
Archivos
Io Y Archivos
E/s Binaria Y Formateo
Io Y Archivos
Manipulación Avanzada De Cadenas
Io Y Archivos
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender las características y limitaciones de la memoria estática en C.
- Aprender a utilizar funciones de asignación dinámica de memoria como malloc, calloc, realloc y free.
- Diferenciar entre las áreas de memoria stack y heap, y sus usos apropiados.
- Identificar errores comunes en la gestión de memoria dinámica y cómo evitarlos.
- Aplicar buenas prácticas para gestionar memoria y evitar fugas o desbordamientos.