Em ambientes onde a alocação dinâmica de memória não é permitida ou disponível, podemos simular o comportamento de ponteiros e listas ligadas utilizando uma estrutura conhecida como Cursor. Essa técnica utiliza um array global de estruturas para gerecniar a memória manualmente, onde os índices do array atuam como endereços de memória.
Definição da Estrutura e Interface
Para implementar um sistema baseado em cursores, definimos um array de estruturas onde cada "nó" contém um campo de dados e um índice para o próximo elemento. O índice 0 geralmente é reservado para atuar como a cabeça de uma lista de blocos livres.
#ifndef CURSOR_H
#define CURSOR_H
#define CAPACIDADE 50
#define CURSOR_NULO 0
typedef int Posicao;
typedef Posicao Lista;
typedef struct {
int Conteudo;
Posicao Proximo;
} Nodo;
// Pool de memória global simulado
extern Nodo EspacoCursor[CAPACIDADE];
void InicializarGerenciador();
Posicao AlocarNodo();
void DesalocarNodo(Posicao p);
Lista CriarLista();
int VerificarVazia(const Lista L);
Posicao Buscar(int valor, const Lista L);
void InserirElemento(int valor, Lista L, Posicao p);
void Remover(int valor, Lista L);
Posicao BuscarAnterior(int valor, const Lista L);
#endif
Implementação do Gerenciamento de Memória
A lógica central reside em manter uma lista encadeada de nós disponíveis dentro do array. Quando um novo nó é necessário, nós o removemos da lista de "espaço livre". Quando um nó é excluído, ele retorna para essa lista.
#include "cursor.h"
#include <stdio.h>
Nodo EspacoCursor[CAPACIDADE];
// Inicializa o array encadeando todos os elementos na lista de livres
void InicializarGerenciador() {
for (int i = 0; i < CAPACIDADE - 1; i++) {
EspacoCursor[i].Conteudo = 0;
EspacoCursor[i].Proximo = i + 1;
}
EspacoCursor[CAPACIDADE - 1].Proximo = CURSOR_NULO;
}
Posicao AlocarNodo() {
Posicao p = EspacoCursor[0].Proximo;
if (p == CURSOR_NULO) {
fprintf(stderr, "Erro: Memória insuficiente no pool.\n");
return CURSOR_NULO;
}
EspacoCursor[0].Proximo = EspacoCursor[p].Proximo;
return p;
}
void DesalocarNodo(Posicao p) {
EspacoCursor[p].Conteudo = 0;
EspacoCursor[p].Proximo = EspacoCursor[0].Proximo;
EspacoCursor[0].Proximo = p;
}
Lista CriarLista() {
Lista L = AlocarNodo();
if (L != CURSOR_NULO) {
EspacoCursor[L].Proximo = CURSOR_NULO;
}
return L;
}
int VerificarVazia(const Lista L) {
return EspacoCursor[L].Proximo == CURSOR_NULO;
}
Manipulação da Lista de Dados
As funções de busca e inserção seguem a lógica clássica de listas ligadas, mas substituindo o acesso a ponteiros (->next) pelo acesso ao índice do array (EspacoCursor[p].Proximo).
Posicao Buscar(int valor, const Lista L) {
Posicao p = EspacoCursor[L].Proximo;
while (p != CURSOR_NULO && EspacoCursor[p].Conteudo != valor) {
p = EspacoCursor[p].Proximo;
}
return p;
}
Posicao BuscarAnterior(int valor, const Lista L) {
Posicao p = L;
while (EspacoCursor[p].Proximo != CURSOR_NULO &&
EspacoCursor[EspacoCursor[p].Proximo].Conteudo != valor) {
p = EspacoCursor[p].Proximo;
}
return p;
}
void InserirElemento(int valor, Lista L, Posicao p) {
Posicao novo = AlocarNodo();
if (novo == CURSOR_NULO) return;
EspacoCursor[novo].Conteudo = valor;
EspacoCursor[novo].Proximo = EspacoCursor[p].Proximo;
EspacoCursor[p].Proximo = novo;
}
void Remover(int valor, Lista L) {
Posicao anterior = BuscarAnterior(valor, L);
if (EspacoCursor[anterior].Proximo != CURSOR_NULO) {
Posicao temp = EspacoCursor[anterior].Proximo;
EspacoCursor[anterior].Proximo = EspacoCursor[temp].Proximo;
DesalocarNodo(temp);
}
}
Exemplo de Utilização
O código abaixo demonstra como inicializar o pool e realizar operações básicas. Um ponto crítico em C é garantir que variáveis globais ou arrays compartilhados declarados em headers usem o qualificador extern para evitar erros de múltipla definição durante a linkagem.
#include <stdio.h>
#include "cursor.h"
int main() {
InicializarGerenciador();
Lista minhaLista = CriarLista();
if (VerificarVazia(minhaLista)) {
printf("Lista inicializada corretamente.\n");
}
// Inserindo elementos
InserirElemento(10, minhaLista, minhaLista);
InserirElemento(20, minhaLista, minhaLista);
Posicao pos = Buscar(10, minhaLista);
if (pos != CURSOR_NULO) {
printf("Elemento 10 encontrado na posicao: %d\n", pos);
}
Remover(10, minhaLista);
printf("Apos remover 10, proximo do header: %d\n", EspacoCursor[minhaLista].Proximo);
return 0;
}
A implementação baseada em cursores é uma excelente forma de entender a abstração da memória. Ao tratar índices como endereços, o desenvolvedor ganha controle total sobre a disposição dos dados e evita a fragmentação comum em alocações dinâmicas de pequena escala.