Problema de array dinâmico de apontadores para estruturas em C

Sidner

Power Member
Ora bem, eu tenho um clico que me está a ler linhas de um ficheiro, linha essas cujos campos estão a preencher uma estrutura apontada por um apontador para essa estrutura (CONTA*), apontador esse que depois está a ser adicionado a um array dinâmico de apontadores (CONTA**).


Isto está dentro dum ciclo while(!feof)
Código:
CONTA** contas; // como variável global


CONTA* conta_ = (CONTA*)malloc(sizeof(CONTA));
printf("\n%p\n", conta_);
size_of_contas++;
contas = (CONTA**)realloc(contas,size_of_contas*sizeof(CONTA*));
tok = strtok(linha, " ");
(*conta_).nconta = atoi(tok);
tok = strtok(NULL, " ");
strcat(nome, tok);
strcat(nome, " ");
tok = strtok(NULL, " ");
strcat(nome, tok);
strcpy((*conta_).nome, nome);
tok = strtok(NULL," ");
strcpy((*conta_).pin, tok);
tok = strtok(NULL," ");
(*conta_).saldo = atof(tok);
contas[size_of_contas-1] = conta_;
printf("%p\t%07u\t%s\t%s\t%.2lf\n", (contas[size_of_contas-1]),(*contas[size_of_contas-1]).nconta, (*contas[size_of_contas-1]).nome, (*contas[size_of_contas-1]).pin, (*contas[size_of_contas-1]).saldo);

Pois bem, o meu problema é que tenho o seguinte: tendo três contas, aquele printf no ciclo dá-me o seguinte output (melhor formatado):
Código:
0x20f3160	0000001	Ana Santos	        9876	10.00


0x20f3190	0000003	Pedro Pereira	0007	1234.53


0x20f31c0	0000004	Rui Sousa	        1234	0.00

Quando faço o mesmo printf mas já depois do ciclo, ou seja, com o array já cheio, dá-me o seguinte output:
Código:
0x20f3160	0000004	Rui Sousa	1234	0.00


0x20f3190	0000004	Rui Sousa	1234	0.00


0x20f31c0	0000004	Rui Sousa	1234	0.00

Precisava mesmo de ajuda, porque eu não percebo o que se passa...
 
Põe ai o printf que estás a usar depois do ciclo.

Cheira-me que o problema está ai.

PS. não faças realloc de 1 em 1. Se não tens hipotese de saber o tamanho à partida, usa um buffer (ex. de 100 em 100) e só fazes realloc quando passar isso.
 
Código:
for( i = 0; i<size_of_contas;i++)
    {
        printf("\n%p\t%07u\t%s\t%s\t%.2lf\n",contas[i], (*contas[size_of_contas-1]).nconta, (*contas[size_of_contas-1]).nome, (*contas[size_of_contas-1]).pin, (*contas[size_of_contas-1]).saldo);
    }

Mas eu não sei nem tenho de saber o tamanho à partida, pois ele vai aumentando consoante o número de contas que existam... Assim escusava de alocar memória desnecessáriamente.

QUE ESTÚPIDO!!!! -_- Só agora me dei conta do erro nos índices.... omg....
 
Última edição:
Foi o que pensei.

Relativamente ao realloc, não faças isso assim. Não uses um array de CONTA (CONTA **), usa uma lista.

Na estrutura CONTA, coloca mais um campo: CONTA *next, e vais alocando à medida da necessidade.
 
Foi o que pensei.

Relativamente ao realloc, não faças isso assim. Não uses um array de CONTA (CONTA **), usa uma lista.

Na estrutura CONTA, coloca mais um campo: CONTA *next, e vais alocando à medida da necessidade.

Tou um bocado em cima do prazo, mas porque é que aconselhas a usar lista em vez de realloc? Já agora, consegues-me explicar como usaria o qsort neste cenário? É que isto não me está a ordenar implementado assim:

Código:
static int cmpcontas(const void *p1, const void *p2)
{
	printf("bestaaaa\n");
	printf("nconta1: %u\tnconta2: %u\n", (*(CONTA*)p1).nconta, (*(CONTA*)p2).nconta);
	return ((*(CONTA*)p1).nconta - (*(CONTA*)p2).nconta);
}

qsort(contas, size_of_contas, sizeof(contas[0]),cmpcontas);

O que faz com que o bsearch não está a funcionar também... Desconfio que seja a função cmpcontas, mas não consigo pô-la direita...
 
Tou um bocado em cima do prazo, mas porque é que aconselhas a usar lista em vez de realloc?

Se estás em cima do prazo não mudes, como é obvio. A minha observação só se deve a fazer-me alguma confusão fazer reallocs dentro de um ciclo. Um realloc envolve, potencualmente, um malloc, memcpy e free, o que pode ser pesado. Agora, a verdade é que isso depende de como está implementado o realloc na stdlib. Pode ser que este aloque blocos e so faça realloc quando chegar ao fim do bloco, o que já terá um impacto (potencialmente) minimo.

A questão de usar listas é que, olhando para o pedaço de código que puses-te, e já estando a alocar a estrutura conta, ficava mais rápido implementares uma lista, dado que não tinhas que fazer allocs ao array (CONTA **), mas somente gerir os ponteiros next. Ficava mais limpo.

Por outro lado, não sabendo os restantes requisitos da aplicação, não posso afirmar que mudar para listas seja uma boa opção, ou sequer uma opção aceitável (como demonstras a seguir, dado que pretendes fazer sort ao array, e nesse caso é provavelmente mais correcto utilizar o array).

Fica só com a ideia de que, dentro de um ciclo, deves ter em atenção às operações que fazes, para minimizar o impacto na performance.


Já agora, consegues-me explicar como usaria o qsort neste cenário? É que isto não me está a ordenar implementado assim:

Código:
static int cmpcontas(const void *p1, const void *p2)
{
    printf("bestaaaa\n");
    printf("nconta1: %u\tnconta2: %u\n", (*(CONTA*)p1).nconta, (*(CONTA*)p2).nconta);
    return ((*(CONTA*)p1).nconta - (*(CONTA*)p2).nconta);
}

qsort(contas, size_of_contas, sizeof(contas[0]),cmpcontas);

O que faz com que o bsearch não está a funcionar também... Desconfio que seja a função cmpcontas, mas não consigo pô-la direita...

Olhando à primeira vista, parece-me que estas a confundir ponteiros com ponteiros para ponteiros. Olha para a definição do qsort:

Código:
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );

o que estás a passar: contas que é CONTA **, logo, o que recebes em p1 e p2 é CONTA **...

o p1 está a apontar para um elemento do array, logo p1 é CONTA **. (*p1) é (CONTA *), e tu queres é **p1.numconta (com o cast correcto). O melhor é fazeres (*p1)->numconta que é mais visivel.

Isso está-te a rebentar não está?
 
Estava sim senhor. :P Entretanto andei a estudar um bocadinho e descobri que tinha de ser assim:
Código:
static int cmpcontas(const void *p1, const void *p2)
{
	CONTA* c1 = *(CONTA**)p1;
	CONTA* c2 = *(CONTA**)p2;
	
	unsigned int i = (*c1).nconta - (*c2).nconta;
	return i;
}

:) Obrigado pela ajuda e pela explicação. Vou passar a ter em atenção isso do realloc em ciclos, parece-me um bom ponto de vista, o teu.
 
Agora está bem, excepto...

O que é que está ai a fazer o "unsigned"? tu queres é mesmo só int, para poderes retornares numeros negativos, para que o qsort funcione.

Isso ainda não te está a funcionar pois não?
 
Epá....Ele tá a funcionar, para ser sincero... Mas realmente, vou alterar isso, não faz sentido ser um unsigned int. Thanks. :)

Edit: Só para acrescentar que acabei tudo! :P Só não fiz a valorização, que consistia numa sincronização não tão limitadora como a que estou a usar...mas é para entregar daqui a 1h, por isso... Paciência.
 
Última edição:
Lê bem as instruções porque eles querem aquilo à maneira deles, os nomes de ficheiros e directorias, e pelo menos no meu caso ainda demorou a alterar tudo.
 
Back
Topo