Ir ao conteúdo
  • Cadastre-se
Aislan Silva Costa

C Ordenar Matriz de Structs em C

Recommended Posts

Boas a todos!

 

Estou com um probleminha que não consigo resolver e busco ajuda dos membros. No meu código, leio o conteúdo de um arquivo e guardo em uma string para uso no código, no loop principal, recebo esta string e repasso para a chamada da função QuebrarStrungCompleta, para quebrar separar a string por "\n" e guardar em uma matriz de strings. Depois repassa cada linha dessa matriz para a chamada da função QuebrarStruct, que ira guardar numa struct a linha separada pelos delimitadores ",", vou fornecer o exemplo do arquivos users.txt, quem for testar, pode ver que até tudo funciona bem. O problema e que agora quero ordenar essa matriz de structs, nas pesquisas não achei muitos exemplos e procuro ajuda dos mais experientes.

 

O que tentei foi o seguinte: Crio a função de comparação que e repasssada para a chamada da função qsort:
 

int comparar(const void * a, const void * b)
{

  const Cliente * ia = (Cliente *) a;
  const Cliente * ib = (Cliente *) b;
  return strcmp(ia->cpf, ib->cpf);


}

Depois chama a função qsort, passo como base o ponteiro para minha matriz de structs, e também a função comparar:

qsort(&cliente, 4, sizeof(Cliente), comparar);

printf("As struct's foram ordenadas\n");


for (int i = 0; i < 4; i++)
{

printf("%s\n", cliente[i]->cpf);


}

Tudo compila, o código roda após a chamada da função qsort, porém da erro ao printar, eu Creio que o erro seja porque, qsort espera uma matriz do tipo;

exemplo: Cliente * cliente, e minha matriz e do tipo Cliente **cliente.

 

#include<stdio.h>

#include<stdlib.h>

#include<string.h>



typedef struct Cliente
 {
		
		char cpf[13];
		char realName[60];
		char sexo[11];
		char key[15];
		char data[11];

		
}Cliente;
        
  
       
        
        
        
   char **QuebrarStringCompleta(char *string)
   {
       
       char **linha;
       char *token;
       int tamVetor = 1;
       
       int i = 0;
       
       linha  = malloc(sizeof(char*)*tamVetor);

       linha[i] = malloc(sizeof(char**)*150);
       
       token = strtok(string, "\n");
       
       strcpy(linha[i], token);
       printf("primeira linha e: %s\n", linha[i]);
       
       i++;
       tamVetor++;
       
      
        while (token != NULL)
	 {
          linha = realloc(linha, sizeof(char*)*tamVetor);

          linha[i] = malloc(sizeof(char**)*150);
       
          token = strtok(NULL, "\n");

       
            if (token == NULL)
             {
               printf("token e nulo: %s, break\n", token);
                break;
             }      
            else
              {
                strcpy(linha[i], token);
                i++;       
                tamVetor++;
              }
            }

      return linha;
   }
        
        
        
      Cliente* QuebrarStruct( char *string)
{
	
        
	Cliente *cliente;
	char *token;
       
        cliente = malloc(sizeof(Cliente));
        token = strtok(string,",");
        strcpy(cliente->cpf, token);
	token = strtok(NULL,",");
        strcpy(cliente->realName, token);
	token = strtok(NULL,",");
        strcpy(cliente->sexo, token);
        token = strtok(NULL,",");
        strcpy(cliente->data, token);

	return cliente;
			
}
	
	  


char * ObterDados(int flag)
{
         
    

	FILE *users;	
        char url[] = "/bd/users/users/users.txt";		

if (flag == 1)
{	
	users = fopen(url, "r");

}

	char *string;
        char ch;
         int i = 0;
          int tamVetor = 0;
          
          string = malloc(sizeof (char * ) * tamVetor); 

	if (users == NULL)
	{
		printf("Erro na abertura do arquivo!");
		return 1;
	}
	else
	{
	
		 while ((ch = fgetc(users)) != EOF)
		{
			if (ch == '#')
			{

				while ((ch = fgetc(users)) != EOF)
				{


					string[i] = ch;
                                        
                                        i++;
					tamVetor++;

					string = realloc(string, sizeof(char *) * tamVetor);

                                        
                                        
                                }
                        }
                 }

                 
        }

                
                return string;
       
}


int comparar(const void * a, const void * b)
{

  const Cliente * ia = (Cliente *) a;
  const Cliente * ib = (Cliente *) b;
  return strcmp(ia->cpf, ib->cpf);


}

int main ()

{
    
char *string;
char **result;

string = ObterDados(1);


printf("String e %s: ", string);

result = QuebrarStringCompleta(string);



printf("As linhas separadas sao: ");

for(int i = 0; i < 5 ; i++)
{
 
    if(result[i] == NULL)
        break;
 printf("%s\n", result[i]);   

}



Cliente **cliente;

cliente= malloc(sizeof(Cliente)*5);




if (cliente == NULL) {
   printf ("Socorro! malloc devolveu NULL!\n");
   exit (EXIT_FAILURE);
}


for (int i = 0; i < 4; i++)
{
cliente[i] = QuebrarStruct(result[i]);

printf("Dados retornados e, usuario: %s, nome real: %s, sexo: %s, data: %s\n", cliente[i]->cpf,cliente[i]->realName, cliente[i]->sexo, cliente[i]->data);

}



qsort(&cliente, 4, sizeof(Cliente), comparar);

printf("As struct's foram ordenadas\n");


for (int i = 0; i < 4; i++)
{

printf("%s\n", cliente[i]->cpf);


}


}

Aguardo a ajuda de todos!

 

users.txt

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Aislan Silva Costa Olá. Tenta isso p ver se resolve:

qsort(cliente, 4, sizeof(cliente[0]), comparar); // aqui estão sendo comparados 4 cpfs

Se quer ordenar por nome:

int cmp(const void *a, const void *b) {
    return strcmp(((Cliente *)a)->realName, ((Cliente *)b)->realName);
}

Como não ficou clara qual é a sua dúvida, recomendo dar uma olhada nesse link e assistir a vídeo-aula:

https://programacaodescomplicada.wordpress.com/2014/06/09/ed1-aula-55-ordenacao-usando-a-funcao-qsort/

adicionado 11 minutos depois

Também gostaria de falar q é preciso liberar a memória que você está alocando. Em nenhuma parte do seu código você libera a memória alocada (!?). A função para liberar a memória alocada é a free

Outro ponto, até por boas práticas de programação: Toda vez que criar um ponteiro faça com q ele aponte para NULL (lugar nuenhum) e, assim q fizer uso do ponteiro, faça ele voltar a apontar p NULL. Com isso você evita q seu ponteiro seja um ponteiro solto, ou "ponteiro selvagem". Ex:

char *string = NULL;
char **result = NULL;

Exemplo p liberar a memória alocada e fazer o ponteiro voltar a apontar p NULL:

printf("As struct's foram ordenadas\n");

for (int i = 0; i < 4; i++) {
    printf("%s\n", cliente[i]->cpf);
}

free(cliente); // aqui libera memória q foi alocada para esse ponteiro
free(string);

string = NULL; // aqui faz o ponteiro voltar a apontar p NULL
result = NULL;

  // fim do main

Vê se é isso. Qualquer coisa é só pedir, ok?

adicionado 35 minutos depois

Obs: No final do seu código, no último for do main faça isso e vai ver q está ordenando corretamente:

for (int i = 0; i < 4; i++) {
    printf("%s\n", cliente[i]->realName);
}

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Aislan Silva Costa Procure perceber o quanto é importante uma boa e adequada identação de um código.

Se quiser dá uma olhada nesse link:

https://www.tutorialspoint.com/online_c_formatter.htm

Caso não esteja mesmo disposto a usar uma boa identação nos seus códigos, faça uso da ferramenta do link acima q deixa seu código devidamente identado. ISSO VALE NOTA!!!

Veja seu código identado abaixo e perceba a diferença:

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

typedef struct Cliente
{
    char cpf[13];
    char realName[60];
    char sexo[11];
    char key[15];
    char data[11];
} Cliente;

char **QuebrarStringCompleta(char *string)
{
    char **linha = NULL;
    char *token = NULL;
    int tamVetor = 1;

    int i = 0;

    linha  = malloc(sizeof(char*)*tamVetor);

    linha[i] = malloc(sizeof(char**)*150);

    token = strtok(string, "\n");

    strcpy(linha[i], token);
    printf("primeira linha e: %s\n", linha[i]);

    i++;
    tamVetor++;

    while (token != NULL)
    {
        linha = realloc(linha, sizeof(char*)*tamVetor);

        linha[i] = malloc(sizeof(char**)*150);

        token = strtok(NULL, "\n");

        if (token == NULL)
        {
            printf("token e nulo: %s, break\n", token);
            break;
        }
        else
        {
            strcpy(linha[i], token);
            i++;
            tamVetor++;
        }
    }
    return linha;
}

Cliente* QuebrarStruct( char *string)
{
    Cliente *cliente = NULL;
    char *token = NULL;

    cliente = malloc(sizeof(Cliente));
    token = strtok(string,",");
    strcpy(cliente->cpf, token);
    token = strtok(NULL,",");
    strcpy(cliente->realName, token);
    token = strtok(NULL,",");
    strcpy(cliente->sexo, token);
    token = strtok(NULL,",");
    strcpy(cliente->data, token);

    return cliente;
}

char * ObterDados(int flag)
{
    FILE *users = NULL;
    char url[] = "users.txt";

    if (flag == 1)
    {
        users = fopen(url, "r");
    }

    char *string = NULL;
    char ch;
    int i = 0;
    int tamVetor = 0;

    string = malloc(sizeof (char * ) * tamVetor);

    if (users == NULL)
    {
        printf("Erro na abertura do arquivo!");
        return 0;
    }
    else
    {
        while ((ch = fgetc(users)) != EOF)
        {
            if (ch == '#')
            {
                while ((ch = fgetc(users)) != EOF)
                {
                    string[i] = ch;
                    i++;
                    tamVetor++;
                    string = realloc(string, sizeof(char *) * tamVetor);
                }
            }
        }
    }
    return string;
}


int comparar(const void * a, const void * b)
{
    const Cliente * ia = (Cliente *) a;
    const Cliente * ib = (Cliente *) b;
    return strcmp(ia->cpf, ib->cpf);
}

int cmp(const void *a, const void *b) {
    return strcmp(((Cliente *)a)->realName, ((Cliente *)b)->realName);
}

int main ()
{
    char *string = NULL;
    char **result = NULL;

    string = ObterDados(1);

    printf("String e %s: ", string);

    result = QuebrarStringCompleta(string);

    printf("As linhas separadas sao: ");

    for(int i = 0; i < 5 ; i++)
    {
        if(result[i] == NULL)
            break;
        printf("%s\n", result[i]);
    }

    Cliente **cliente = NULL;

    cliente= malloc(sizeof(Cliente)*5);

    if (cliente == NULL) {
        printf ("Socorro! malloc devolveu NULL!\n");
        exit (EXIT_FAILURE);
    }

    for (int i = 0; i < 10; i++)
    {
        cliente[i] = QuebrarStruct(result[i]);
        printf("Dados retornados e, usuario: %s, nome real: %s, sexo: %s, data: %s\n", cliente[i]->cpf, cliente[i]->realName, cliente[i]->sexo, cliente[i]->data);
    }

    qsort(cliente, 10, sizeof(cliente[0]), comparar);

    printf("As struct's foram ordenadas\n");

    for (int i = 0; i < 10; i++) {
        printf("%s\n", cliente[i]->realName);
    }

    free(cliente); // aqui libera memória q foi alocada para esse ponteiro
    free(string);

    string = NULL; // aqui faz o ponteiro voltar a apontar p NULL
    result = NULL;
}

Consegue ver como muda tudo em um código uma boa identação?

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×