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

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

Δημοσ.

καλησπέρα σας, έχω τον παρακάτω κώδικα,

>
void calloc2d(double** array, int r, int c){
int i;
array=(double**)calloc(r,sizeof(double*));
if(array==NULL){
	printf("\nInsufficient Memory\n");
}
for(i=0;i<r;r++){
	array[i]=(double*)calloc(c,sizeof(double));
}
}

 

 

και θέλω μέσα στην main να την καλώ την συνάρτηση, γράφω δλδ

double **dis;

calloc2d(dis,n,n);

 

 

αλλά μου βγάζει σφάλμα λέγοντας ότι δεν είναι ορισμένος ο πίνακας dis και ότι

Error 15 error C2109: subscript requires array or pointer type

 

ξέρετε ποιο είναι το λάθος;

 

Ώρες ώρες είναι να τρελαίνεσαι με αυτή την C, το "λάθος" ήταν ότι το double **dis το είχα ορίσει ακριβώς πάνω από το κάλεσμα της συνάρτησης, μόλις το πήρα από εκεί και το έβαλα στην αρχή της main μαζί με τα άλλα declarations έπαιξε, και βγάζει το εξής σφάλμα...

 

Run-Time Check Failure #3 - The variable 'dis' is being used without being initialized.

 

ενώ την αρχικοποιώ μετά αν εννοεί αυτό που καταλαβαίνω.

 

>calloc2d(dis,n,n);
//===============================================
//Initialize dis[][]
for(i=0;i<n;i++){
	for(j=0;j<n;j++){
		dis[i][j]=99999;
	}
}

Δημοσ.

καλησπέρα σας, έχω τον παρακάτω κώδικα,

>
void calloc2d(double** array, int r, int c){
int i;
array=(double**)calloc(r,sizeof(double*));
if(array==NULL){
	printf("\nInsufficient Memory\n");
}
for(i=0;i<r;r++){
	array[i]=(double*)calloc(c,sizeof(double));
}
}

 

Καταρχήν, το for σου είναι λάθος. Θέλεις i++ αντί για r++.

 

Ώρες ώρες είναι να τρελαίνεσαι με αυτή την C, το "λάθος" ήταν ότι το double **dis το είχα ορίσει ακριβώς πάνω από το κάλεσμα της συνάρτησης, μόλις το πήρα από εκεί και το έβαλα στην αρχή της main μαζί με τα άλλα declarations έπαιξε, και βγάζει το εξής σφάλμα...

 

Δεν φταίει η C αυτή καθεαυτή αλλά μάλλον ο compiler σου. Η C89 απαιτούσε οι δηλώσεις μεταβλητών να βρίσκονται όχι απαραίτητα στην αρχή της main αλλά απαραίτητα πριν να εκτελέσεις κώδικα. Η C99 δεν έχει αυτό τον περιορισμό αλλά ίσως ο compiler σου δεν την έχει υλοποιήσει.

 

και θέλω μέσα στην main να την καλώ την συνάρτηση, γράφω δλδ

double **dis;

calloc2d(dis,n,n);

 

 

Ώρες ώρες είναι να τρελαίνεσαι με αυτή την C, το "λάθος" ήταν ότι το double **dis το είχα ορίσει ακριβώς πάνω από το κάλεσμα της συνάρτησης, μόλις το πήρα από εκεί και το έβαλα στην αρχή της main μαζί με τα άλλα declarations έπαιξε, και βγάζει το εξής σφάλμα...

 

Run-Time Check Failure #3 - The variable 'dis' is being used without being initialized.

 

ενώ την αρχικοποιώ μετά αν εννοεί αυτό που καταλαβαίνω.

 

>calloc2d(dis,n,n);
//===============================================
//Initialize dis[][]
for(i=0;i<n;i++){
	for(j=0;j<n;j++){
		dis[i][j]=99999;
	}
}

 

 

 

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

void calloc2d(double **array, int r, int c);

int main(void)
{
double **dis = NULL;;
printf("dis before calloc = %p\n", (void *)dis);
calloc2d(dis, 5, 5);
printf("dis after calloc = %p\n", (void *)dis);

return 0;
}

void calloc2d(double **array, int r, int c){
       int i;
       array=(double**)calloc(r,sizeof(double*));
       if(array==NULL){
               printf("\nInsufficient Memory\n");
       }
printf("dis in calloc = %p\n", (void *)array);
       for(i=0;i<r;i++){
               array[i]=(double*)calloc(c,sizeof(double));
       }
}

 

 

 

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

>
dis before calloc = (nil)
dis in calloc = 0x179c010
dis after calloc = (nil)

 

Όπως βλέπεις, η dis όντως δεν αρχικοποιείται. Ένας τρόπος να κάνεις αυτό που θέλεις είναι αντί να περνάς την dis ως παράμετρο στην συνάρτηση, να περνάς μόνο τα n,c και να επιστρέφεις το dis.

Δημοσ.

Όπως βλέπεις, η dis όντως δεν αρχικοποιείται. Ένας τρόπος να κάνεις αυτό που θέλεις είναι αντί να περνάς την dis ως παράμετρο στην συνάρτηση, να περνάς μόνο τα n,c και να επιστρέφεις το dis.

 

Ένας άλλος είναι να περάσεις τη διεύθυνση μνήμης του διπλού pointer (τριπλός pointer)

 

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

void calloc2d(double ***array, int r, int c);

int main(void)
{
       double **dis = NULL;;
       printf("dis before calloc = %p\n", (void *)dis);
       calloc2d(&dis, 5, 5);
       printf("dis after calloc = %p\n", (void *)dis);

       return 0;
}

void calloc2d(double ***array, int r, int c){
       int i;
       *array = (double**)calloc(r,sizeof(double*));
       if((*array)==NULL){
               printf("\nInsufficient Memory\n");
       }
       printf("dis in calloc = %p\n", (void *)(*array));
       for(i=0;i<r;i++){
               (*array)[i]=(double*)calloc(c,sizeof(double));
       }
}

 

Αν και η πρόταση του imitheos είναι καλύτερη γιατί κερδίζει σε απλότητα.

 

Σε τι περιβάλλον αναπτύσσεις? (IDE, compiler)

Δημοσ.

Ένας άλλος είναι να περάσεις τη διεύθυνση μνήμης του διπλού pointer (τριπλός pointer)

...

Αν και η πρόταση του imitheos είναι καλύτερη γιατί κερδίζει σε απλότητα.

...

Κι αυτός καλός τρόπος είναι, δηλαδή το "by reference" πέρασμα του dis στην calloc2d(). Και είναι καλό να συνοδεύεται κι από ένα "by reference" πέρασμα σε μια συνάρτηση απελευθέρωσης, που εκτός από free() θα τον κάνει και NULL.

 

Παρεμπιπτόντως, η calloc2d() του αρχικού post είναι ημιτελής (προβληματική). Δεν ελέγχει για αποτυχία της calloc() μέσα στο for-loop και προφανώς δεν κάνει και cleanup σε τέτοια περίπτωση (memory leak).

Δημοσ.

Δοθείσης της ευκαιρίας, ας μου επιτραπεί να παρατηρήσω τα εξής.

 

Η δέσμευση μνήμης χωριστά για κάθε γραμμή, δηλ. με χρήση του

>
for(i=0;i<r;i++)                
(*array)[i]=(double*)calloc(c,sizeof(double)); 

είναι γενικά κακή πρακτική διότι η μνήμη μπορεί να δεσμεύεται κατακερματισμένα.

Όταν σαρώνεται ο πίνακας, η ανάγνωση τυχόν τμημάτων του (γραμμές) που βρίσκονται

σε διαφορετικές περιοχές της μνήμης επιφέρει καθυστέρηση.

Επιπλέον, ο κατακερματισμός έχει ως αποτέλεσμα τμήματα της μνήμης να μην μπορούν

να χρησιμοποιηθούν πλήρως. Αυτό ήταν ένα πρόβλημα που τώρα λύνεται (νομίζω) εμμέσως

από το λειτουργικό σύστημα...

 

 

Είναι καλύτερο να δεσμεύεται μονομιάς όλη η απαιτούμενη μνήμη με μια εντολή του τύπου

>
s = r*c; 
Tipus* p = (Tipus*)calloc(s, sizeof(Tipus));

και μετά με ένα βρόχο να δείχνεται η αρχή κάθε σειράς στην δεσμευμένη περιοχή με (κάπως έτσι)

>for (i = 0; i < r; i++)
{   array[i] = p;
   p += c;
}

Τοιουτοτρόπως, αργότερα στο πρόγραμμα, για ανάθεση τιμών ή αντιγραφή του πίνακα,

μπορούν να χρησιμοποιηθούν και εντολές memset ή memcpy που είναι λιτές και σαφώς

πιο γρήγορες από τους βρόγχους. Αν ο πίνακας δεν είναι σίγουρα μαζεμένος σε ένα

μόνον μέρος της μνήμης αντί εδώ κι εκεί, αυτά δεν μπορούν να γίνουν.

 

Aπό άποψη βελτιστοποίησης, ακόμη καλύτερο αποτέλεσμα επιτυγχάνεται αν η δέσμευση μνήμης

γίνεται πάντα για πλήθος στοιχείων που είναι (ακέραιο) πολλαπλάσιο αυτών της μια γραμμής.

(Το έχω δει έτσι αλλά χρηστικά είναι κάπως μπελάς είναι αλήθεια...)

 

-

Δημοσ.

+1 στον φίλο Smirnov. Έχουμε αναφερθεί αρκετές φορές σε αυτό το θέμα, και με παραδείγματα... αυτός είναι έτσι κι αλλιώς ο τρόπος που διαχειρίζεται ο compiler τους πολυδιάστατους, στατικούς πίνακες.

 

Μονοκόμματη δέσμευση μνήμης ίσης με NROWS * NCOLS *sizeof(element) δηλαδή σαν να ήταν 1d, και κατόπιν αν n είναι ο indexer του 1d πίνακα, τότε τα:

 

>i = n / NCOLS;
j = n % NCOLS;

σου δίνουν την τρέχουσα γραμμή και στήλη, αντίστοιχα, του εκάστοτε n.

 

Αντίστροφα, το...

>n = i * NCOLS + j

σου υπολογίζει το n αν ξέρεις την γραμμή i και την στήλη j.

 

Από την άλλη μεριά, η δυναμική δέσμευση ενός 1d πίνακα από NROWS δείκτες μας επιτρέπει να "κολλήσουμε" πάνω τους (επίσης δυναμικά) γραμμές ανομοιογενούς μήκους, που μπορεί να μας εξοικονομήσει πολλή μνήμη!

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...