Análisis de Memoria y Algoritmos de Manipulación de Arrays en C

Distribución de Memoria en Arrays Unidimensionales y Bidimensionales

En el lenguaje C, los arrays se almacenan en bloques de memoria contigua. Comprender cómo el compilador asigna y direcciona estos bloques es fundamental para la manipulación eficiente de punteros. Para un array unidimensional, el nombre del array decae a un puntero a su primer elemento. En arrays bidimensionales, la memoria se organiza de forma contigua fila por fila (row-major order), lo que significa que la dirección de la segunda fila comienza inmediatamente después del último elemento de la primera fila.

#include <stdio.h>
#include <stdint.h>

#define ROWS 2
#define COLS 4

void analyze_1d_memory() {
    int32_t integer_seq[COLS] = {15, 25, 35, 45};
    
    printf("Tamaño total del array 1D: %zu bytes\n", sizeof(integer_seq));
    printf("Tamaño de un elemento: %zu bytes\n", sizeof(integer_seq[0]));
    
    for (int i = 0; i < COLS; ++i) {
        printf("Dirección de integer_seq[%d]: %p | Valor: %d\n", i, (void*)&integer_seq[i], integer_seq[i]);
    }
    printf("Dirección base (integer_seq): %p\n\n", (void*)integer_seq);
}

void analyze_2d_memory() {
    char char_matrix[ROWS][COLS] = {
        {'A', 'B', 'C', 'D'},
        {'E', 'F', 'G', 'H'}
    };
    
    printf("Tamaño total de la matriz 2D: %zu bytes\n", sizeof(char_matrix));
    
    for (int i = 0; i < ROWS; ++i) {
        for (int j = 0; j < COLS; ++j) {
            printf("Dir [%d][%d]: %p | Val: %c\n", i, j, (void*)&char_matrix[i][j], char_matrix[i][j]);
        }
    }
    
    printf("\nDirección base (char_matrix): %p\n", (void*)char_matrix);
    printf("Dirección fila 0 (char_matrix[0]): %p\n", (void*)char_matrix[0]);
    printf("Dirección fila 1 (char_matrix[1]): %p\n", (void*)char_matrix[1]);
    printf("Diferencia de direcciones entre filas: %ld bytes\n\n", (long)((char*)char_matrix[1] - (char*)char_matrix[0]));
}

int main() {
    analyze_1d_memory();
    analyze_2d_memory();
    return 0;
}

Decaimiento de Arrays y Paso por Referencia

Cuando un array se pasa como argumento a una función, no se copia el bloque de memoria completo. En su lugar, el array "decae" a un puntero a su primer elemento. Esto implica que las modificaciones dentro de la función afectan directamente a la memoria original. Para arrays bidimensionales de caracteres, es necesario especificar la dimensión de las columnas en el prototipo de la función para que el compilador pueda calcular correctamente los desplazamientos de memoria.

#include <stdio.h>
#include <string.h>

#define MAX_LEN 64

void exchange_text_buffers(char *buffer_a, char *buffer_b) {
    char temp_storage[MAX_LEN];
    
    strncpy(temp_storage, buffer_a, MAX_LEN - 1);
    temp_storage[MAX_LEN - 1] = '\0';
    
    strncpy(buffer_a, buffer_b, MAX_LEN - 1);
    buffer_a[MAX_LEN - 1] = '\0';
    
    strncpy(buffer_b, temp_storage, MAX_LEN - 1);
    buffer_b[MAX_LEN - 1] = '\0';
}

void demonstrate_1d_swap() {
    char msg_alpha[MAX_LEN] = "Error crítico en el sistema.";
    char msg_beta[MAX_LEN] = "Sistema restaurado correctamente.";
    
    printf("Antes del intercambio 1D:\n1: %s\n2: %s\n", msg_alpha, msg_beta);
    exchange_text_buffers(msg_alpha, msg_beta);
    printf("Después del intercambio 1D:\n1: %s\n2: %s\n\n", msg_alpha, msg_beta);
}

void demonstrate_2d_swap() {
    char log_entries[2][MAX_LEN] = {
        "Inicio de sesión fallido",
        "Acceso concedido"
    };
    
    printf("Antes del intercambio 2D:\n1: %s\n2: %s\n", log_entries[0], log_entries[1]);
    exchange_text_buffers(log_entries[0], log_entries[1]);
    printf("Después del intercambio 2D:\n1: %s\n2: %s\n\n", log_entries[0], log_entries[1]);
}

int main() {
    demonstrate_1d_swap();
    demonstrate_2d_swap();
    return 0;
}

Procesamiento de Cadenas: Búsqueda y Extracción

El análisis léxico de cadenas de texto requiere iterar a través de los caracteres manteniendo un estado. Para extraer la palabra más larga de una oración, se puede utilizar un enfoque de un solo paso (single-pass) que rastree la longitud actual y la longitud máxima encontrada, evitando el uso de funciones de tokenización que podrían modificar la cadena original o requerir memoria adicional.

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#define BUFFER_SIZE 512

void extract_longest_word(const char *sentence) {
    int current_len = 0;
    int max_len = 0;
    int max_end_index = 0;
    int i = 0;

    while (sentence[i] != '\0') {
        if (isspace((unsigned char)sentence[i])) {
            current_len = 0;
        } else {
            current_len++;
            if (current_len > max_len) {
                max_len = current_len;
                max_end_index = i + 1;
            }
        }
        i++;
    }

    if (max_len > 0) {
        printf("Palabra más larga (%d caracteres): ", max_len);
        for (int j = max_end_index - max_len; j < max_end_index; ++j) {
            putchar(sentence[j]);
        }
        putchar('\n');
    } else {
        printf("No se encontraron palabras.\n");
    }
}

int main() {
    char input_line[BUFFER_SIZE];
    
    printf("Ingrese una línea de texto (Ctrl+D/Ctrl+Z para salir):\n");
    while (fgets(input_line, sizeof(input_line), stdin) != NULL) {
        input_line[strcspn(input_line, "\n")] = '\0';
        if (strlen(input_line) > 0) {
            extract_longest_word(input_line);
        }
    }
    
    return 0;
}

Conversión de Sistemas Numéricos

La conversión de un entero decimal a otras bases (binaria, octal, hexadecimal) se logra mediante divisiones sucesivas. El residuo de cada división proporciona el dígito en la nueva base, comenzando por el menos significativo. Utilizar una cadena de mapeo de caracteres permite manejar bases hasta 16 de manera uniforme. Un enfoque recursivo o el uso de un búfer invertido resuelve el problema del orden de impresión.

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

const char DIGIT_MAP[] = "0123456789ABCDEF";

void render_base(int value, int base) {
    if (value == 0) {
        printf("0");
        return;
    }
    
    if (value < 0) {
        printf("-");
        value = abs(value);
    }

    char buffer[64];
    int index = 63;
    buffer[index] = '\0';

    while (value > 0) {
        buffer[--index] = DIGIT_MAP[value % base];
        value /= base;
    }

    printf("%s", &buffer[index]);
}

int main() {
    int target_number;
    
    printf("Introduzca un número entero decimal: ");
    while (scanf("%d", &target_number) == 1) {
        printf("Binario : "); render_base(target_number, 2);  printf("\n");
        printf("Octal   : "); render_base(target_number, 8);  printf("\n");
        printf("Hex     : "); render_base(target_number, 16); printf("\n\n");
        printf("Introduzca un número entero decimal (o letra para salir): ");
    }
    
    return 0;
}

Opreaciones con Colecciones: Ordenamiento y Estadísticas

El procesamiento de datos numéricos en arays suele requerir cálculos estadísticos básicos y reorganización de elementos. El algoritmo de ordenamiento burbuja (bubble sort), aunque ineficiente para grandes conjuntos de datos, es didáctico para entender la comparación e intercambio de elementos adyacentes. Para cadenas de texto, la comparación lexicográfica se delega a funciones estándar de biblioteca.

#include <stdio.h>
#include <string.h>

#define STUDENT_COUNT 5
#define NAME_MAX_LEN 32

double calculate_mean(const int *data, int size) {
    double sum = 0.0;
    for (int i = 0; i < size; ++i) {
        sum += data[i];
    }
    return sum / size;
}

void sort_descending(int *data, int size) {
    for (int i = 0; i < size - 1; ++i) {
        for (int j = 0; j < size - i - 1; ++j) {
            if (data[j] < data[j + 1]) {
                int temp = data[j];
                data[j] = data[j + 1];
                data[j + 1] = temp;
            }
        }
    }
}

void sort_names_alphabetically(char names[][NAME_MAX_LEN], int count) {
    char temp_name[NAME_MAX_LEN];
    for (int i = 0; i < count - 1; ++i) {
        for (int j = 0; j < count - i - 1; ++j) {
            if (strcmp(names[j], names[j + 1]) > 0) {
                strcpy(temp_name, names[j]);
                strcpy(names[j], names[j + 1]);
                strcpy(names[j + 1], temp_name);
            }
        }
    }
}

void print_scores(const int *data, int size) {
    for (int i = 0; i < size; ++i) printf("%d ", data[i]);
    printf("\n");
}

void print_names(const char names[][NAME_MAX_LEN], int count) {
    for (int i = 0; i < count; ++i) printf("%s\n", names[i]);
}

int main() {
    int evaluations[STUDENT_COUNT] = {85, 92, 78, 90, 88};
    char roster[][NAME_MAX_LEN] = {"Elena", "Carlos", "Ana", "Miguel", "Sofia"};

    printf("Calificaciones originales: ");
    print_scores(evaluations, STUDENT_COUNT);
    
    double avg = calculate_mean(evaluations, STUDENT_COUNT);
    sort_descending(evaluations, STUDENT_COUNT);
    
    printf("Promedio: %.2f\n", avg);
    printf("Calificaciones ordenadas: ");
    print_scores(evaluations, STUDENT_COUNT);

    printf("\nLista original:\n");
    print_names(roster, STUDENT_COUNT);
    
    sort_names_alphabetically(roster, STUDENT_COUNT);
    
    printf("\nLista ordenada alfabéticamente:\n");
    print_names(roster, STUDENT_COUNT);

    return 0;
}

Manipulación Avanzada de Matrices y Cadenas

Las operaciones a nivel de bits y la manipulación de matrices cuadradas requieren un control preciso de los índices. Para detectar dígitos duplicados en una cadena numérica, una máscara de bits (bitmask) es altamente eficiente. Para desplazar circularmante los elementos de una matriz, se debe preservar el elemento que "desborda" el límite de la fila para colocarlo en la posición inicial.

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define MATRIX_DIM 4

int check_digit_uniqueness(const char *numeric_str) {
    uint32_t seen_mask = 0;
    
    for (int i = 0; numeric_str[i] != '\0'; ++i) {
        if (numeric_str[i] >= '0' && numeric_str[i] <= '9') {
            int bit_pos = numeric_str[i] - '0';
            uint32_t bit_flag = 1U << bit_pos;
            
            if (seen_mask & bit_flag) {
                return 0; // Duplicado encontrado
            }
            seen_mask |= bit_flag;
        }
    }
    return 1; // Todos únicos
}

void shift_matrix_rows_right(int matrix[][MATRIX_DIM], int dim) {
    for (int i = 0; i < dim; ++i) {
        int last_element = matrix[i][dim - 1];
        for (int j = dim - 1; j > 0; --j) {
            matrix[i][j] = matrix[i][j - 1];
        }
        matrix[i][0] = last_element;
    }
}

void display_matrix(const int matrix[][MATRIX_DIM], int dim) {
    for (int i = 0; i < dim; ++i) {
        for (int j = 0; j < dim; ++j) {
            printf("%4d", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    char test_num_1[] = "1234567890";
    char test_num_2[] = "9876543211";
    
    printf("'%s' tiene dígitos únicos? %s\n", test_num_1, check_digit_uniqueness(test_num_1) ? "SI" : "NO");
    printf("'%s' tiene dígitos únicos? %s\n", test_num_2, check_digit_uniqueness(test_num_2) ? "SI" : "NO");

    int grid[MATRIX_DIM][MATRIX_DIM] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
        {13, 14, 15, 16}
    };

    printf("\nMatriz original:\n");
    display_matrix(grid, MATRIX_DIM);

    shift_matrix_rows_right(grid, MATRIX_DIM);

    printf("\nMatriz con filas desplazadas a la derecha:\n");
    display_matrix(grid, MATRIX_DIM);

    return 0;
}

Etiquetas: C-language memory-management array-pointers string-manipulation base-conversion

Publicado el 6-26 04:43