Προς το περιεχόμενο

Malloc σε Struct


Lomar

Προτεινόμενες αναρτήσεις

Δημοσ.

Χαίρεται,

 

θέλω να φτιάξω ένα πρόγραμμα σε C το οποίο να δέχεται 3 θερμοκρασίες κατα τη διάρκεια της ημέρας (πρωί μεσημέρι βράδυ), να αποθηκεύονται σε ένα binary αρχείο και μετα να εκτυπώνονται κτλ.

 

Το πρόγραμμα θα δέχεται αυτές τις τιμές απο το πληκτρολόγιο, έως ότου o χρήστης να δώσει τιμές (συνεχόμενες) για μια μέρα 100 100 100.

 

Παραθέτω την προσπάθεια (btw το google με το επίπεδο γνώσεων μου -όχι και πολλά - βοήθησε λίγο, αλλά όχι αρκετά):

 

>

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

struct therm{
           struct imera *day; 
    };
    

struct imera{
             int prwi;
             int mes;
             int vradi;
};
    

int main (void){
   FILE *x;
   int mera=0,a=0,b=0,c=0;
   
   struct therm rec;
   
   x=fopen("thermokrasies.dat","w");
   
   printf ("\n\n Dwse thermokrasies... Telos 100X3");
   do{
          a=0;
          b=0;
          c=0;
          
          printf ("\n\n Dwse tin %d thermokrasia (prwi) (mesimeri) (vradi) : ",mera+1);
          
          scanf ("%f",&a);
          scanf ("%f",&;
          scanf ("%f",&c);
          
          if (a != 100 || b != 100 || c != 100){

          day=realloc(day, (mera+1)*sizeof(struct therm *));
          rec.day[mera].prwi=(struct therm *) malloc (sizeof(struct therm));
          rec.day[mera].mes=(struct therm *) malloc (sizeof(struct therm));
          rec.day[mera].vradi=(struct therm *) malloc (sizeof(struct therm));           


          rec.day[mera].prwi=a;
          rec.day[mera].mes=b;
          rec.day[mera].prwi=c;           
          
          fwrite(&rec,sizeof(struct therm),1,x);
          mera++;
          }
          }while (a != 100 || b != 100 || c != 100);
          
mera=0;           
          
fread(&rec,sizeof(struct therm),1,x);
          
while (!feof(x))
     if (!feof(x)){
                   printf ("\n\n %d mera thermokrasies: %.2f prwi, %.2f mes, %.2f vradi ...",mera+1, day[mera].prwi, day[mera].mes, day[mera].vradi);
                   mera++;
                   }
     else
         printf ("\n\n TELOS EGGRAFWN!!! \n\n");
}

fclose (x);

return 0;
}


 

Οποιαδήποτε βοήθεια, ευπρόσδεκτη και πολύτιμη, ευχαριστώ.

Δημοσ.
>
#include <stdio.h>
#include <stdlib.h>

struct imera {
 int prwi;
 int mes;
 int vradi;
};

struct therm {
 struct imera *day; 
};
    
int main (void)
{
 FILE *x;
 int mera=0,a=0,b=0,c=0;
 struct therm rec={NULL};

 /* writing part */
 x=fopen("thermokrasies.dat","w");
 printf ("\n\n Dwse thermokrasies... Telos 100X3");
 do
 {
   a=0;
   b=0;
   c=0;
          
   printf ("\n\n Dwse tin %d thermokrasia (prwi) (mesimeri) (vradi) : ",mera+1);
          
   scanf ("%d",&a);
   scanf ("%d",&;
   scanf ("%d",&c);
          
   if (a != 100 || b != 100 || c != 100)
   {
     struct imera * day;
     
     if (rec.day == NULL)
       day = (struct day *)malloc(sizeof (struct imera));
     else
       day = realloc(rec.day, (mera+1)* sizeof(struct imera));

     if (day != NULL)
     {
       rec.day = day;
       rec.day[mera].prwi = a;
       rec.day[mera].mes = b;
       rec.day[mera].vradi = c;           

       rec.day[mera].prwi=a;
       rec.day[mera].mes=b;
       rec.day[mera].prwi=c;           
          
       fwrite(&rec,sizeof(struct therm),1,x);
       mera++;
     }
   }
 } while (a != 100 || b != 100 || c != 100);

 fclose (x);
 free(rec.day);
 /* reading part */
 rec.day = (struct day *)malloc(sizeof (struct imera));
 x=fopen("thermokrasies.dat","r");   
 mera=0;                    
          
 while (!feof(x))
 {
   fread(&rec,sizeof(struct therm),1,x);

   if (!feof(x))
   {
     printf ("\n\n %d mera thermokrasies: %d prwi, %d, %d vradi ...",mera+1, rec.day->prwi, rec.day->mes, rec.day->vradi);
     mera++;
   }
   else
     printf ("\n\n TELOS EGGRAFWN!!! \n\n");
 }

 fclose (x);

 return 0;
}

Δημοσ.

Ευχαριστώ πολύ!

 

Δεν πρόλαβα να μελετήσω τον κώδικά σου - είναι και αργά τώρα - αύριο που θα το κοιτάξω καλύτερα ελπίζω να καταλάβω τι έκανα λάθος.

 

Πρώτη απορία όμως, αν και βιαστική, γιατί την struct την δήλωσες μετά το:

 

if (a != 100 || b != 100 || c != 100)

{

struct imera * day;

 

if (rec.day == NULL)

 

??

 

Επίσης, το NULL, γιατί το χρησιμοποιείς;

Δημοσ.

Πρώτη απορία όμως, αν και βιαστική, γιατί την struct την δήλωσες μετά το:

 

if (a != 100 || b != 100 || c != 100)

{

struct imera * day;

 

 

Εάν προσέξεις τον κώδικα σου χρησιμοποιείς μια μεταβλητή day, η οποία δεν είναι δηλωμένη πουθενά και προφανώς είναι, απο οτι κατάλαβα, τύπου struct therm *. Έτσι αποφάσισα να τη δηλώσω ως προσώρινη μεταβλητή για να την χρησιμοποιήσω για δέσμευση της μνήμης.

 

Επίσης, το NULL, γιατί το χρησιμοποιείς;

 

Απο οτι κατάλαβα απο τον κώδικα σου θέλεις να φυλάς το input σε ένα dynamic array. Οποτε την πρώτη φορά που δεν υπάρχει κανένα στοχείο στον dynamic array θα πρέπει να κάνεις malloc, ενώ τις επομενες φορές θα πρέπει να επεκτείνεις το dynamic array κάνοντας realloc.Έτσι για να ξέρω οτι είναι η πρώτη φορά ελέγχω αν ο dynamic array είναι κενός δλδ NULL.

Δημοσ.

1ο ερώτημα.

 

Μα την struct imera *day την είχα δηλώσει έξω απο την main. Βασικά η απορία μου είναι, γιατί την δήλωσες μεσα στην for;

 

2ο ερώτημα.

 

αααααααααααααααααααααα, λογικό :D.

 

3o ερώτημα.

 

>
if (day != NULL)
     {
       rec.day = day;
       rec.day[mera].prwi = a;
       rec.day[mera].mes = b;
       rec.day[mera].vradi = c;           

   [b]rec.day[mera].prwi=a;
       rec.day[mera].mes=b;         =====================================> [b][i][u][color="Red"]ΓΙΑΤΙ ΤΑ ΕΓΡΑΨΕΣ 2 ΦΟΡΕΣ???[/color][/u][/i][/b]
       rec.day[mera].prwi=c; [/b]   ==========================> [b][i][u][color="Red"]ΓΙΑΤΙ ΔΙΛΩΝΕΙΣ ΤΟ ΠΡΩΙ ΞΑΝΑ ΚΑΙ ΛΑΘΟΣ (για τα ζητουμενα του προγραμματος)??[/color][/u][/i][/b]
          
       fwrite(&rec,sizeof(struct therm),1,x);
       mera++;
     }
   }

 

Παρατήρηση.

 

Όταν τρέχω το πρόγραμμα οι εγγραφές που εκτυπώνει είναι εντελώς λάθος (οι τιμές τους). :?:

Αυτό γιατί μπορεί να γίνεται;

 

Ευχαριστώ πάντως για την βοήθεια, γιατί το σημαντικό για εμένα ήταν να καταλάβω την λειτουργία των pointer σε array μέσα σε struct που εμπλέκεται και με μια άλλη (ζαλίστικα... :P), και πιστεύω πως τώρα κατανόησα κάποια πράγματα παραπάνω.

Δημοσ.

1ο ερώτημα.

 

Μα την struct imera *day την είχα δηλώσει έξω απο την main. Βασικά η απορία μου είναι, γιατί την δήλωσες μεσα στην for;

 

 

Δεν την ειχες δηλωσει καν εκτος της main, την ειχες δηλωσει μεσα σε ενα αλλο struct με ονομα therm. Την μεταβλητη struct imera *day την δηλωσα εκει που την χρειαστηκα. Δεν παιζει ρολο που ακριβως.

 

3o ερώτημα.

> 
if (day != NULL)
{
   rec.day = day;
   rec.day[mera].prwi = a;
   rec.day[mera].mes = b;
   rec.day[mera].vradi = c;           

   rec.day[mera].prwi=a;
   rec.day[mera].mes=b;         =====================================> ΓΙΑΤΙ ΤΑ ΕΓΡΑΨΕΣ 2 ΦΟΡΕΣ???
   rec.day[mera].prwi=c;    ==========================> ΓΙΑΤΙ ΔΙΛΩΝΕΙΣ ΤΟ ΠΡΩΙ ΞΑΝΑ ΚΑΙ ΛΑΘΟΣ (για τα ζητουμενα του προγραμματος)??
          
   fwrite(&rec,sizeof(struct therm),1,x);
   mera++;
}
   }

 

 

Sorry προκειται για copy/paste λαθος.

Δημοσ.

ok αυτό με το πρώτο ερώτημα δεν το ήξερα, οτι δλδ πρέπει να την δηλώνω κ μέσα στη main. Νόμιζα οτι η rec ήταν αρκετή.

 

Αλλά ακόμα δν μπορώ να καταλάβω γιατί αποθηκεύει ότι να ναι νούμερα στο αρχείο (κατα την εμφάνιση διαπίστωσα το πρόβλημα)...

 

Μήπως επειδή εδώ:

 

>
printf ("\n\n %d mera thermokrasies: %d prwi, %d, %d vradi ...",mera+1, rec.day->prwi, rec.day->mes, rec.day->vradi);
     mera++;

 

το mera δεν φαίνεται πουθενά, επίσης το σκηνικό με τα βελάκια κάτι μου θυμίζει, αλλά δομές δεδομένων δεν έχω κάνει ακόμη στη σχολή μου :D

 

Άν μπορούσες να με διαφωτίσεις με τα δυο παραπάνω, δλδ γιατί το day αν και array το διαχειριζόμαστε έτσι;

 

thnks.

  • Moderators
Δημοσ.

H day είναι μέλος της δομής struct therm, έχει οριστεί ως δείκτης σε δομή imera και χρησιμοποιείται στο πρώτο μέρος του προγράμματος σου (όπου γράφεις στο αρχείο) ως δείκτης στην αρχή ενός "δυναμικού" (λόγω της realloc) πίνακα από δομές imera. Ο πίνακας αυτός υπάρχει λόγω της malloc και των realloc, και μόνο με το δείκτη day μπορείς να προσπελάσεις τις καταχωρήσεις του.

 

Απο μόνο του το day δείχνει στην αρχή του πίνακα με τις δομές imera. Αν του δώσεις ένα int ως index (πχ day[1], day[2] κλπ) τότε σου "φέρνει" την δομή imera που βρίσκεται στην αντίστοιχη θέση του δυναμικού πίνακα (και μπορείς χρησιμοποιώντας την τελεία (.) να πάρεις τα μέλη της δομής εκείνης).

 

 

Στο δεύτερο μέρος του προγράμματος η day είναι δείκτης σε μία μόνο δομή (και όχι πίνακα) imera και άρα το rec.day->prwi λειτουργεί επειδή η day είναι δείκτης -και δεν μπορείς να χρησιμοποιήσεις την τελεία (.) για να προσπελάσεις ένα μέλος της- αλλά πρέπει να χρησιμοποιήσεις το βελάκι (->) με το ίδιο ακριβώς αποτέλεσμα.

------

 

Το πρόβλημα που εντόπισα εγώ είναι ότι αποθηκεύετε συνεχώς την δομή therm στο αρχείο του δίσκού (η οποία ουσιαστικά είναι μόνο ένας δείκτης) κάτι στο οποίο δε βρίσκω νόημα. Ειδικά γιατί ο δείκτης αυτός θα είναι άκυρος αν το αρχείο διαβαζόταν απο άλλο πρόγραμμα ή επόμενη κλήση του προγράμματος. Επίσης δε βλέπω πολύ νόημα στην ύπαρξη της therm γενικότερα....

 

Δοκιμάστε να αποθηκεύσετε τη δομή imera σε κάθε loop.

Δημοσ.

Το παρακάτω πρόγραμμα υλοποιεί αυτό που ζήτησες χωρίς την χρήση δεύτερης δομής μέσα σε ένα δυναμικό πίνακα δομών. Γράφει τα αποτελέσματα σε ένα δυαδικό αρχείο, κατόπιν τα διαβάζει από αυτό και στη συνέχεια τυπώνει και την μνήμη και αυτά που διάβασε από το αρχείο. Τέλος διαγράφει και το αρχείο από τον σκληρό δίσκο και απελευθερώνει την μνήμη. Δεν έχω πολύ χρόνο αυτήν την περίοδο έχω και εξεταστική, καλή συνέχεια.

 

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

#define N 500

typedef struct rec
{
       int prwi;
       int mesimeri;
       int bradi;
       char *name;
       int index;
}Record;

Record *CreateArray()
{
      Record *ar = (Record *) malloc(N * sizeof(Record));
      if(ar)
      {
            int i;
            for(i = 0; i < N; i++)
            {
                  ar[i].bradi = -1;
                  ar[i].prwi = -1;
                  ar[i].mesimeri = -1;
                  
                  ar[i].name = NULL;
                  
                  //Unused Slot.
                  
                  ar[i].index = -1;
            }
            if(i == N)
                 return ar;
            else
                return NULL;
      }
      else
      {
          printf("Error, no space available.\n");
          return NULL;
      }
}
                  

Record *CreateRecord(int p, int m, int b, char *day)
{
      Record *rec = (Record *)malloc(sizeof(Record));
      if(rec)
      {
             rec->name = strdup(day);
             if(rec->name)
             {
                          rec->prwi = p;
                          rec->mesimeri = m;
                          rec->bradi = b;
                          
                          //Used slot.
                          
                          rec->index = 0;
                          
                          //Return the record.
                          
                          return rec;
             }
             else
             {
                 printf("Error, can not get the name of the day.\n");
                 return NULL;
             }
      }
      else
      {
          printf("Error, no space available for record.\n");
          return NULL;
      }
}

Record* DeleteRecord(Record *ar, int index)
{
    if(ar)
    {
          //Find the record and delete it, save it to r.
          
          if(!ar[index].index)
          {
                 //Copy the record first.
                 
                 Record *r = CreateRecord(ar[index].prwi, ar[index].mesimeri, ar[index].bradi, ar[index].name);
                              
                  ar[index].bradi = -1;
                  ar[index].prwi = -1;
                  ar[index].mesimeri = -1;
                  
                  //Clean the name.
                  
                  memset(ar[index].name, 0 , sizeof(ar[index].name));  
                  
                  free(ar[index].name); 
                  
                  ar[index].name = NULL;              
                                    
                  //Unused Slot.
                  
                  ar[index].index = -1;
                  
                  return r;
                  
          }
          else
              printf("Can not delete an empty record.\n");
    }
}

void InsertRecord(Record *ar, int index, int p, int m, int b, char *day)
{
    if(ar)
    {
          Record *r = CreateRecord(p,m,b,day);
          if(r)
          {
               if(ar[index].index == -1)
                                   memcpy(&ar[index], r, sizeof(Record));
               else
               {
                   printf("Error, occupied space here.\n");
                   free(r->name);
                   free(r);
                   r = NULL;
               }
          }
          else
              printf("Error, could not create the record.\n");
    }
    else
        printf("Error, the array is NULL.\n");
}
void PrintTable(Record *ar)
{
    if(ar)
    {
          int i = 0;
          while(i < N)
          {
                  if(!ar[i].index)
                  {
                                  printf("Record[%d]\n",i);
                                  printf("Prwi: %d\nMesimeri: %d\nBradi: %d\n", ar[i].prwi, ar[i].mesimeri, ar[i].bradi);
                                  printf("Day:%s\n\n", ar[i].name);
                  }
                  i++;
          }
    }
}
void WriteRecordToFile(Record *r, FILE *f)
{
    if(r && f)
    {
         int count = 0;
         
         //Write the record to file.

         count = fwrite(r, sizeof(Record), 1, f);
         if(!count)
                   printf("Error in writing to file.\n");
    }
}

void ReadRecordFromFile(Record *r, FILE *f)
{
    if(r && f)
    {
         int count = 0;
         
         //Read the record from file.
         
         count = fread(r, sizeof(Record), 1, f);
         
         if(!count)
                   printf("Error in Reading from file.\n");
    }
}                               
                              

int main(int argc, char *argv[])
{
   //Variables.
   
   FILE *f = NULL;
   
   int prwi = 0;
   int mesimeri = 0;
   int bradi = 0;
   
   int i = 0;
   int j = 0;
   
   int choice = 0;
   
   char name[20] = {0};
   
   //Memory Records.
   
   Record *arr = CreateArray();
   
   Record r;
   
   f = fopen("test.dat", "wb");
   
   //After the call we created an array that holds N records.
   
   do
   {
           fflush(stdin);
           printf("Give me the name of the day.\n");
           gets(name);
           printf("Give me the temps, seperated by spaces.\n");
           if(scanf("%d %d %d", &prwi, &mesimeri, &bradi) != 3)
                        break;
           else
           {
               InsertRecord(arr, i, prwi, mesimeri, bradi, name);
               
               WriteRecordToFile(&arr[i], f);
               
               i++;
           }
           printf("Press 1 if you want to enter more, else whatever to stop.\n");
           scanf("%d", &choice);
   }while(i < N && choice == 1);
   fclose(f);
   
   printf("\n\nLets Print Memory.\n\n");
   
   PrintTable(arr);
   
   //Now lets test if we made it right..
   
   printf("\nAfter Writing to File.\n\n");
   printf("Reading....\n\n");
   
   f = fopen("test.dat", "rb");
   
   while(j < i && !feof(f))
   {
       memset(&r, 0 , sizeof(Record));
       
       ReadRecordFromFile(&r, f);
       
       printf("Record[%d]\n",j);
       printf("Prwi: %d\nMesimeri: %d\nBradi: %d\n", r.prwi, r.mesimeri, r.bradi);
       printf("Day:%s\n\n", r.name);
       
       j++;
       
   }
   
   fclose(f);
   
   remove("test.dat");
   
   for(; i >= 0; i--)
         free(arr[i].name);
   free(arr);
   arr = NULL;
   
   system("PAUSE");	
   return 0;
}

 

Εννοείται μπορεί να υπάρχουν και λάθη, είχα καιρό να ασχοληθώ με αρχεία!!

 

Φιλικά Bokarinho..

Δημοσ.

@Praetorian

 

thnks για τις συμβουλές αύριο μεθαύριο που θα ασχοληθώ θα σου πω και σχετικές απορίες.

 

@Bokarinho

 

:shock:

 

Respect αυτό που έγραψες, αλλα ρε φίλε δεν κατάλαβα και πολλά...

 

Πρώτη φορά βλέπω τύπο δεδομένων Record και αυτό εδώ με έστειλε αδιάβαστο:

 

>

Record* DeleteRecord(Record *ar, int index) 

 

pointer σε τύπο δεδομένων συνάρτησης πρώτη φορά βλέπω και δεν μπορώ καν να φανταστώ τι δουλειά κάνει!

 

Μια γρήγορη ματιά του έριξα και διαπίστωσα οτι αυτός ο κώδικας δεν είναι - τουλάχιστον ακόμη - για τα δικά μου κυβικά... :D

 

thnks πάντως, μόλις βρώ χρόνο και ασχοληθώ πάλι σοβαρά θα επανέλθω.

  • Moderators
Δημοσ.

Ο κώδικας του bokarinho αν και πιθανότατα θα δουλευει (δεν έχω χρόνο να τον ελέγξω διεξοδικά) είναι αρκετά πολύπλοκος και περιέχει κώδικα που πλεονάζει γι'αυτό το απλό που θέλεις να κάνεις με το πρόγραμμα σου. (πχ DeleteRecord )

 

Εγώ θα έλεγα να δουλέψεις πάνω στον κώδικα που πρότεινε ο pinball_elf. Έτσι όπως βλέπω την εκφώνηση θα έλεγα ότι μπορείς να αποφύγεις ακόμα και τις Malloc και Realloc (έτσι κι αλλιώς από την εμπειρία μου η Realloc συχνά εμφανίζει προβλήματα και crashes στη χρήση της). Μια απλή μεταβλητη (και όχι δείκτης) της δομής imera σου αρκει, που θα ανανεώνεις τα πεδία της σε κάθε loop και θα την αποθηκεύεις έπειτα στο αρχείο σου (μέσα στο while loop).

 

Όσο για το Record* DeleteRecord(Record *ar, int index)

 

H Record είναι ουσιαστικά ένα ψευδώνυμο για τη struct rec. (αυτό κάνει η εντολή typedef, η οποία typedef χρησιμοποιείται πολύ συχνά σε συνδυασμό με τον ορισμό των struct γιατί κάνει πιο απλή τη χρήση τους στον κώδικα (αποφεύγεις να γραφείς το struct συνέχεια).

 

Η DeleteRecord() παίρνει όρισμα δείκτη στη δομή Record (για να μπορεί αλλάξει τα πεδία του -όρισμα κατ'αναφορά) και επιστρέφει δείκτη σε δομή Record. Μέσα στον κώδικα της DeleteRecord δημιουργείται ένα αντίγραφο -με την Createrecord()- της δομής που θέλεις να σβήσεις και ο δείκτης σε αυτό το αντίγραφο είναι αυτό που επιστρέφει η DeleteRecord().

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...