How to transform my code with struct from static memory to dynamics in C?

4

The exercise asks me to read information in a file, being they, cpf, name, email and age of several people stored in a struct, sort in ascending order by age, if equal ages by cpf, and print in another file with the same format as it received, all the information of a person is separated by comma and from one person to another by different line. And I already know the maximum size of the information, however do not know the number of lines. I have done using static memory but I must create a vector of structs using memory and dynamics and I am not able to do this.

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

typedef struct{
 char CPF[12];
 char nome[41];
 char email[31];
 int idade;
}Dado;

int main()
{
FILE *arq, *arqout;
char ch;
int num=0,i,j,aux;

arq = fopen("read.txt","r");
while( fscanf(arq,"%c", &ch)!= EOF )
    if(ch == '\n')
    num++;
rewind(arq);
Dado pimpolho[num+1];

for (i=0;i<num;i++)
{
    j=0;
    fscanf(arq,"%c", &ch);
    while( ch != ',')
    {
        pimpolho[i].CPF[j] = ch;
        fscanf(arq,"%c", &ch);
        j++;
    }
    pimpolho[i].CPF[j] = '
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
 char CPF[12];
 char nome[41];
 char email[31];
 int idade;
}Dado;

int main()
{
FILE *arq, *arqout;
char ch;
int num=0,i,j,aux;

arq = fopen("read.txt","r");
while( fscanf(arq,"%c", &ch)!= EOF )
    if(ch == '\n')
    num++;
rewind(arq);
Dado pimpolho[num+1];

for (i=0;i<num;i++)
{
    j=0;
    fscanf(arq,"%c", &ch);
    while( ch != ',')
    {
        pimpolho[i].CPF[j] = ch;
        fscanf(arq,"%c", &ch);
        j++;
    }
    pimpolho[i].CPF[j] = '%pre%';
    j=0;
    fscanf(arq,"%c", &ch);
    while( ch != ',')
    {
        pimpolho[i].nome[j] = ch;
        fscanf(arq,"%c", &ch);
        j++;
    }
    pimpolho[i].nome[j] = '%pre%';
    j=0;
    fscanf(arq,"%c", &ch);
    while( ch != ',')
    {
        pimpolho[i].email[j] = ch;
        fscanf(arq,"%c", &ch);
        j++;
    }
    pimpolho[i].email[j] = '%pre%';
    fscanf(arq, "%d", &pimpolho[i].idade);
    fscanf(arq,"%c", &ch);
}

for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade > pimpolho[j+1].idade)
        {
            pimpolho[num] = pimpolho[j];
            pimpolho[j] = pimpolho[j+1];
            pimpolho[j+1] = pimpolho[num];
        }
for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade == pimpolho[j+1].idade)
        {
            aux = strncmp(pimpolho[j].CPF,pimpolho[j+1].CPF,11);
            if (aux>0)
            {
                pimpolho[num] = pimpolho[j];
                pimpolho[j] = pimpolho[j+1];
                pimpolho[j+1] = pimpolho[num];
            }
        }
arqout = fopen("write.txt","w");
for (i=0;i<num;i++)
{
     fprintf(arqout,"%s,%s,%s,%d\n",pimpolho[i].CPF,pimpolho[i].nome,pimpolho[i].email,pimpolho[i].idade);
}
fclose(arqout);
fclose(arq);
return 0;
}
'; j=0; fscanf(arq,"%c", &ch); while( ch != ',') { pimpolho[i].nome[j] = ch; fscanf(arq,"%c", &ch); j++; } pimpolho[i].nome[j] = '%pre%'; j=0; fscanf(arq,"%c", &ch); while( ch != ',') { pimpolho[i].email[j] = ch; fscanf(arq,"%c", &ch); j++; } pimpolho[i].email[j] = '%pre%'; fscanf(arq, "%d", &pimpolho[i].idade); fscanf(arq,"%c", &ch); } for (i = num - 1; i > 0; i--) for (j = 0; j < i; j++) if (pimpolho[j].idade > pimpolho[j+1].idade) { pimpolho[num] = pimpolho[j]; pimpolho[j] = pimpolho[j+1]; pimpolho[j+1] = pimpolho[num]; } for (i = num - 1; i > 0; i--) for (j = 0; j < i; j++) if (pimpolho[j].idade == pimpolho[j+1].idade) { aux = strncmp(pimpolho[j].CPF,pimpolho[j+1].CPF,11); if (aux>0) { pimpolho[num] = pimpolho[j]; pimpolho[j] = pimpolho[j+1]; pimpolho[j+1] = pimpolho[num]; } } arqout = fopen("write.txt","w"); for (i=0;i<num;i++) { fprintf(arqout,"%s,%s,%s,%d\n",pimpolho[i].CPF,pimpolho[i].nome,pimpolho[i].email,pimpolho[i].idade); } fclose(arqout); fclose(arq); return 0; }

Is it possible to change this with some changes?

    
asked by anonymous 13.09.2018 / 22:38

2 answers

3

Dynamic allocation with vector

Allocating dynamically is as simple as calling malloc directly:

Dado *pimpolho = malloc(sizeof(Dado) * (num+1));

The rest you have works because when you do pimpolho[i] is equivalent to doing *(pimpolho + i) . It is simply a question of whether you use array syntax or pointer syntax, and array is simpler and should therefore be used when possible.

Note : As I said in the commentary, for the example you have this does not bring any advantage, quite the contrary, it makes the allocation more complicated, just as it can make some parts of the code more complicated in this case not) and forces you to worry about releasing it with free when you no longer need it. In this case how you will use the vector until the end of the program is not worth releasing the memory because it will already be released at the end of it but in other cases it has to do it otherwise memory leaks.

So do not do this in your programs unless it has a concrete goal and benefits.

Refactoring

I do not want to let go of some important refactorings that you can do that are not complicated. Avoid maximizing the repetition of logic, as this brings much more trouble than it seems. Looking at reading the fields you have:

for (i=0;i<num;i++)
{
    j=0;
    fscanf(arq,"%c", &ch);
    while( ch != ',')
    {
        pimpolho[i].CPF[j] = ch;
        fscanf(arq,"%c", &ch);
        j++;
    }
    pimpolho[i].CPF[j] = '
void ler_string_arq(FILE* arq, char *campo_destino){
    int letra = 0;
    char ch;
    fscanf(arq,"%c", &ch);
    while( ch != ',') {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '
for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade > pimpolho[j+1].idade)
        {
            pimpolho[num] = pimpolho[j];
            pimpolho[j] = pimpolho[j+1];
            pimpolho[j+1] = pimpolho[num];
        }

for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade == pimpolho[j+1].idade)
        {
            aux = strncmp(pimpolho[j].CPF,pimpolho[j+1].CPF,11);
            if (aux>0)
            {
                pimpolho[num] = pimpolho[j];
                pimpolho[j] = pimpolho[j+1];
                pimpolho[j+1] = pimpolho[num];
            }
        }
'; } int main() { //... for (i=0; i<num; i++) { ler_string_arq(arq, pimpolho[i].CPF); ler_string_arq(arq, pimpolho[i].nome); ler_string_arq(arq, pimpolho[i].email); fscanf(arq, "%d", &pimpolho[i].idade); fscanf(arq,"%c", &ch); }
'; j=0; fscanf(arq,"%c", &ch); while( ch != ',') { pimpolho[i].nome[j] = ch; fscanf(arq,"%c", &ch); j++; } pimpolho[i].nome[j] = '
for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade > pimpolho[j+1].idade ||
            (pimpolho[j].idade == pimpolho[j+1].idade && strncmp(pimpolho[j].CPF,pimpolho[j+1].CPF,11) > 0)){
            pimpolho[num] = pimpolho[j];
            pimpolho[j] = pimpolho[j+1];
            pimpolho[j+1] = pimpolho[num];
        }
'; j=0; fscanf(arq,"%c", &ch); while( ch != ',') { pimpolho[i].email[j] = ch; fscanf(arq,"%c", &ch); j++; } pimpolho[i].email[j] = '
typedef struct Dado{
//               ^----
    char CPF[12];
    char nome[41];
    char email[31];
    int idade;
    struct Dado* proximo; //<---
} Dado;
'; fscanf(arq, "%d", &pimpolho[i].idade); fscanf(arq,"%c", &ch); }

This actually corresponds to reading the 4 fields, the CPF, name, email and age, with the first 3 being the same. But the code was repeated. Not only is it harder to read, but it gets more extensive and propitious to go wrong when you need to change it so you have to change it in all places right. Whenever this happens, abstract the equal logic for a function and call it. Now look how much better it is:

int ler_string_arq(FILE* arq, char *campo_destino){
//^----tipo int agora
    int letra = 0;
    char ch;
    if (fscanf(arq,"%c", &ch) != 1){ //se não leu um char então chegou ao fim
        return 0;
    }

    while( ch != ',') {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '
Dado *inicio_lista = NULL, *ultima = NULL; //ponteiros para lista e ultima pessoa

while(1) {
    Dado *pessoa = malloc(sizeof(Dado)); //cria nova pessoa com alocação dinamica
    pessoa->proximo = NULL; //proximo da pessoa criada é nulo
    if (inicio_lista  == NULL){ //se ainda nao tem nenhuma esta é a primeira 
        inicio_lista = pessoa;
    }
    if (ultima != NULL) { //se já tem pessoas liga a anterior a esta
        ultima->proximo = pessoa;
    }

    if (!ler_string_arq(arq, pessoa->CPF)){ //se apanhou EOF
        free(pessoa);
        ultima->proximo = NULL;
        break; //sai
    }
    ultima = pessoa;

    ler_string_arq(arq, pessoa->nome);
    ler_string_arq(arq, pessoa->email);
    fscanf(arq, "%d", &pessoa->idade);
    fscanf(arq,"%c", &ch);
}
fclose(arq);
'; return 1; }

In ordering it has the same problem because it repeats two ordering logics first by sorting by age, and then sorting those that have the same age:

arqout = fopen("write.txt","w");
Dado* pessoa = inicio_lista;
while (pessoa!= NULL){ //enquanto nao chega ao fim da lista
    fprintf(arqout,"%s,%s,%s,%d\n", pessoa->CPF, pessoa->nome, pessoa->email, pessoa->idade);
    pessoa = pessoa->proximo; //avança para a proxima pessoa
}

This is entirely unnecessary because you can do both at once:

Dado *pimpolho = malloc(sizeof(Dado) * (num+1));

I will not dwell on this part, but keep in mind that the change made in the order is by copy. This can become quite inefficient if the amount of data is too large as it requires having to copy lots of bytes from side to side to make the switch. The way to solve is to use an array of pointers instead of an array with all the objects directly, but this implies changing the code almost all, and is probably overdone for the exercise in question.

There are other things that I can improve of course, but I focused on only those that are stronger and have more impact on the code in general.

Dynamic allocation with list

The small difference of using a list instead of a vector already makes perfect sense, because in fact when using a list you do not need to know how many elements you have previously. This means that you do not have to go through the file twice, being the first to find the number of people that exist. You can simply read, allocate and link the pointers to each other. Now the code itself is more complicated because it involves allocations, pointer changes, memory release, etc ...

First implies changing the structure so that each person can have a pointer to the next one:

for (i=0;i<num;i++)
{
    j=0;
    fscanf(arq,"%c", &ch);
    while( ch != ',')
    {
        pimpolho[i].CPF[j] = ch;
        fscanf(arq,"%c", &ch);
        j++;
    }
    pimpolho[i].CPF[j] = '
void ler_string_arq(FILE* arq, char *campo_destino){
    int letra = 0;
    char ch;
    fscanf(arq,"%c", &ch);
    while( ch != ',') {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '
for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade > pimpolho[j+1].idade)
        {
            pimpolho[num] = pimpolho[j];
            pimpolho[j] = pimpolho[j+1];
            pimpolho[j+1] = pimpolho[num];
        }

for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade == pimpolho[j+1].idade)
        {
            aux = strncmp(pimpolho[j].CPF,pimpolho[j+1].CPF,11);
            if (aux>0)
            {
                pimpolho[num] = pimpolho[j];
                pimpolho[j] = pimpolho[j+1];
                pimpolho[j+1] = pimpolho[num];
            }
        }
'; } int main() { //... for (i=0; i<num; i++) { ler_string_arq(arq, pimpolho[i].CPF); ler_string_arq(arq, pimpolho[i].nome); ler_string_arq(arq, pimpolho[i].email); fscanf(arq, "%d", &pimpolho[i].idade); fscanf(arq,"%c", &ch); }
'; j=0; fscanf(arq,"%c", &ch); while( ch != ',') { pimpolho[i].nome[j] = ch; fscanf(arq,"%c", &ch); j++; } pimpolho[i].nome[j] = '
for (i = num - 1; i > 0; i--)
    for (j = 0; j < i; j++)
        if (pimpolho[j].idade > pimpolho[j+1].idade ||
            (pimpolho[j].idade == pimpolho[j+1].idade && strncmp(pimpolho[j].CPF,pimpolho[j+1].CPF,11) > 0)){
            pimpolho[num] = pimpolho[j];
            pimpolho[j] = pimpolho[j+1];
            pimpolho[j+1] = pimpolho[num];
        }
'; j=0; fscanf(arq,"%c", &ch); while( ch != ',') { pimpolho[i].email[j] = ch; fscanf(arq,"%c", &ch); j++; } pimpolho[i].email[j] = '
typedef struct Dado{
//               ^----
    char CPF[12];
    char nome[41];
    char email[31];
    int idade;
    struct Dado* proximo; //<---
} Dado;
'; fscanf(arq, "%d", &pimpolho[i].idade); fscanf(arq,"%c", &ch); }

Then you have to be able to see when you have reached the end of the file. The most straightforward is to interpret this in the reading of the first field CPF . For this, the simplest is to change the function ler_string_arq to return 0 when it reaches the end of the file:

int ler_string_arq(FILE* arq, char *campo_destino){
//^----tipo int agora
    int letra = 0;
    char ch;
    if (fscanf(arq,"%c", &ch) != 1){ //se não leu um char então chegou ao fim
        return 0;
    }

    while( ch != ',') {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '
Dado *inicio_lista = NULL, *ultima = NULL; //ponteiros para lista e ultima pessoa

while(1) {
    Dado *pessoa = malloc(sizeof(Dado)); //cria nova pessoa com alocação dinamica
    pessoa->proximo = NULL; //proximo da pessoa criada é nulo
    if (inicio_lista  == NULL){ //se ainda nao tem nenhuma esta é a primeira 
        inicio_lista = pessoa;
    }
    if (ultima != NULL) { //se já tem pessoas liga a anterior a esta
        ultima->proximo = pessoa;
    }

    if (!ler_string_arq(arq, pessoa->CPF)){ //se apanhou EOF
        free(pessoa);
        ultima->proximo = NULL;
        break; //sai
    }
    ultima = pessoa;

    ler_string_arq(arq, pessoa->nome);
    ler_string_arq(arq, pessoa->email);
    fscanf(arq, "%d", &pessoa->idade);
    fscanf(arq,"%c", &ch);
}
fclose(arq);
'; return 1; }

Then while reading is now also quite different:

arqout = fopen("write.txt","w");
Dado* pessoa = inicio_lista;
while (pessoa!= NULL){ //enquanto nao chega ao fim da lista
    fprintf(arqout,"%s,%s,%s,%d\n", pessoa->CPF, pessoa->nome, pessoa->email, pessoa->idade);
    pessoa = pessoa->proximo; //avança para a proxima pessoa
}

For the writing would be quite identical changing the syntax largely:

%pre%

Note that I purposely omitted the sort order of people, because now with a linked list this is much more complicated and I do not want to stretch more than the answer is already quite big. Normally these sorting in lists are done with Merge Sort and they end up handy in the scenario where I I pointed to being sort with pointers and so are quite efficient.

In addition, the complexity between the two sorting algorithms is quite different because Merge Sort runs in O(nlogn) whereas the bubble sort that runs in O(n²) .

    
14.09.2018 / 12:50
1

I hope it helps:

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

typedef struct
{
   char CPF[12];
   char nome[41];
   char email[31];
   int idade;
}Dado;

int main()
{
   FILE *arq, *arqout;
   char ch;
   int num = 0, i, j, aux;
   //melhorando o código
   //arq = fopen("read.txt", "r");
   //verifica se ocorreu algum erro
   if ((arq = fopen("read.txt", "r")) == NULL)
   {
      printf("ocorreu um erro ao abrir o arquivo read.txt!\n");
      return 0;
   }
   //sempre coloque chaves em seu código para que não fique confuso
   while (fscanf(arq, "%c", &ch) != EOF)
   {
      if (ch == '\n')
      {
         num++;
      }
   }
   rewind(arq);
   //primeira modificação transformar a estrutura de Dado estatico para dinamico
   //Dado pimpolho[num + 1];
   Dado * pimpolho = new Dado[num + 1];
   //agora ele e dinamico e sempre verifica se a alocação ocorreu com sucesso
   if (pimpolho == NULL)
   {
      return 0;
   }

   for (i = 0; i < num; i++)
   {
      j = 0;
      fscanf(arq, "%c", &ch);
      while (ch != ',')
      {
         pimpolho[i].CPF[j] = ch;
         fscanf(arq, "%c", &ch);
         j++;
      }
      pimpolho[i].CPF[j] = '
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct
{
   char CPF[12];
   char nome[41];
   char email[31];
   int idade;
}Dado;

int main()
{
   FILE *arq, *arqout;
   char ch;
   int num = 0, i, j, aux;
   //melhorando o código
   //arq = fopen("read.txt", "r");
   //verifica se ocorreu algum erro
   if ((arq = fopen("read.txt", "r")) == NULL)
   {
      printf("ocorreu um erro ao abrir o arquivo read.txt!\n");
      return 0;
   }
   //sempre coloque chaves em seu código para que não fique confuso
   while (fscanf(arq, "%c", &ch) != EOF)
   {
      if (ch == '\n')
      {
         num++;
      }
   }
   rewind(arq);
   //primeira modificação transformar a estrutura de Dado estatico para dinamico
   //Dado pimpolho[num + 1];
   Dado * pimpolho = new Dado[num + 1];
   //agora ele e dinamico e sempre verifica se a alocação ocorreu com sucesso
   if (pimpolho == NULL)
   {
      return 0;
   }

   for (i = 0; i < num; i++)
   {
      j = 0;
      fscanf(arq, "%c", &ch);
      while (ch != ',')
      {
         pimpolho[i].CPF[j] = ch;
         fscanf(arq, "%c", &ch);
         j++;
      }
      pimpolho[i].CPF[j] = '%pre%';
      j = 0;
      fscanf(arq, "%c", &ch);
      while (ch != ',')
      {
         pimpolho[i].nome[j] = ch;
         fscanf(arq, "%c", &ch);
         j++;
      }
      pimpolho[i].nome[j] = '%pre%';
      j = 0;
      fscanf(arq, "%c", &ch);
      while (ch != ',')
      {
         pimpolho[i].email[j] = ch;
         fscanf(arq, "%c", &ch);
         j++;
      }
      pimpolho[i].email[j] = '%pre%';
      fscanf(arq, "%d", &pimpolho[i].idade);
      fscanf(arq, "%c", &ch);
   }
   //sempre coloque chaves em seu código para que não fique confuso
   for (i = num - 1; i > 0; i--)
   {
      for (j = 0; j < i; j++)
      {
         if (pimpolho[j].idade > pimpolho[j + 1].idade)
         {
            pimpolho[num] = pimpolho[j];
            pimpolho[j] = pimpolho[j + 1];
            pimpolho[j + 1] = pimpolho[num];
         }
      }
   }
   //sempre coloque chaves em seu código para que não fique confuso
   for (i = num - 1; i > 0; i--)
   {
      for (j = 0; j < i; j++)
      {
         if (pimpolho[j].idade == pimpolho[j + 1].idade)
         {
            aux = strncmp(pimpolho[j].CPF, pimpolho[j + 1].CPF, 11);
            if (aux > 0)
            {
               pimpolho[num] = pimpolho[j];
               pimpolho[j] = pimpolho[j + 1];
               pimpolho[j + 1] = pimpolho[num];
            }
         }
      }
   }
   //verifica se ocorreu algum erro
   //arqout = fopen("write.txt", "w");
   if ((arqout = fopen("write.txt", "w")) == NULL)
   {
      //libera a memoria utilizada
      delete[]pimpolho;
      printf("ocorreu um erro ao criar o arquivo write.txt!\n");
      return 0;
   }
   for (i = 0; i < num; i++)
   {
      fprintf(arqout, "%s,%s,%s,%d\n", pimpolho[i].CPF, pimpolho[i].nome, pimpolho[i].email, pimpolho[i].idade);
   }
   fclose(arqout);
   fclose(arq);
   //terminou libere a memoria utilizada
   delete[] pimpolho;
   return 0;
}
'; j = 0; fscanf(arq, "%c", &ch); while (ch != ',') { pimpolho[i].nome[j] = ch; fscanf(arq, "%c", &ch); j++; } pimpolho[i].nome[j] = '%pre%'; j = 0; fscanf(arq, "%c", &ch); while (ch != ',') { pimpolho[i].email[j] = ch; fscanf(arq, "%c", &ch); j++; } pimpolho[i].email[j] = '%pre%'; fscanf(arq, "%d", &pimpolho[i].idade); fscanf(arq, "%c", &ch); } //sempre coloque chaves em seu código para que não fique confuso for (i = num - 1; i > 0; i--) { for (j = 0; j < i; j++) { if (pimpolho[j].idade > pimpolho[j + 1].idade) { pimpolho[num] = pimpolho[j]; pimpolho[j] = pimpolho[j + 1]; pimpolho[j + 1] = pimpolho[num]; } } } //sempre coloque chaves em seu código para que não fique confuso for (i = num - 1; i > 0; i--) { for (j = 0; j < i; j++) { if (pimpolho[j].idade == pimpolho[j + 1].idade) { aux = strncmp(pimpolho[j].CPF, pimpolho[j + 1].CPF, 11); if (aux > 0) { pimpolho[num] = pimpolho[j]; pimpolho[j] = pimpolho[j + 1]; pimpolho[j + 1] = pimpolho[num]; } } } } //verifica se ocorreu algum erro //arqout = fopen("write.txt", "w"); if ((arqout = fopen("write.txt", "w")) == NULL) { //libera a memoria utilizada delete[]pimpolho; printf("ocorreu um erro ao criar o arquivo write.txt!\n"); return 0; } for (i = 0; i < num; i++) { fprintf(arqout, "%s,%s,%s,%d\n", pimpolho[i].CPF, pimpolho[i].nome, pimpolho[i].email, pimpolho[i].idade); } fclose(arqout); fclose(arq); //terminou libere a memoria utilizada delete[] pimpolho; return 0; }
    
14.09.2018 / 02:22