Mudança de valor em variável ponteiro global na linguagem C

Prezados,

Estou desenvolvendo um jogo de cartas em C. Utilizo duas variáveis globais do tipo ponteiro para Lista (TAD).

    Lista* M_l; //Montante de compra
    Lista* G_l; //Pilha de descarte

Inicializo a lista M_l com todas as cartas do jogo.
A lista G_l permanece nula até que uma carta é jogada sobre a mesa (Pilha de descarte).

A fim de distribuir uma carta de G_l para M_l no início do jogo, criei a seguinte função que transfere n cartas do tipo Lista *.

void transferirCartas(Lista *listDest, Lista *listOrig, int n);

Basicamente, uso duas rotinas do TAD lista para inserir e remover cartas da lista:

    carta temp = lst_ObterCarta(listOrig);
    listDest = lst_Insere(listDest, temp);
    listOrig = lst_Remove(listOrig);

Ao usar esse procedimento percebi que quando altero *listDest e *listOrig dentro da rotina, as variáveis globais M_l e G_l não sofrem alterações, e portanto, M_l por exemplo, continua a ficar nula (Sem cartas inseridas),

Porém, ao usar a rotina ou apenas invocar as mesmas rotinas do TAD lista abaixo usando como argumento as variáveis globais de fato : G_l e M_l - consigo realizar a transferência de cartas normalmente. (Isso não ocorre quando outra variável local as recebe como na rotina acima ou na própria main quando faço apontamento direto e realizo inserção e remoção).

 carta temp = lst_ObterCarta(G_l);
 M_l = lst_Insere(M_l, temp);
 G_l = lst_Remove(G_l);

Alguém sabe o que pode estar ocorrendo? (Pensei que pode ser algo relacionado com heap, stacks e retornos das chamadas de função).

A implementação do TAD Lista está neste Link>> github <<

Grato pela ajuda!

vejamos:

/* Insere no inicio da Lista */
Lista *lst_Insere(Lista *atual, carta c)
{

    Lista *novo = (Lista *)malloc(sizeof(Lista));
    novo->Carta = c;
    novo->prox = atual;
    return novo;
}

aqui vc claramente esta criando uma nova lista, o que é curioso pois a sua estrutura de dados Lista possui uma Carta e o prox é de novo uma Lista. Não parece ser uma Lista e sim um Nó, como vc precisa inserir na frente vc não tem outra opção alem de criar um novo Nó e adicionar a lista antiga.

Uma lista é uma coleção de Nos (na minha opiniao). Eu imagino a Lista como algo que contem um tamanho e o um ponteiro para o primeiro No (a cabeça, ou rabo da lista / head, tail ).

Vc ate pode ignorar essa questão de No x Lista e chamar tudo de lista, mas o seu ponteiro global tem que apontar sempre para o primeiro elemento. A ordem das suas operações vai importar

1 curtida

Discordo sobre, a estrutura de dados criada permite a inserção no início. Não deixa de ser uma Lista encadeada.
Voltando ao assunto central, eu entendi sobre o que disse. Mas repare com essas hipóteses:

Usando as rotinas abaixo dentro de um procedimento ou uma função como a ‘Main’, as variáveis globais não são atualizadas. O estranho é que passo o ponteiro como explicitei na rotina que transfere cartas, logo, a inserção e remoção deveria atualizar os ponteiros globais, concorda?.

    carta temp = lst_ObterCarta(listOrig);
    listDest = lst_Insere(listDest, temp);
    listOrig = lst_Remove(listOrig); 

Desse modo, funciona:

carta temp = lst_ObterCarta(G_l);
 M_l = lst_Insere(M_l, temp);
 G_l = lst_Remove(G_l);

Então acho que o código acima não deveria funciona também :).
Grato!

Vamos la

Vc tem uma variavel global x

x é do tipo ponteiro para estrutura que contem valor e um ponteiro pra próxima estrutura

Então se vc inicia assim:

x->value = 1;
x->next = NULL;

Só tem um elemento, certo?

Vamos adicionar mais um, ai vc precisa criar uma nova estrutura

Vc vai adicionar onde? Se vc adicionar no fim, então

y = aquele malloc maroto;
y->value = 2;
y->next = NULL;
x->next = y;

Pronto, o x global foi atualizado E vc começa em x (value1) e chega no próximo (value 2)

Agora se vc quer inserir na frente, o x global vai continuar apontando para o antigo elemento.

y = aquele malloc maroto;
y->value = 2;
y->next = x;

a sua lista começa em y! A variável global x não sabe de nada pois vc não fez nada com ela. Como resolver?

y = aquele malloc maroto;
y->value = 2;
y->next = x;
x = y; // tcharam!

x não é uma estrutura de dados

x é um ponteiro para uma estrutura de dados

a estrutura tem um valor (bytes).

o ponteiro tem um valor q é o endereço dessa estrutura na memória

Então

// x tem endereço 100
y = aquele malloc maroto; // y tem endereço 200
y->value = 2;
y->next = x; // next aponta para 100
x = y; // agora x aponta para 200 (cujo next aponta pra 100)

Posso ter errado algo, verifique :slight_smile:

2 curtidas

Fez sentido o seu exemplo. Um dos motivos que usei a inserção no início foi por simular um montante de cartas (Pilha), no entanto, vejo que a simplicidade em fazer isso tornou o código menos modular e genérico, já que dependendo da função como a transferirCartas vai ser necessário tratar por fora em outras rotinas os ponteiros globais (atualização do endereço) e etc. Sem falar que o uso de variáveis globais não é uma boa prática, meu exemplo sugere que se fosse usado variáveis locais, eu não teria essa preocupação de inserção no início ou final. Concorda com meu ponto de vista? Agradeço pelos esclarecimentos :slight_smile:

Depende

Conforme os programas crescem em complexidade, pode ficar cada vez mais difícil controlar o estado global - principalmente se existir concorrência/multi-threading

Se o seu programa precisa de uma variável global, e vc pode substituir por uma variável local isso não me parece um grande problema (tanto faz). Agora 20 ja fica mais complicado

A chave do bom design é imaginar como vc vai testar a sua aplicação. Se vc começar a pensar em termos de TDD vai preferir evitar globais pois a complexidade para escrever testes cresce.

Se o seu baralho só existe durante o jogo e é manipulado pelas etapas do jogo, fica mais legível o uso de variável local, pois vc olha a função e ja sabe o que acontece

1 curtida