Hoja de Trucos de Programación en C

Aprenda Programación en C con Laboratorios Prácticos

Aprenda programación en C a través de laboratorios prácticos y escenarios del mundo real. LabEx ofrece cursos completos de C que cubren sintaxis esencial, gestión de memoria, punteros, estructuras de datos y técnicas avanzadas. Domine las potentes características de C para construir aplicaciones eficientes a nivel de sistema y comprender conceptos de programación de bajo nivel.

Sintaxis Básica y Estructura

Programa “Hola Mundo”

Estructura básica de un programa en C.

#include <stdio.h>
int main() {
    printf("Hola, Mundo!\n");
    return 0;
}

Cabeceras y Preprocesador

Incluir librerías y usar directivas del preprocesador.

#include <stdio.h>    // Entrada/salida estándar
#include <stdlib.h>   // Librería estándar
#include <string.h>   // Funciones de cadena
#include <math.h>     // Funciones matemáticas
#define PI 3.14159
#define MAX_SIZE 100

Comentarios

Comentarios de una sola línea y de múltiples líneas.

// Comentario de una sola línea
/*
Comentario
de múltiples líneas
que abarca varias líneas
*/
// TODO: Implementar funcionalidad
/* FIXME: Error en esta sección */

Función Main

Punto de entrada del programa con valores de retorno.

int main() {
    // Código del programa aquí
    return 0;  // Éxito
}
int main(int argc, char *argv[]) {
    // argc: número de argumentos
    // argv: valores de los argumentos (línea de comandos)
    return 0;
}
Quiz

Inicia sesión para responder este quiz y rastrear tu progreso de aprendizaje

¿Qué indica return 0 en la función main?
El programa falló
El programa sigue ejecutándose
El programa se ejecutó con éxito
El programa no devolvió ningún valor

Salida Básica

Mostrar texto y variables en la consola.

printf("Hola\n");
printf("Valor: %d\n", 42);
// Múltiples valores en una línea
printf("Nombre: %s, Edad: %d\n", name, age);

Entrada Básica

Leer la entrada del usuario desde la consola.

int age;
char name[50];
scanf("%d", &age);
scanf("%s", name);
// Leer línea completa con espacios
fgets(name, sizeof(name), stdin);

Tipos de Datos y Variables

Tipos Primitivos

Tipos de datos básicos para almacenar diferentes clases de valores.

// Tipos enteros
int age = 25;
short small_num = 100;
long large_num = 1000000L;
long long huge_num = 9223372036854775807LL;
// Tipos de punto flotante
float price = 19.99f;
double precise = 3.14159265359;
// Carácter y booleano (usando int)
char grade = 'A';
int is_valid = 1;  // 1 para verdadero, 0 para falso

Arreglos y Cadenas

Manejo de arreglos y cadenas en C.

// Arreglos
int numbers[5] = {1, 2, 3, 4, 5};
int matrix[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
// Cadenas (arreglos de caracteres)
char name[50] = "John Doe";
char greeting[] = "Hello";
char buffer[100];  // Sin inicializar
// Longitud y tamaño de la cadena
int len = strlen(name);
int size = sizeof(buffer);
Quiz

Inicia sesión para responder este quiz y rastrear tu progreso de aprendizaje

¿Cómo se representan las cadenas en C?
Como un tipo de cadena especial
Como enteros
Como arreglos de caracteres
Solo como punteros

Constantes y Modificadores

Valores inmutables y modificadores de almacenamiento.

// Constantes
const int MAX_SIZE = 100;
const double PI = 3.14159;
// Constantes del preprocesador
#define BUFFER_SIZE 512
#define TRUE 1
#define FALSE 0
// Modificadores de almacenamiento
static int count = 0;     // Variable estática
extern int global_var;    // Variable externa
register int fast_var;    // Sugerencia de registro

Estructuras de Control de Flujo

Sentencias Condicionales

Tomar decisiones basadas en condiciones.

// Sentencia If-else
if (age >= 18) {
    printf("Adulto\n");
} else if (age >= 13) {
    printf("Adolescente\n");
} else {
    printf("Niño\n");
}
// Operador ternario
char* status = (age >= 18) ? "Adulto" : "Menor";
// Sentencia Switch
switch (grade) {
    case 'A':
        printf("¡Excelente!\n");
        break;
    case 'B':
        printf("¡Buen trabajo!\n");
        break;
    default:
        printf("¡Sigue intentándolo!\n");
}

Bucles For

Iterar con bucles basados en un contador.

// Bucle for tradicional
for (int i = 0; i < 10; i++) {
    printf("%d ", i);
}
// Iteración de arreglo
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
for (int i = 0; i < size; i++) {
    printf("%d ", numbers[i]);
}
// Bucles anidados
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        printf("%d,%d ", i, j);
    }
}
Quiz

Inicia sesión para responder este quiz y rastrear tu progreso de aprendizaje

¿Qué calcula sizeof(numbers) / sizeof(numbers[0])?
El número de elementos en el arreglo
El tamaño total de memoria del arreglo
El índice del último elemento
El tamaño de un elemento

Bucles While

Iteración basada en una condición.

// Bucle While
int count = 0;
while (count < 5) {
    printf("%d\n", count);
    count++;
}
// Bucle Do-while (se ejecuta al menos una vez)
int input;
do {
    printf("Introduce un número (0 para salir): ");
    scanf("%d", &input);
} while (input != 0);

Control de Bucles

Sentencias break y continue.

for (int i = 0; i < 10; i++) {
    if (i == 3) {
        continue; // Saltar iteración
    }
    if (i == 7) {
        break;    // Salir del bucle
    }
    printf("%d ", i);
}
// Bucles anidados con break
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == j) break; // Romper solo el bucle interno
        printf("%d,%d ", i, j);
    }
}

Funciones

Declaración y Definición de Funciones

Crear bloques de código reutilizables.

// Declaración de función (prototipo)
int add(int a, int b);
void printMessage(char* msg);
// Definición de función
int add(int a, int b) {
    return a + b;
}
void printMessage(char* msg) {
    printf("%s\n", msg);
}
// Llamada a función
int result = add(5, 3);
printMessage("¡Hola, funciones!");

Pasar Arreglos a Funciones

Funciones que trabajan con arreglos.

// Arreglo como parámetro (puntero)
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
// Modificar elementos del arreglo
void doubleValues(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;
    }
}

Funciones Recursivas

Funciones que se llaman a sí mismas.

// Cálculo de factorial
int factorial(int n) {
    if (n <= 1) {
        return 1;  // Caso base
    }
    return n * factorial(n - 1);
}
// Secuencia de Fibonacci
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    }
    return fibonacci(n-1) + fibonacci(n-2);
}

Punteros a Funciones

Punteros a funciones para comportamiento dinámico.

// Declaración de puntero a función
int (*operation)(int, int);
// Asignar función a puntero
operation = add;
int result = operation(5, 3);
// Arreglo de punteros a funciones
int (*operations[])(int, int) = {add, subtract, multiply};
result = operations[0](10, 5);

Punteros y Gestión de Memoria

Conceptos Básicos de Punteros

Declarar y usar punteros para acceder a direcciones de memoria.

int x = 10;
int *ptr = &x;  // Puntero a x
printf("Valor de x: %d\n", x);
printf("Dirección de x: %p\n", &x);
printf("Valor de ptr: %p\n", ptr);
printf("Valor apuntado por ptr: %d\n", *ptr);
// Modificar valor a través del puntero
*ptr = 20;
printf("Nuevo valor de x: %d\n", x);
// Puntero nulo
int *null_ptr = NULL;

Arreglos y Punteros

Relación entre arreglos y punteros.

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // Puntero al primer elemento
// Notación de arreglo vs aritmética de punteros
printf("%d\n", arr[2]);   // Notación de arreglo
printf("%d\n", *(p + 2)); // Aritmética de punteros
printf("%d\n", p[2]);     // Puntero como arreglo
// Iterar usando puntero
for (int i = 0; i < 5; i++) {
    printf("%d ", *(p + i));
}

Asignación Dinámica de Memoria

Asignar y liberar memoria en tiempo de ejecución.

#include <stdlib.h>
// Asignar memoria para un entero
int *ptr = (int*)malloc(sizeof(int));
if (ptr != NULL) {
    *ptr = 42;
    printf("Valor: %d\n", *ptr);
    free(ptr);  // Siempre liberar la memoria asignada
}
// Asignar arreglo dinámicamente
int *arr = (int*)malloc(10 * sizeof(int));
if (arr != NULL) {
    for (int i = 0; i < 10; i++) {
        arr[i] = i * i;
    }
    free(arr);
}

Punteros a Cadenas

Trabajar con cadenas y punteros de caracteres.

// Literales de cadena y punteros
char *str1 = "Hello";           // Literal de cadena
char str2[] = "World";          // Arreglo de caracteres
char *str3 = (char*)malloc(20); // Cadena dinámica
// Funciones de cadena
strcpy(str3, "Dynamic");
printf("Longitud: %lu\n", strlen(str1));
printf("Comparación: %d\n", strcmp(str1, str2));
strcat(str2, "!");
// Siempre liberar cadenas dinámicas
free(str3);

Estructuras y Tipos Definidos por el Usuario

Definición de Estructura

Definir tipos de datos personalizados con múltiples campos.

// Definición de estructura
struct Rectangle {
    double width;
    double height;
};
// Estructura con typedef
typedef struct {
    char name[50];
    int age;
    double gpa;
} Student;
// Crear e inicializar estructuras
struct Rectangle rect1 = {5.0, 3.0};
Student student1 = {"Alice", 20, 3.75};
// Acceder a miembros de la estructura
printf("Área: %.2f\n", rect1.width * rect1.height);
printf("Estudiante: %s, Edad: %d\n", student1.name, student1.age);

Estructuras Anidadas

Estructuras que contienen otras estructuras.

typedef struct {
    int day, month, year;
} Date;
typedef struct {
    char name[50];
    Date birthdate;
    double salary;
} Employee;
Employee emp = {
    "John Smith",
    {15, 6, 1985},
    50000.0
};
printf("Nacimiento: %d/%d/%d\n",
       emp.birthdate.day,
       emp.birthdate.month,
       emp.birthdate.year);

Punteros a Estructuras

Usar punteros para acceder y modificar estructuras.

Student *student_ptr = &student1;
// Acceder usando puntero (dos métodos)
printf("Nombre: %s\n", (*student_ptr).name);
printf("Edad: %d\n", student_ptr->age);
// Modificar a través del puntero
student_ptr->age = 21;
strcpy(student_ptr->name, "Alice Johnson");
// Asignación dinámica de estructura
Student *new_student = (Student*)malloc(sizeof(Student));
if (new_student != NULL) {
    strcpy(new_student->name, "Bob");
    new_student->age = 19;
    new_student->gpa = 3.2;
    free(new_student);
}

Uniones y Enums

Métodos alternativos de organización de datos.

// Unión - espacio de memoria compartido
union Data {
    int integer;
    float floating;
    char character;
};
union Data data;
data.integer = 42;
printf("Entero: %d\n", data.integer);
// Enumeración
enum Weekday {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
};
enum Weekday today = FRIDAY;
printf("Hoy es el día %d\n", today);

Operaciones de Entrada/Salida de Archivos

Lectura de Archivos

Leer datos de archivos de texto.

#include <stdio.h>
// Leer archivo completo carácter por carácter
FILE *file = fopen("data.txt", "r");
if (file != NULL) {
    int ch;
    while ((ch = fgetc(file)) != EOF) {
        putchar(ch);
    }
    fclose(file);
}
// Leer línea por línea
FILE *file2 = fopen("lines.txt", "r");
char buffer[256];
while (fgets(buffer, sizeof(buffer), file2) != NULL) {
    printf("Línea: %s", buffer);
}
fclose(file2);
// Leer datos formateados
FILE *numbers = fopen("numbers.txt", "r");
int num;
while (fscanf(numbers, "%d", &num) == 1) {
    printf("Número: %d\n", num);
}
fclose(numbers);

Verificación de Errores

Manejar operaciones de archivos de forma segura.

FILE *file = fopen("data.txt", "r");
if (file == NULL) {
    printf("¡Error al abrir el archivo!\n");
    perror("fopen");  // Imprimir mensaje de error del sistema
    return 1;
}
// Comprobar errores de lectura
if (ferror(file)) {
    printf("¡Error al leer el archivo!\n");
}
// Comprobar fin de archivo
if (feof(file)) {
    printf("Se alcanzó el final del archivo\n");
}
fclose(file);

Escritura de Archivos

Escribir datos en archivos de texto.

// Escribir en archivo
FILE *outfile = fopen("output.txt", "w");
if (outfile != NULL) {
    fprintf(outfile, "¡Hola, archivo!\n");
    fprintf(outfile, "Número: %d\n", 42);
    fclose(outfile);
}
// Anexar a archivo existente
FILE *appendfile = fopen("log.txt", "a");
if (appendfile != NULL) {
    fprintf(appendfile, "Nueva entrada de registro\n");
    fclose(appendfile);
}
// Escribir arreglo en archivo
int numbers[] = {1, 2, 3, 4, 5};
FILE *numfile = fopen("numbers.txt", "w");
for (int i = 0; i < 5; i++) {
    fprintf(numfile, "%d ", numbers[i]);
}
fclose(numfile);

Operaciones de Archivos Binarios

Leer y escribir datos binarios de manera eficiente.

// Escribir datos binarios
Student students[3] = {
    {"Alice", 20, 3.75},
    {"Bob", 21, 3.2},
    {"Charlie", 19, 3.9}
};
FILE *binfile = fopen("students.bin", "wb");
fwrite(students, sizeof(Student), 3, binfile);
fclose(binfile);
// Leer datos binarios
Student loaded_students[3];
FILE *readbin = fopen("students.bin", "rb");
fread(loaded_students, sizeof(Student), 3, readbin);
fclose(readbin);

Manipulación de Cadenas

Funciones de Cadena

Operaciones comunes de cadenas de la librería string.h.

#include <string.h>
char str1[50] = "Hello";
char str2[] = "World";
char dest[100];
// Longitud de cadena
int len = strlen(str1);
printf("Longitud: %d\n", len);
// Copia de cadena
strcpy(dest, str1);
strncpy(dest, str1, 10); // Copiar los primeros 10 caracteres
// Concatenación de cadena
strcat(dest, " ");
strcat(dest, str2);
strncat(dest, "!", 1);   // Anexar 1 carácter
// Comparación de cadenas
int result = strcmp(str1, str2);
if (result == 0) {
    printf("Las cadenas son iguales\n");
}

Búsqueda de Cadenas

Encontrar subcadenas y caracteres dentro de cadenas.

char text[] = "The quick brown fox";
char *ptr;
// Encontrar primera ocurrencia de carácter
ptr = strchr(text, 'q');
if (ptr != NULL) {
    printf("Se encontró 'q' en la posición: %ld\n", ptr - text);
}
// Encontrar última ocurrencia
ptr = strrchr(text, 'o');
printf("Última 'o' en la posición: %ld\n", ptr - text);
// Encontrar subcadena
ptr = strstr(text, "brown");
if (ptr != NULL) {
    printf("Se encontró 'brown' en: %s\n", ptr);
}

Conversión de Cadenas

Convertir cadenas a números y viceversa.

#include <stdlib.h>
// Conversión de cadena a número
char num_str[] = "12345";
char float_str[] = "3.14159";
int num = atoi(num_str);
long long_num = atol(num_str);
double float_num = atof(float_str);
printf("Entero: %d\n", num);
printf("Largo: %ld\n", long_num);
printf("Doble: %.2f\n", float_num);
// Número a cadena (usando sprintf)
char buffer[50];
sprintf(buffer, "%d", 42);
sprintf(buffer, "%.2f", 3.14159);
printf("Cadena: %s\n", buffer);

Procesamiento Personalizado de Cadenas

Técnicas manuales de manipulación de cadenas.

// Contar caracteres en cadena
int countChar(char *str, char target) {
    int count = 0;
    while (*str) {
        if (*str == target) count++;
        str++;
    }
    return count;
}
// Invertir cadena in situ
void reverseString(char *str) {
    int len = strlen(str);
    for (int i = 0; i < len/2; i++) {
        char temp = str[i];
        str[i] = str[len-1-i];
        str[len-1-i] = temp;
    }
}

Proceso de Compilación y Construcción

Compilación con GCC

GNU Compiler Collection para C.

# Compilación básica
gcc -o programa main.c
# Con información de depuración
gcc -g -o programa main.c
# Niveles de optimización
gcc -O2 -o programa main.c
# Múltiples archivos fuente
gcc -o programa main.c utils.c math.c
# Incluir directorios adicionales
gcc -I/usr/local/include -o programa main.c
# Enlazar librerías
gcc -o programa main.c -lm -lpthread

Estándares de C

Compilar con versiones específicas del estándar C.

# Estándar C90/C89 (ANSI C)
gcc -std=c89 -o programa main.c
# Estándar C99
gcc -std=c99 -o programa main.c
# Estándar C11 (recomendado)
gcc -std=c11 -o programa main.c
# Estándar C18 (más reciente)
gcc -std=c18 -o programa main.c
# Habilitar todas las advertencias
gcc -Wall -Wextra -std=c11 -o programa main.c

Conceptos Básicos de Makefile

Automatizar la compilación con la utilidad make.

# Makefile simple
CC = gcc
CFLAGS = -std=c11 -Wall -g
TARGET = program
SOURCES = main.c utils.c
$(TARGET): $(SOURCES)
$(CC) $(CFLAGS) -o $(TARGET) $(SOURCES)
clean:
rm -f $(TARGET)
.PHONY: clean

Mejores Prácticas y Consejos

Convenciones de Nomenclatura

La nomenclatura consistente hace que el código sea más legible.

// Variables y funciones: snake_case
int student_count;
double calculate_average(int scores[], int size);
// Constantes: UPPER_CASE
#define MAX_BUFFER_SIZE 1024
#define PI 3.14159
// Estructuras: PascalCase o snake_case
typedef struct {
    char name[50];
    int age;
} Student;
// Variables globales: prefijo g_
int g_total_count = 0;
// Parámetros de función: nombres claros
void process_data(int *input_array, int array_size);

Seguridad de Memoria

Prevenir errores comunes relacionados con la memoria.

// Inicializar siempre las variables
int count = 0;        // Bien
int count;            // Peligroso - sin inicializar
// Comprobar el valor de retorno de malloc
int *ptr = malloc(sizeof(int) * 10);
if (ptr == NULL) {
    printf("Fallo en la asignación de memoria!\n");
    return -1;
}
// Siempre liberar la memoria asignada
free(ptr);
ptr = NULL;  // Prevenir reutilización accidental
// Comprobación de límites de arreglo
for (int i = 0; i < array_size; i++) {
    // Acceso seguro al arreglo
    array[i] = i;
}

Consejos de Rendimiento

Escribir código C eficiente.

// Usar tipos de datos apropiados
char small_num = 10;   // Para valores pequeños
int normal_num = 1000; // Para enteros típicos
// Minimizar llamadas a funciones en bucles
int len = strlen(str); // Calcular una vez
for (int i = 0; i < len; i++) {
    // Procesar cadena
}
// Usar register para variables accedidas frecuentemente
register int counter;
// Preferir arreglos sobre asignación dinámica cuando el tamaño es conocido
int fixed_array[100];  // Asignación en la pila
// vs
int *dynamic_array = malloc(100 * sizeof(int));

Organización del Código

Estructurar el código para su mantenimiento.

// Archivo de cabecera (utils.h)
#ifndef UTILS_H
#define UTILS_H
// Prototipos de funciones
double calculate_area(double radius);
int fibonacci(int n);
// Definiciones de estructuras
typedef struct {
    int x, y;
} Point;
#endif // UTILS_H
// Archivo de implementación (utils.c)
#include "utils.h"
#include <math.h>
double calculate_area(double radius) {
    return M_PI * radius * radius;
}

Enlaces Relevantes