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

Δυναμικά Οριζόμενοι Πίνακες σε C


Lomar

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

Δημοσ.

@chiossif: πρώτα ο advisor, μετά όλα τα άλλα. Τσέκαρε πμ.

 

Μόλις σκαρφίστηκα το παρακάτω

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

int main(void) {
 typedef int data_type;

 const size_t N = 10;
 data_type **a;

 size_t i;
 
 if ( (a=malloc(N*sizeof *a))==NULL )
 {
   fprintf(stderr, "Error creating array\n");
   exit(-1);
 }

 if ( (a[0]=malloc(N*N*sizeof **a))==NULL )
 {
   fprintf(stderr, "Error creating array\n");
   exit(-1);
 }

 for (i=1; i<N; ++i)
 {
   a[i] = &(a[0][i*N]);
 }

 for (i=0; i<N; ++i)
 {
   size_t j;
   for (j=0; j<N; ++j)
   {
     a[i][j] = rand()/(RAND_MAX/10);
     printf("%d ", a[i][j]);
   }
   putchar('\n');
 }
 
 return EXIT_SUCCESS;
}

 

Πλεονεκτήματα: ω, ναι μπορείς να καλείς άνετα την memcpy() και σε πράξεις με πίνακες που είναι αρκούντως εντατικές και περιέχουν πολλές αντιγραφές έχει πολύ νόημα. Επιπλέον, μπορείς να έχεις εύκολα μια σειριακή αναπαράσταση του ν-διάστατου πίνακά σου.

 

Μειονεκτήματα: πρέπει να μπορεί να γίνει όλο αυτό το chunk της μνήμης allocated - κάτι σχετικά δύσκολο σε μεγάλους πίνακες. Επιπλέον δεν είναι και τόσο διαισθητικό σε κάποιον που το βλέπει πρώτη φορά και μάλλον θέλεις επιπλέον μεθόδους για να το χειρίζεσαι - ή καλύτερα μια πλήρη βιβλιοθήκη.

  • Απαντ. 64
  • Δημ.
  • Τελ. απάντηση
Δημοσ.

Ωραία η ιδέα σου (και δεν προδίδεις "πολύ" το λάθος μου).

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

 

Φίλοι, δώστε μου 48 ώρες...

Δημοσ.
@chiossif: πρώτα ο advisor, μετά όλα τα άλλα. Τσέκαρε πμ.

 

Μόλις σκαρφίστηκα το παρακάτω

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

int main(void) {
 typedef int data_type;

 const size_t N = 10;
 data_type **a;

 size_t i;
 
 if ( (a=malloc(N*sizeof *a))==NULL )
 {
   fprintf(stderr, "Error creating array\n");
   exit(-1);
 }

 if ( (a[0]=malloc(N*N*sizeof **a))==NULL )
 {
   fprintf(stderr, "Error creating array\n");
   exit(-1);
 }

 for (i=1; i<N; ++i)
 {
   a[i] = &(a[0][i*N]);
 }

 for (i=0; i<N; ++i)
 {
   size_t j;
   for (j=0; j<N; ++j)
   {
     a[i][j] = rand()/(RAND_MAX/10);
     printf("%d ", a[i][j]);
   }
   putchar('\n');
 }
 
 return EXIT_SUCCESS;
}

 

Πλεονεκτήματα: ω, ναι μπορείς να καλείς άνετα την memcpy() και σε πράξεις με πίνακες που είναι αρκούντως εντατικές και περιέχουν πολλές αντιγραφές έχει πολύ νόημα. Επιπλέον, μπορείς να έχεις εύκολα μια σειριακή αναπαράσταση του ν-διάστατου πίνακά σου.

 

Μειονεκτήματα: πρέπει να μπορεί να γίνει όλο αυτό το chunk της μνήμης allocated - κάτι σχετικά δύσκολο σε μεγάλους πίνακες. Επιπλέον δεν είναι και τόσο διαισθητικό σε κάποιον που το βλέπει πρώτη φορά και μάλλον θέλεις επιπλέον μεθόδους για να το χειρίζεσαι - ή καλύτερα μια πλήρη βιβλιοθήκη.

 

Εξεζητημένη αλλά ενδιαφέρουσα παραλλαγή μιας γνωστής τεχνικής η οποία όμως προσπερνά το ουσιαστικό ζητούμενο του προηγούμενου κώδικα όπως παρατηρείς στην αρχή των μειονεκτημάτων της -συνεπώς από αυτή την σκοπιά η memcpy συνεχίζει να μας ταλαιπωρεί υπό τις προϋποθέσεις του προηγούμενο προγράμματος (το αναφέρω μιας και διαφώνησες μαζί μου αρχικά σε παλαιότερο post αλλά de facto συμφώνησες αναδιατάσσοντας στον παρόν κώδικα την στρατηγική δέσμευσης μνήμης -μιλώ γενικά προς σεβασμό αυτού του θαυμάσιου Trivial Persuit;)).

 

Θα ήθελα έτσι τυπικά να αναρτήσεις μια έκδοση που να καλεί την memcpy κάνοντας αντιγραφή τον **a σε έναν νέο παρόμοιο του πίνακα (πχ. **B), επίσης θα ήθελα πριν την έξοδο να καλέσεις την ρουτίνα free και για τους δυο πίνακες (**a και **B) -η απλότητα της μεθόδου τότε θα γίνει αντιληπτή και στους υπόλοιπους με τον καλύτερο δυνατό τρόπο.

 

Καλή συνέχεια.

Δημοσ.

@DirectX: κακώς διαφώνησα, γιατί δεν είχα κοιτάξει καλά τον κώδικα - και φυσικα έχεις δίκιο γιατί μόλις το κοίταξα καλύτερα, κατάλαβα τι εννοούσες. Μόλις σήμερα κάθισα να δω τι ακριβώς κάνει - και φυσικά είδα ότι στηρίζεται σε εξ αρχής κακή (ηθελημένα από τον chiossif - που αρέσκεται σε προγραμματιστικά quiz) υπόθεση.

 

Ετοίμασα μια μεγαλύτερη έκδοση - τα forums αρχίζουν να μη βολεύουν για τόσο κώδικα, χρειαζόμαστε plugins για syntax highlighting και compilation:

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

typedef int data_type;

void print(const char *name, data_type **arr, const size_t N) {
 size_t i;
 
 printf("%s=\n", name);
 for (i=0; i<N; ++i)
 {
   size_t j;
   for (j=0; j<N; ++j)
     printf("%3d ", arr[i][j]);
   putchar('\n');
 }
}

void pivot(data_type **arr, const size_t r1, const size_t r2) {
 data_type *t = arr[r1];
 arr[r1] = arr[r2];
 arr[r2] = t;
}

void free_array(data_type **arr, const size_t N) {
 size_t i;
 data_type *t = arr[0];
 for (i=1; i<N; ++i)
   if (t-arr[i]>0)
     t = arr[i];
 free(t);
 free(arr);
}

int main(void) {
 typedef int data_type;

 const size_t N = 5;

 data_type **a;
 data_type **b;
 
 size_t i;
 
 if ( (a=malloc(N*sizeof *a))==NULL )
   exit(-1);
 if ( (a[0]=malloc(N*N*sizeof **a))==NULL )
   exit(-1);
 for (i=1; i<N; ++i)
   a[i] = &(a[0][i*N]);

 if ( (b=malloc(N*sizeof *)==NULL )
   exit(-1);
 if ( (b[0]=malloc(N*N*sizeof **)==NULL )
   exit(-1);
 for (i=1; i<N; ++i)
   b[i] = &(b[0][i*N]);

 for (i=0; i<N*N; ++i)
   a[0][i] = i;
 
 print("a", a, N);
 memcpy(b[0], a[0], N*N*sizeof **a);
 print("b", b, N);
 pivot(b, 0, 1);
 pivot(b, 0, 3);
 print("b", b, N);
 
 free_array(a, N);
 free_array(b, N);

 return EXIT_SUCCESS;
}

 

Συγγνώμη για την έλλειψη αγκύστρων, αλλά προσπάθησα να μειώσω το μέγεθος του κώδικα. Άμα νομίζετε ότι αξίζει, μπορώ να βάλω και μερικά σχόλια όταν ξημερώσει νέα μέρα.

Δημοσ.

Μην ανησυχείς, ο κώδικας είναι καλογραμμένος και ευανάγνωστος.

 

Πάντως +1 ψήφο και από εμένα για την εγκατάσταση κάποιου plugin για syntax highlighting.

 

Υ.Γ.

Νομίζω οτι κάποια στιγμή σε παλαιότερο post (http://www.insomnia.gr/vb3/showpost.php?p=1342124&postcount=18) ο Alkisg είχε πετύχει highlighting εκμεταλευόμενος την PHP ( ? ) -μου έκανε εντύπωση τότε, λεπτομέρειες όμως δεν γνωρίζω.

Δημοσ.

Τα περισσότερα είναι απόλυτα κατανοητές διαδικασίες, ακόμα και από κάποιον που μόλις έχει μάθει C. Ίσως το πιο cryptic από όλα να είναι η free_array(). Επειδή όταν κάνω pivoting σε γραμμές ουσιαστικά πειράζω τους pointers και δεν ανταλλάζω στοιχεία, υπάρχει περίπτωση να αλλάξω και το a[0] το οποίο δείχνει σε όλο το chunk των δεδομένων με αποτέλεσμα μετά αν απλώς καλέσω free(a[0]) να μην αποδεσμεύσω όλη την μνήμη.

 

Το

>
void free_array(data_type **arr, const size_t N) {
 size_t i;
 data_type *t = arr[0];
 for (i=1; i<N; ++i)
   if (t-arr[i]>0)
     t = arr[i];
 free(t);
 free(arr);
}

ουσιαστικά ψάχνει να βρει ποιο στοιχείο του a έχει την μικρότερη διεύθυνση στη μνήμη - αυτό με την μικρότερη είναι το παλιό a[0] στο οποίο υπήρχε η διεύθυνση όλου του chunk.

 

Γενικά η λύση θέλει κάποιο bookkeeping, αλλά έχει σημαντικά πλεονεκτήματα για matrix calculations.

Δημοσ.

[offtopic]

Για highlighting αρκεί να βάλετε [ΡΗΡ] ακόμα και αν είναι C ο κώδικας:

 

>void free_array(data_type **arr, const size_t N) {
 size_t i;
 data_type *t = arr[0];
 for (i=1; i<N; ++i)
   if (t-arr[i]>0)
     t = arr[i];
 free(t);
 free(arr);
}

 

Και αν ο Hal θέλει, μπορεί να εγκαταστήσει το geshi highlighter που υποστηρίζει ένα σωρό γλώσσες...

[/offtopic]

Δημοσ.

[offtopic #2]Και όποιος έχει πολλή όρεξη, περνάει τον κώδικά του από τον GeSHi to BBCode converter (http://meohaw.net/hotf/replace.php):

>[color=#339933]#include <stdio.h>[/color]
[color=#339933]#include <stdlib.h>[/color]
[color=#339933]#include <string.h>[/color]

[color=#993333]typedef[/color] [color=#993333]int[/color] data_type;

[color=#993333]void[/color] print[color=#66cc66]([/color][color=#993333]const[/color] [color=#993333]char[/color] *name, data_type **arr, [color=#993333]const[/color] size_t N[color=#66cc66])[/color] [color=#66cc66]{[/color]
 size_t i;
 
 [color=#000066]printf[/color][color=#66cc66]([/color][color=#ff0000]"%s=[color=#000099]\n[/color]"[/color], name[color=#66cc66])[/color];
 [color=#b1b100]for[/color] [color=#66cc66]([/color]i=[color=#cc66cc]0[/color]; i<N; ++i[color=#66cc66])[/color]
 [color=#66cc66]{[/color]
   size_t j;
   [color=#b1b100]for[/color] [color=#66cc66]([/color]j=[color=#cc66cc]0[/color]; j<N; ++j[color=#66cc66])[/color]
     [color=#000066]printf[/color][color=#66cc66]([/color][color=#ff0000]"%3d "[/color], arr[color=#66cc66][[/color]i[color=#66cc66]][/color][color=#66cc66][[/color]j[color=#66cc66]][/color][color=#66cc66])[/color];
   putchar[color=#66cc66]([/color][color=#ff0000]'[color=#000099]\n[/color]'[/color][color=#66cc66])[/color];
 [color=#66cc66]}[/color]
[color=#66cc66]}[/color]

[color=#993333]void[/color] pivot[color=#66cc66]([/color]data_type **arr, [color=#993333]const[/color] size_t r1, [color=#993333]const[/color] size_t r2[color=#66cc66])[/color] [color=#66cc66]{[/color]
 data_type *t = arr[color=#66cc66][[/color]r1[color=#66cc66]][/color];
 arr[color=#66cc66][[/color]r1[color=#66cc66]][/color] = arr[color=#66cc66][[/color]r2[color=#66cc66]][/color];
 arr[color=#66cc66][[/color]r2[color=#66cc66]][/color] = t;
[color=#66cc66]}[/color]

[color=#993333]void[/color] free_array[color=#66cc66]([/color]data_type **arr, [color=#993333]const[/color] size_t N[color=#66cc66])[/color] [color=#66cc66]{[/color]
 size_t i;
 data_type *t = arr[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color];
 [color=#b1b100]for[/color] [color=#66cc66]([/color]i=[color=#cc66cc]1[/color]; i<N; ++i[color=#66cc66])[/color]
   [color=#b1b100]if[/color] [color=#66cc66]([/color]t-arr[color=#66cc66][[/color]i[color=#66cc66]][/color]>[color=#cc66cc]0[/color][color=#66cc66])[/color]
     t = arr[color=#66cc66][[/color]i[color=#66cc66]][/color];
 free[color=#66cc66]([/color]t[color=#66cc66])[/color];
 free[color=#66cc66]([/color]arr[color=#66cc66])[/color];
[color=#66cc66]}[/color]

[color=#993333]int[/color] main[color=#66cc66]([/color][color=#993333]void[/color][color=#66cc66])[/color] [color=#66cc66]{[/color]
 [color=#993333]typedef[/color] [color=#993333]int[/color] data_type;

 [color=#993333]const[/color] size_t N = [color=#cc66cc]5[/color];

 data_type **a;
 data_type **b;
 
 size_t i;
 
 [color=#b1b100]if[/color] [color=#66cc66]([/color] [color=#66cc66]([/color]a=malloc[color=#66cc66]([/color]N*[color=#993333]sizeof[/color] *a[color=#66cc66])[/color][color=#66cc66])[/color]==[color=#000000]NULL[/color] [color=#66cc66])[/color]
   exit[color=#66cc66]([/color][color=#cc66cc]-1[/color][color=#66cc66])[/color];
 [color=#b1b100]if[/color] [color=#66cc66]([/color] [color=#66cc66]([/color]a[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color]=malloc[color=#66cc66]([/color]N*N*[color=#993333]sizeof[/color] **a[color=#66cc66])[/color][color=#66cc66])[/color]==[color=#000000]NULL[/color] [color=#66cc66])[/color]
   exit[color=#66cc66]([/color][color=#cc66cc]-1[/color][color=#66cc66])[/color];
 [color=#b1b100]for[/color] [color=#66cc66]([/color]i=[color=#cc66cc]1[/color]; i<N; ++i[color=#66cc66])[/color]
   a[color=#66cc66][[/color]i[color=#66cc66]][/color] = &[color=#66cc66]([/color]a[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color][color=#66cc66][[/color]i*N[color=#66cc66]][/color][color=#66cc66])[/color];

 [color=#b1b100]if[/color] [color=#66cc66]([/color] [color=#66cc66]([/color]b=malloc[color=#66cc66]([/color]N*[color=#993333]sizeof[/color] *b[color=#66cc66])[/color][color=#66cc66])[/color]==[color=#000000]NULL[/color] [color=#66cc66])[/color]
   exit[color=#66cc66]([/color][color=#cc66cc]-1[/color][color=#66cc66])[/color];
 [color=#b1b100]if[/color] [color=#66cc66]([/color] [color=#66cc66]([/color]b[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color]=malloc[color=#66cc66]([/color]N*N*[color=#993333]sizeof[/color] **b[color=#66cc66])[/color][color=#66cc66])[/color]==[color=#000000]NULL[/color] [color=#66cc66])[/color]
   exit[color=#66cc66]([/color][color=#cc66cc]-1[/color][color=#66cc66])[/color];
 [color=#b1b100]for[/color] [color=#66cc66]([/color]i=[color=#cc66cc]1[/color]; i<N; ++i[color=#66cc66])[/color]
   b[color=#66cc66][[/color]i[color=#66cc66]][/color] = &[color=#66cc66]([/color]b[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color][color=#66cc66][[/color]i*N[color=#66cc66]][/color][color=#66cc66])[/color];

 [color=#b1b100]for[/color] [color=#66cc66]([/color]i=[color=#cc66cc]0[/color]; i<N*N; ++i[color=#66cc66])[/color]
   a[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color][color=#66cc66][[/color]i[color=#66cc66]][/color] = i;
 
 print[color=#66cc66]([/color][color=#ff0000]"a"[/color], a, N[color=#66cc66])[/color];
 memcpy[color=#66cc66]([/color]b[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color], a[color=#66cc66][[/color][color=#cc66cc]0[/color][color=#66cc66]][/color], N*N*[color=#993333]sizeof[/color] **a[color=#66cc66])[/color];
 print[color=#66cc66]([/color][color=#ff0000]"b"[/color], b, N[color=#66cc66])[/color];
 pivot[color=#66cc66]([/color]b, [color=#cc66cc]0[/color], [color=#cc66cc]1[/color][color=#66cc66])[/color];
 pivot[color=#66cc66]([/color]b, [color=#cc66cc]0[/color], [color=#cc66cc]3[/color][color=#66cc66])[/color];
 print[color=#66cc66]([/color][color=#ff0000]"b"[/color], b, N[color=#66cc66])[/color];
 
 free_array[color=#66cc66]([/color]a, N[color=#66cc66])[/color];
 free_array[color=#66cc66]([/color]b, N[color=#66cc66])[/color];

 [color=#b1b100]return[/color] EXIT_SUCCESS;
[color=#66cc66]}[/color]

[/offtopic]

Δημοσ.

>
// BUG's home:
/* Copies a to b */
// a array (and b too) wasn't allocated at once so
// it can't be copied at once with:
//    memcpy(b,a,n*n*sizeof(double));
// Use the following codeblock:
   for(i=0;i<n;i++){
       memcpy(b[i],a[i],n*sizeof(double));
   }

 

Πράγματι. Εφόσον χρησιμοποιούμε πολλές malloc δεν πρέπει να θεωρούμε δεδομένο ότι οι θέσεις μνήμης που μας "αφιερώνονται" είναι συνεχείς - στην σειρά. Χωρίς αυτήν την προϋπόθεση η memcpy δεν μπορεί να δουλέψει. Τώρα γιατί το λάθος "έβγαινε" στις free(b); Αυτήν την συμπεριφορά, ενώ την δικαιολογώ απόλυτα, δεν γνωρίζω τους μηχανισμούς που την δημιουργούν.

 

Τώρα: Πώς θα παρακάμψουμε αυτό το θέμα στην C;

 

Για να δούμε τι θέλουμε:

1. Πίνακες 2 διαστάσεων.

2. Δυναμική καταχώρηση μνήμης.

3. Πρόσβαση στα στοιχεία με αριθμοδείκτες (indexes) πχ a[j] και όχι αριθμητική δεικτών (pointers) πχ*(a+i*n+j).

4. Συμπαγή καταχώρηση μνήμης, δηλαδή όλος ο πίνακας να "πιάνει" ένα κομάτι μνήμης και έτσι να είναι δυνατή η χρήση εντολής memcpy ή άλλων ανάλογων όπου απαιτείται.

 

Πως το λύνουμε:

Η λύση βρίσκεται στην καταχώρηση μνήμης για μονοδιάστατο πίνακα και στην συνέχεια η χρήση του από τον διδιάστατο a όπως σωστά προτάθηκε σε αυτό το θέμα. Τώρα για να μην γίνει εξαιρετικά σύνθετο θα πρέπει να περιοριστούμε στα απολύτως απαραίτητα. Προτείνω:

 

>
/* Allocate memory to a as a double array NxN */
   if ((x=malloc(n*n*sizeof(double)))==NULL){
       printf("\nNot enough memory avaliable.\n");
       exit(1);
   }
   if ((a=malloc(n*sizeof(double *)))==NULL){
       printf("\nNot enough memory avaliable.\n");
       exit(1);
   }
   for(i=0;i<n;i++)
       a[i]=x+i*n;

 

Τι κάνω εδώ; μα ότι είπαμε:

1. Πιάνω μνήμη για έναν μονοδιάστατο πίνακα ΝχΝ έστω x

2. Πιάνω μνήμη για έναν πίνακα δεικτών στις γραμμές του έστω a όπως και πριν

3. Δείχνω κάθε a στις σωστές θέσεις μέσα στο x με αριθμητική δεικτών.

 

Και φυσικά όλα δουλεύουν ρολόι (δείτε συνημμένο αρχείο). Το μόνο που πρέπει να προσεχτεί είναι οι απελευθερώσεις μνήμης οι οποίες απλοποιούνται στο εξής:

>
/* Free a array */
   free(a[0]);
   free(a);

 

Ευχαριστώ άπαντες για την ωραία e-συζήτηση.

Αναμένω σχόλια, κριτική και ΣΙΓΟΥΡΑ νέες φρέσκες ιδέες.

 

@all: μετονομάστε το συννημένο σε array2d_malloc.c ώστε να μπορείτε να το χρησιμοποιήσετε

@alkisg: έκανα χρήση του [.p.h.p.] [./.p.h.p.] αντί των [.c.o.d.e.] [./.c.o.d.e.]

-έχω βάλει περιττές τελείες- ελπίζω να είναι καλύτερα. Εκτός απ' αυτό ομολογώ ότι σε περίμενα -και άλλους ίσως- και intopic. Χωρίς παρεξήγηση βέβαια. Απλά έχω συνηθίσει να συναντώ εδώ ή σε ανάλογα θέματα κάποιους insomniac's... (ποτέ δεν είναι αργά) :-)

 

Ο δαίμον του πληκτρολογίου "άφησε" ένα λάθος μέσα στο συννημένο. Να το αφήσω και εγώ με την σειρά μου ως quiz όπως είπε ο φίλος dop; Όχι. Λοιπόν. Η νέα memcpy πρέπει να είναι έτσι:

 

/* Copies a to b */

memcpy(b[0],a[0],n*n*sizeof(double));

 

και ΌΧΙ έτσι:

 

/* Copies a to b */

memcpy(b,a,n*n*sizeof(double));

 

Ζητώ συγνώμμη για το λάθος...

array2d_malloc.txt

Δημοσ.

@chiossif:

μωρέ το πρόβλημα με τη malloc το είχα δει, αλλά κάπου χάθηκα μέσα στο topic και δεν είχα καταλάβει αν ήταν κατά λάθος το σφάλμα ή σε στυλ quiz! :)

 

Εξήγηση: η malloc συνήθως χρησιμοποιεί την ενσωματωμένη βιβλιοθήκη της C, η οποία είναι διαφορετική σε κάθε μηχάνημα/compiler. Συνήθως, όταν κάνουμε malloc(100), γίνονται τα εξής:

[header: μήκος δεσμευμένης μνήμης, πιθανώς pointer στην επόμενη δεσμευμένη και πιθανώς flags για αν χρησιμοποιείται κτλ]

[data - 100 bytes]

 

Ο pointer που μας επιστρέφεται δείχνει στα data.

Αν εμείς πάμε και πειράξουμε το p[-1], πειράζουμε το header.

 

Η free κάνει το αντίθετο. Αν και της περνάμε δείκτη στα data, αυτή "αφαιρεί" κάτι από τον pointer και γυρνάει στο header. Εκεί κάνει κάποια sanity checks και ελευθερώνει τη μνήμη αλλάζοντας τα flags.

Αν αποτύχουν τα sanity checks (π.χ. αρνητικό μέγεθος δεσμευμένης μνήμης) τότε έχουμε το γνωστό segmentation fault στο linux ή exception στα windows.

 

Το header αυτό μπορεί να είναι π.χ. 8 bytes. Άρα ποτέ οι malloc μας δε θα είναι συνεχόμενες, η μέθοδος αυτή έχει πάντα bug. Απλά μερικές φορές μπορεί να μην το πιάσουν με την πρώτη τα sanity checks, θα αφήσει όμως το heap corrupted και θα χτυπήσει σε άσχετη στιγμή παρακάτω.

Δημοσ.

>
#include <stdio.h>

int main (void) {
   int i;
   int j;
   
   i=1;j=2;

   int a[i][j];

   return 0;
}

 

Γιατί να μην γίνεται όπως παραπάνω η ο ορισμός δυναμικών πινάκων (θυμίζω από C99: define anywhere και variable length arrays).

Δημοσ.

@Sta: δυστυχώς το adoption του C99 είναι πιο αργό και από χελώνα. Επιπλέον, έκανα το παρακάτω

 

test_c89.c

>
#include <stdlib.h>

int main(void) {
 size_t i;
 const int N = 5000;
 
 for (i=1; i<=N; ++i)
 {
   int **a;
   size_t j;
   a = malloc(i*sizeof *a);
   if (a==NULL)
   {
     fprintf(stderr, "Error\n");
     exit(-1);
   }
   for (j=0; j<i; ++j)
   {
     a[j] = malloc(i*sizeof **a);
     if (a[j]==NULL)
     {
       fprintf(stderr, "Error\n");
       exit(-1);       
     }
   }
   a[0][0] = 0;
   for (j=0; j<i; ++j)
     free(a[j]);
   free(a);
 }

 return 0;
}

 

test_c99.c

>
#include <stdlib.h>

int main(void) {
 size_t i;
 const int N = 5000;
 
 for (i=1; i<N; ++i)
 {
   int a[i][i];
   a[0][0] = 0;
 }

 return 0;
}

 

Αποτέλεσμα: το test_c89.c έκανε ~1min 25s, το test_c99.c έκανε... μια τρύπα στο νερό (segmentation fault). Ή ο compiler είναι buggy ή ο κώδικάς μου έχει κάποιο λάθος ή υπάρχει κάποιο όριο σε αυτό τον κανόνα (δεν έχω πρόχειρο δυστυχώς το standard μπροστά μου).

Δημοσ.

Dop, μπορεί να φταίει το stack size σου.

int a[5000][5000] <=> 100.000.000 bytes.

Η default stack στα Windows είναι νομίζω 1 Mb (οι μεταβλητές που δηλώνονται σε { block } πάνε στο stack).

 

Δοκίμασε με μικρότερα νούμερα, ή με συνδυασμό malloc/int a.

Δημοσ.

Για το C99 και τις Variable Length Arrays βρήκα ένα ενδιαφέρον FAQ εδώ: http://www.comeaucomputing.com/techtalk/c99/#variablelengtharrays.

 

Όσον αφορά τους γνωστότερους compilers και το C99 από ότι είδα εδώ http://en.wikipedia.org/wiki/C99#C99 φαίνεται πως έχουν προβλήματα μαζί του, κρίμα διότι ορισμένα πράγματα πρέπει να γίνονται ευκολότερα σήμερα ακόμα και για την C :(

Δημοσ.

Έχω τρέξει το 1ο σκέλος του array2d_malloc.txt (έως 45η γραμμή, επισυναπτόμενο σε προηγούμενο post μου) μόνο για τον πίνακα a και ζήτησα Ν=8162. Μου το έδωσε και ενώ εμφάνιζε πίνακα a το διέκοψα με Ctrl-C. Ζήτησα περίπου 508Μ και τα έλαβα ενώ μεγαλύτερες δοκιμές δεν πέτυχαν πχ Ν=16324. Ο ΠΥ μου είναι Pentium III 669 με 768MBram και 384 swap ενώ το OpenSUSE 10.1 (My Computer Konqeror) ανάφερε πριν την εκτέλεση 631.34 ελεύθερα. Μου έκανε εντύπωση στα πολλά δευτερόλεπτα που κράτησε ΜΟΝΟ το malloc η ράβδος της μνήμης του System Monitor του Panel Menu. Α, ξέχασα όλα αυτά ΜΕΣΑ από το IDE μου ( Code::blocks + gcc 4.1.0 ).

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

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

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