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

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


Lomar

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

Χαίρεται,

 

έχω το εξής πρόβλημα:

 

"Να γίνει πρόγραμμα που αφού ορισθεί δυναμικά ο αριθμός των στηλών ενός δισδιάστατου πίνακα 10 γραμμών, στη συνέχεια να ορισθεί με τέτοιο τρόπο ώστε το κάθε στοιχείο του να περιέχει την τιμή Αij=i*j"

 

Αυτή είναι η λύση που έδωσα:

 

>
#include <stdio.h>
#include <stdlib.h>
#define N 10

int main ()
{


int i, j, meg, M;
float **a;

printf ("\n Dwse ton arithmo twn sthlwn tou pinaka: \n");
scanf ("%d",&M);

meg=N*sizeof(int *);

a=malloc(meg);

meg=N*sizeof(float);

for(i=0;i<N;i++)
a[i]=malloc(meg);

if (!a)
{
printf ("\n FAILURE!!! \n");
return;
}

for (i=0;i<N;i++) 
  for (j=0;j<M;j++)
    a[i][j]=i*j;

   
for (i=0;i<N;i++)
 for (j=0;i<M;j++)
   printf ("\n To i einai: %d  to j einai: %d kai to p[i][j] einai: %f \n", i,j,a[i][j]);

free(a);

return 0;
}

 

Και αυτό είναι το πρόβλημα...

 

Το πρόγραμμα εκτελείται κανονικά χωρίς λάθη, αλλά μετά όταν τρέχει, μου εμφανίζει τα εξής μηνύματα:

 

"Dwse ton arithmo twn sthlwn tou pinaka:

/*Γράφω πχ 10, και μου εμφανίζει άπειρες φορές το εξής: */

 

To i einai: 0 to j einai: /*κάτι τεράστια άσχετα αρνητικά νούμερα */ kai to p[j] einai: <non-float printf>

"

 

Και αυτό το σκηνικό επαναλαμβάνεται επάπειρον!!!

 

Λίγη βοήθεια σας παρακαλώ γιατί έχω τρελαθεί, και γενικά δεν έχω πολυκαταλάβει πως ορίζουμε δυναμικά έναν πολυδιάστατο πίνακα, μπορεί να μου εξηγήσει κάποιος τουλάχιστον το θεωρητικό μέρος με απλά και κατανοητά λόγια και παραδείγματα;

 

I'am a desperate programmer :(

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

for (i=0;i<N;i++)

for (j=0;i<M;j++)

printf ("\n To i einai: %d to j einai: %d kai to p[j] einai: %f \n", i,j,a[j]);

 

free(a);

 

1.Arxika nomizw oti sto 2o loop h sun8hkh prepei na einai j<M k oxi i<M.

 

2.Den kaneis pou8ena xrhsh tou plh8ous twn sthlwn pou eisagage o xrhsths

O pinakas sou prepei na exei mege8os N*M, opou N=10 k M = orizetai apo ton xrhsth

 

(einai to deutero pou xrhsimopoeis)

meg=N*sizeof(float);

^^^

Mhpws edw to N prepei na ginei M ???

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Κάπως έτσι:

 

>
#include <stdio.h>
#include <stdlib.h>
#define N 10

int main ()
{


int i, j, meg, M;
int **a;

printf ("\n Dwse ton arithmo twn sthlwn tou pinaka: \n");
scanf ("%d",&M);

meg=N*sizeof(int *);

a=malloc(meg);

if (!a)
{
  printf("FAILURE!!! \n");
  return 1;
}

meg=M*sizeof(int);

for(i=0;i<N;i++)
{
  a[i]=malloc(meg);

  if (!a[i])
  {
     int j;
     for (j=0;j<i;j++)
        free(a[j]);
     printf ("\n FAILURE!!! \n");
     return 1;
  }
}

for (i=0;i<N;i++) 
  for (j=0;j<M;j++)
    a[i][j]=i*j;

   
for (i=0;i<N;i++)
 for (j=0;j<M;j++)
   printf ("\n To i einai: %d  to j einai: %d kai to p[i][j] einai: %d \n",i,j,a[i][j]);

for (i=0;i<N;i++)
  free(a[i]);

free(a);

return 0;
}

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

ΠΡΟΣΟΧΗ ! Λύνει "παραπλήσιο" πρόβλημα. Απλά λέει κάτι άλλο:

 

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

int main () {
   int n, i, j;
   double i1, **a;

   do{
       printf ("\nEnter matrix dimension N>0 : ");
       scanf ("%d",&n);
   }while(n<1);

   if ((a=(double **)malloc(n*sizeof(double *)))==NULL){
       printf("\nNot enough memory available.\n");
       exit(1);
   }

   for(i=0;i<n;i++){
       if ((a[i]=(double *)malloc(n*sizeof(double)))==NULL){
           printf("\nNot enough memory available.\n");
           exit(1);
       }
   }

   for (i=0;i<n;i++){
       i1=(double)i+1;
       a[i][i]=i1/i1;
       for (j=0;j<i;j++)
           a[j][i]=a[i][j]=i1/(j+1);
   }

   for (i=0;i<n;i++){
       for (j=0;j<n;j++)
           printf(" %7.3lf", a[i][j]);
       printf("\n");
   }

   for(i=0;i<n;i++)
       free(a[i]);
   free(a);

   return 0;
}

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αυτο που δεν καταλαβαινω τοσα χρονια ειναι γιατι βαζουν αρκετοι τιμη επιστροφης στη main τη στιγμη που δε χρειαζεται στην πληθωρα των περιπτωσεων οποτε υπαρχει το return 0 μετα.

Ενα απλο void main() κανει τη δουλεια. :)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

1) Η τιμή επιστροφής χρειάζεται στο λειτουργικό για να καταλαβαίνει αν η εφαρμογή έχει επιστρέψει με λάθος ή όχι.

 

2) Στην C, αν δεν επιστρέψεις κάτι, τότε επιστρέφονται σκουπίδια. Αυτό μπορεί να πειράξει, μπορεί και όχι. Στην C++ αν δεν έχει επιστραφεί κάποια τιμή στο τέλος, τότε θεωρείται ότι είναι 0 (ουσιαστικά επιστρέφεις default constructable int, που είναι 0).

 

3) Δοκίμασε το εξής:

>
int foo() {}

int main(void) {
 foo(1, 2, 3, 4, 5, 6, 7);
}

Ω, ναι, το δέχεται αν είναι C compiler. Τι απέγιναν τα ορίσματά σου; Τι θα γίνει αν το κάνεις αυτό στη main()? Ποιος ξέρει...

 

Επίσης, επισκέψου την σελίδα http://c-faq.com και διάβασε τις εξής ερωτήσεις: 11.15, 11.14a, 11.12b, 2.18

 

Γενικά, κάνοντας οτιδήποτε άλλο εκτός int main(void) είσαι εκτός standard.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Simboulh:

Otan kaleis thn malloc kalw einai na kaneis type casting.

H malloc epistrefei void* .

Dhladh:

struct x *p;

p=(struct x*)malloc(sizeof(struct x));

 

kathws epishs kai meta thn malloc h opoiasdipote klishs sistimatos kaneis elegxo.

px if(p==NULL)

perror("Memory allocation error");

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ποτέ casting στην malloc(). Το void* γίνεται αυτόματα casting από τον compiler που ξέρει τι κάνει. Αν κάνεις εσύ casting, μπορεί να κάνεις κάτι πολύ λάθος.

 

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

>
sometype_t *t = malloc(sizeof(*t));
if (t==NULL)
{
 /* error handling code */
}

 

ΥΓ κάποιος mod ας σβήσει το διπλό post παραπάνω

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@dop:

 

1. Αντιγράφω από το κεφάλαιο 7 παράγραφο 8.5 Storage Management του βιβλίου "The C programming Language" των Brian W. Kernighan και Dennis M. Ritchie:

 

"The pointer returned by malloc or calloc has the proper alignment for the object in question, but it must be cast into the appropriate type, as in

int *ip;

 

ip = (int *) calloc(n, sizeof(int));

"

 

Φίλε dop, αναμένω σχόλιο ( και μάθε ότι αν δεν το υπογράφει ένας από τους δύο δύσκολα θα το δεχτώ :-) ).

 

2. int main (void): Συμφωνώ ότι πρέπει να τηρούμε τις "συμφωνίες" μας. Ιδιαίτερα στην C όπου οι "συμφωνίες" υπάρχουν για να προλαμβάνουν λάθη ενώ οι "διαφωνούντες" θα πρέπει να γνωρίζουν καλά τι κάνουν. Στην συγκεκριμένη περίπτωση δεν υπέρχε λόγος "διαφωνίας". Πρόκειται για παράληψη.

 

@MrSeanKon (Αλήθεια, πότε θα γίνει αυτός Sir;)

 

Η τιμή επιστροφής είναι η καλύτερη "συνήθεια" ενός προγραμματιστή που δεν σταματά να προγραμματίζει και μετά τo compilation.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@chiossif: αν και η συνεισφορά των K&R στη C είναι ανεκτίμητη, το πρότυπο έχει εξελιχθεί σε πολλά σημεία. Π.χ. κανείς δε δηλώνει πια τις παραμέτρους των συναρτήσεων με τον τρόπο που πρότειναν...

 

Κοίταξα στο τρέχον πρότυπο, ISO/IEC 9899:TC2, αλλά δε βρήκα σαφή αναφορά στο αν πρέπει να κάνουμε casting ή όχι στη malloc. Όμως εντός του προτύπου έχει 5-6 παραδείγματα με τη malloc, και σε κανένα δε χρησιμοποιεί casting.

 

Από το c-faq που έδωσε ο dop, σχετική απάντηση είναι η http://c-faq.com/malloc/cast.html όπου εξηγεί τι παίζεται και αναφέρει και τους K&R. Καταλήγει λέγοντας ότι το να χρησιμοποιείς casts ή όχι είναι (to some extent) θέμα στυλ.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

:mrgreen: chiossif.

Tα σχολια περιττευουν απο εμενα αφου αναλυσατε το θεμα αρκετα.

Απλα μια απορια πες παρατηρηση εκανα διοτι προερχομαι απο κατι Unixοειδεις οθονες με FORTRAN και goto κι ουδεποτε ασχοληθηκα σοβαρα με τον προγραμματισμο.

Εξαναγκαστηκα να μαθω τα εντελως βασικα για προγραμματισμο σε Windows ομως δεν ειναι το καταλληλο μερος να επεκταθω. :)

Θα παραθεσω ομως εναν υποτηπωδη κωδικα για να σας δειξω μερικες αλχημειες που κανω.

 

>
#include <stdio.h>
void main()
{
   int[] pinakas={1,2};

   pinakas[3]=4;
   pinakas[4]=5;  /* Αυξηθηκε η διασταση του πινακα */  
}

 

Σε ορισμενες περιπτωσεις στον κωδικα της Βιβλου επειδη δε θελω να σπαταλιεται ασκοπα μνημη (σιγα τα λαχανα θα μου πεις ποσα δεδομενα εισαγονται) ε αντι να δηλωνω εκ των προτερων εναν μεγαλο πινακα ο οποιος μπορει να χρησιμοποιησει το 10% του χωρου του, το δηλωνω καπως ετσι. :mrgreen:

Σε Borland τρεχει κανονικα σε Visual Studio C θελει καποιες ψιλομετατροπες αλλα τα ξερετε καλυτερα απο εμενα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@dop:

 

1. Αντιγράφω από το κεφάλαιο 7 παράγραφο 8.5 Storage Management του βιβλίου "The C programming Language" των Brian W. Kernighan και Dennis M. Ritchie:

 

"The pointer returned by malloc or calloc has the proper alignment for the object in question, but it must be cast into the appropriate type, as in

int *ip;

 

ip = (int *) calloc(n, sizeof(int));

"

 

Φίλε dop, αναμένω σχόλιο ( και μάθε ότι αν δεν το υπογράφει ένας από τους δύο δύσκολα θα το δεχτώ :-) ).

 

2. int main (void): Συμφωνώ ότι πρέπει να τηρούμε τις "συμφωνίες" μας. Ιδιαίτερα στην C όπου οι "συμφωνίες" υπάρχουν για να προλαμβάνουν λάθη ενώ οι "διαφωνούντες" θα πρέπει να γνωρίζουν καλά τι κάνουν. Στην συγκεκριμένη περίπτωση δεν υπέρχε λόγος "διαφωνίας". Πρόκειται για παράληψη.

 

@MrSeanKon (Αλήθεια, πότε θα γίνει αυτός Sir;)

 

Η τιμή επιστροφής είναι η καλύτερη "συνήθεια" ενός προγραμματιστή που δεν σταματά να προγραμματίζει και μετά τo compilation.

 

Την C και εγώ την έχω διδαχθεί από αυτό το βιβλίο και μου είχε αφήσει την εντύπωση ότι πρέπει να κάνω πάντα casting όταν κάνω allocation στην μνήμη χρησιμοποιώντας malloc ή calloc. Όμως, θυμάμαι χαρακτηριστικά πως οι καθηγητές που μας έκαναν μάθημα, ο καθένας εξέφραζε διαφορετική άποψη πάνω στο θέμα. Πλέον όμως διαβάζοντας τα παραπάνω αρχίζω να συγκλίνω και εγώ προς την άποψη ότι είναι πιο σωστό να μην κάνεις casting όχι επειδή η γλώσσα σου το επιβάλλει, αλλά επειδή οι compilers πλέον θα το κάνουν καλύτερα από εσένα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Errata index του The C Programming Language: http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html (Errors not corrected in any printing):

142(§6.5, toward the end): The remark about casting the return value of malloc ("the proper method is to declare ... then explicitly coerce") needs to be rewritten. The example is correct and works, but the advice is debatable in the context of the 1988-1989 ANSI/ISO standards. It's not necessary (given that coercion of void * to ALMOSTANYTYPE * is automatic), and possibly harmful if malloc, or a proxy for it, fails to be declared as returning void *. The explicit cast can cover up an unintended error. On the other hand, pre-ANSI, the cast was necessary, and it is in C++ also.

 

Άρα ΟΧΙ CAST ΣΤΗΝ MALLOC. Μπορείς εύκολα να αλλάξεις τον τύπο για τον οποίο δεσμεύεις δυναμικά μνήμη, χωρίς να χρειάζεται να ξανακοιτάξεις όλο το σύμπαν και να διορθώσεις 1) την sizeof και 2) το casting.

 

 

@myle: και οι καθηγητές κάνουν λάθος. Και οι δικοί επέμεναν στο casting και εγώ δεν το χρησιμοποιούσα "επειδή είναι ο σωστός τρόπος" και δεν κρύβει λάθη ;)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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


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