Δυναμική μνήμη μαζί με typedef struct δομή

...ασύγχρονα μαθήματα γλώσσας C

Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό Tasudo » 27 Ιούλ 2011, 13:48

Αντιμετωπίζω πρόβλημα στην χρήση δυναμικής διαχείρισης μνήμης(αρχάριος βλέπετε)μαζί με δομές struct
Συγκεκριμένα κάνω λάθος πιστεύω στον τρόπο που θέτω την διαχείριση σε σχέση με το αντικείμενο που θέλω


Πιο συγκεκριμένα

Στο συγκεκριμένο πρόγραμμα ενώ μπορεί να δώσω ως input για numwords το 3
Οταν μπαίνει μέσα στην for στην οποία γίνεται εισαγωγή των λέξεων
Η scanf "εκτελείται" μόνο μία φορά κατά την εκτέλεση ενώ τα print συνεχίζουνε σύμφωνα με τον δοσμένο αριθμό.

Τι λάθος κάνω???? :problem:
Σημείωση:το πρόγραμμα είναι ημιτελές


Κώδικας: Επιλογή όλων

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

#define WORDSIZE 20
#define MAXWORDS 5


typedef struct {
char *word; /* metabliti xaraktiron*/
char *digits; /* metabliti psifion*/
} infoT;


int main (int argc, char *argv[]) {

infoT *pairs;
char format_str[20];
int numwords;
int i;

pairs = NULL; /* initialize pairs*/
numwords = 0;
sprintf(format_str,"%%%ds",WORDSIZE-1);

do {
printf("Enter number of words: "); /* Minima eisagogis arithmou lekseon*/
scanf("%d", &numwords); /* Eisagogi arithmou lekseon apo to pliktrologio*/
if ( (numwords < 0) || (numwords > MAXWORDS) ) /* Elegxos sostis eisagogis arithmou lekseon*/
printf("Wrong number input!\n");

}while ( (numwords < 0) || (numwords > MAXWORDS) );

pairs = (infoT *)realloc(pairs,numwords*sizeof(infoT)); /* Dunamiki desmeusi mnimis gia numword pairs*/
if ( pairs == NULL ) {
printf("Memory allocation error\n");
return (1);
}

for (i=0; i<numwords; i++) {
printf("Enter word: "); /* Minima eisagogis leksis*/
scanf(format_str,pairs[i].word); /* Eisagogi leksis apo to pliktrologio*/


}




printf("END\n");

return 0;
}

Tasudo
babeTUX
babeTUX
 
Δημοσιεύσεις: 16
Εγγραφή: 24 Ιούλ 2011, 18:27
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό Tasudo » 27 Ιούλ 2011, 16:52

Τελικά κατάφερα να λύσω το πρόβλημα(προς το παρόν),οπότε θεωρείστε το άκυρο
Tasudo
babeTUX
babeTUX
 
Δημοσιεύσεις: 16
Εγγραφή: 24 Ιούλ 2011, 18:27
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό clepto » 27 Ιούλ 2011, 17:21

γράψε και την λύση για την κάποιος που μπορεί να την χρειαστεί...
1 Γνώσεις Linux: Ικανοποιητικό ┃ Προγραμματισμού: Ικανοποιητικό ┃ Αγγλικών: Ικανοποιητικό
2 Ubuntu 13.04 raring 3.8.0-30-generic 64bit (en_US.UTF-8, Unity ubuntu), Ubuntu 3.8.0-19-generic, Windows 7
3 Intel Core i7-3537U CPU @ 2.00GHz ‖ RAM 3840 MiB ‖ ASUS K56CB
4 Intel 3rd Gen Core processor Graphics Controller [8086:0166] {i915}
5 wlan0: Atheros Inc. AR9485 Wireless Network Adapter [168c:0032] (rev 01) ⋮ eth0: Realtek RTL8111/8168 PCI Express Gigabit Ethernet controller [10ec:8168] (rev 0a)
clepto
antiwinTUX
antiwinTUX
 
Δημοσιεύσεις: 4102
Εγγραφή: 07 Ιαν 2010, 16:27
Τοποθεσία: Πάτρα
Launchpad: christriant
IRC: Clepto
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό migf1 » 27 Ιούλ 2011, 17:31

Tasudo έγραψε:Τελικά κατάφερα να λύσω το πρόβλημα(προς το παρόν),οπότε θεωρείστε το άκυρο

Ποιο ήταν το λάθος τελικά; Γράψε το αν θες για να είναι χρήσιμο το post και σε άλλα παιδιά.

Αυτό που βλέπω εγώ πάντως στον παραπάνω κώδικα, είναι πως με το scanf στο σώμα του for-loop επιχειρείς να διαβάσεις ως string το pairs[i].word, αλλά το πεδίο word στη δομή infoT είναι ορισμένο ως δείκτης σε char, για τον οποίο όμως δείκτη δεν έχεις δεσμεύσει μνήμη. Η πιο εύκολη λύση είναι να ορίσεις το εν λόγω πεδίο ως string μέσα στην δομή του infoT (δηλαδή αντί για: char *word; που το έχεις τώρα, να το ορίσεις ως: char word[WORDSIZE];). Αυτό βέβαια σημαίνει πως τα word μέσα σε όλα τα pairs θα έχουν fixed μέγιστο μήκος ίσο με WORDSIZE (καλό είναι αυτό, δες παρακάτω) και θα σου δουλεύει το scanf().

Η πιο δύσκολη λύση (αν δλδ θες να είναι δυναμικό και το μέγιστο μήκος του εκάστοτε word μέσα στον pairs) είναι:
  • να διαβάζεις με το scanf() την κάθε λέξη σε ένα προσωρινό string (π.x. tmpstring[WORDSIZE])
  • να μετράς κατόπιν το ωφέλιμο μήκος του, με: int tmplen = strlen(tmpstring)+1 (δλδ το πλήθος των χαρακτήρων που σου πληκτρολόγησε ο χρήστης + 1 για τον μηδενικό χαρακτήρα στο τέλος)
  • να δεσμεύεις μνήμη για το εκάστοτε word: pairs[i].word = malloc( tmplen * sizeof char); (θέλει κι έλεγχο για το αν πέτυχε το malloc() )
  • να αντιγράφεις το tmpstring στο word: strncpy( pairs[i].word, tmpstring, WORDSIZE);
Btw, το κολπάκι που κάνεις με το format_str δεν είμαι καθόλου σίγουρος πως δουλεύει σωστά!

Επίσης, το να ΜΗΝ φιξάρεις το μέγιστο μήκος των word σε WORDSIZE (αλλά να το δεσμεύεις κι αυτό δυναμικά) θα σου δημιουργήσει έξτρα πονοκεφάλους αν χρειαστεί να σώζεις τα pairs σε αρχείο, το οποίο θα πρέπει κατόπιν να ξαναδιαβάσεις. Κι αυτό γιατί δεν θα καταλαμβάνουν όλα τα pairs το ίδιο πλήθος bytes μέσα στο αρχείο σου.

Επίσης, γιατί χρησιμοποιείς realloc() για το allocation του pairs; Εκεί θες malloc() ή calloc(). Το realloc() τα βάζουμε μονάχα όταν θέλουμε να επαναπροσδιορίζουμε δυναμικά το αρχικό μέγεθος μνήμης που έχουμε δεσμεύσει.

Συμπτωματικά, χτες έφτιαξα κι εγώ μια συνάρτηση που χρησιμοποιούσα realloc() και ανακάλυψα κάτι που δεν το γνώριζα: πως το realloc() πρέπει να χρησιμοποιείται με χρήση προσωρινού δείκτη πριν το εφαρμόσουμε στον κανονικό μας δείκτη. Το σχετικό νήμα βρίσκεται εδώ αν θες να διαβάσεις λεπτομέρειες
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό Tasudo » 27 Ιούλ 2011, 20:13

migf1 έχεις δίκιο,πολύς πονοκέφαλος...
έκανα κάποιες αλλαγές αλλα πλέον αντιμετωπίζω πρόβλημα πάλι με την μνήμη :(

Κώδικας: Επιλογή όλων


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

#define WORDSIZE 20
#define MAXWORDS 5


typedef struct {
char word[MAXWORDS]; /* metabliti xaraktiron*/
char digits[MAXWORDS]; /* metabliti psifion*/
} infoT;



char* new_string(char input_word[MAXWORDS],int number);

int main (int argc, char *argv[]) {

infoT pairs[MAXWORDS];

char format_str[20];
int numwords;
int i;


/* initialize pairs*/
numwords = 0;
sprintf(format_str,"%%%ds",WORDSIZE-1);

do {
printf("Enter number of words: "); /* Minima eisagogis arithmou lekseon*/
scanf("%d", &numwords); /* Eisagogi arithmou lekseon apo to pliktrologio*/
if ( (numwords < 0) || (numwords > MAXWORDS) ) /* Elegxos sostis eisagogis arithmou lekseon*/
printf("Wrong number input!\n");

}while ( (numwords < 0) || (numwords > MAXWORDS) );


for (i=0; i<numwords; i++) {
pairs[i] = (infoT*)malloc(sizeof(infoT)*MAXWORDS); /* Dunamiki desmeusi mnimis gia numword pairs*/


if ( pairs == NULL ) {
printf("Memory allocation error\n");
return (1);
}
}

for (i=0; i<numwords; i++) {
printf("Enter word: \n"); /* Minima eisagogis leksis*/
scanf(format_str,pairs[i].word); /* Eisagogi leksis apo to pliktrologio*/


}





printf("END\n");

return 0;
}



Κατά το compiling o compiler εμφανίζει error: incompatible types when assigning to type ‘infoT’ from type ‘struct infoT * -- δηλαδή τι τύπους δεδομένων μπερδεύω???Help!!!
το οποίο αφορά την δέσμευση μνήμης.Που θα πει οτι ακόμα δεν έχω καταλάβει πως μπορώ να δεσμεύσω δυναμικά μνήμη
σε δομές δεδομένων.


Όσο για το κόλπο που λες με την format_str το έχω χρησιμοποιήσει και άλλες φορές και έχει λειτουργήσει(i think)
Tasudo
babeTUX
babeTUX
 
Δημοσιεύσεις: 16
Εγγραφή: 24 Ιούλ 2011, 18:27
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό migf1 » 27 Ιούλ 2011, 20:47

Tasudo έγραψε:migf1 έχεις δίκιο,πολύς πονοκέφαλος...
έκανα κάποιες αλλαγές αλλα πλέον αντιμετωπίζω πρόβλημα πάλι με την μνήμη :(

Spoiler: show
Κώδικας: Επιλογή όλων


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

#define WORDSIZE 20
#define MAXWORDS 5


typedef struct {
char word[MAXWORDS]; /* metabliti xaraktiron*/
char digits[MAXWORDS]; /* metabliti psifion*/
} infoT;



char* new_string(char input_word[MAXWORDS],int number);

int main (int argc, char *argv[]) {

infoT pairs[MAXWORDS];

char format_str[20];
int numwords;
int i;


/* initialize pairs*/
numwords = 0;
sprintf(format_str,"%%%ds",WORDSIZE-1);

do {
printf("Enter number of words: "); /* Minima eisagogis arithmou lekseon*/
scanf("%d", &numwords); /* Eisagogi arithmou lekseon apo to pliktrologio*/
if ( (numwords < 0) || (numwords > MAXWORDS) ) /* Elegxos sostis eisagogis arithmou lekseon*/
printf("Wrong number input!\n");

}while ( (numwords < 0) || (numwords > MAXWORDS) );


for (i=0; i<numwords; i++) {
pairs[i] = (infoT*)malloc(sizeof(infoT)*MAXWORDS); /* Dunamiki desmeusi mnimis gia numword pairs*/


if ( pairs == NULL ) {
printf("Memory allocation error\n");
return (1);
}
}

for (i=0; i<numwords; i++) {
printf("Enter word: \n"); /* Minima eisagogis leksis*/
scanf(format_str,pairs[i].word); /* Eisagogi leksis apo to pliktrologio*/


}

printf("END\n");

return 0;
}


Κατά το compiling o compiler εμφανίζει error: incompatible types when assigning to type ‘infoT’ from type ‘struct infoT * -- δηλαδή τι τύπους δεδομένων μπερδεύω???Help!!!
το οποίο αφορά την δέσμευση μνήμης.Που θα πει οτι ακόμα δεν έχω καταλάβει πως μπορώ να δεσμεύσω δυναμικά μνήμη
σε δομές δεδομένων.

Όσο για το κόλπο που λες με την format_str το έχω χρησιμοποιήσει και άλλες φορές και έχει λειτουργήσει(i think)

Καταρχήν νομίζω πως τα πεδία: word και digits θέλεις να τα ορίσεις με μέγιστο μήκος ίσο με WORDSIZE και όχι με MAXWORDS που τα έχεις τώρα.

Σχετικά με το μήνυμα του compiler τώρα, γράψε σε ποια γραμμή σου βγάζει το error (κάνε την παράθεση).
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό Tasudo » 27 Ιούλ 2011, 21:03

Το μήνυμα εμφανίζεται στη γραμμή 42:15 δλδ στη 42 που είναι το malloc και ειναι η
Κώδικας: Επιλογή όλων

for (i=0; i<numwords; i++) {
pairs[i] = (infoT*)malloc(sizeof(infoT)*MAXWORDS); /* Dunamiki desmeusi mnimis gia numword pairs*/
.....
Tasudo
babeTUX
babeTUX
 
Δημοσιεύσεις: 16
Εγγραφή: 24 Ιούλ 2011, 18:27
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό migf1 » 27 Ιούλ 2011, 21:19

Είναι επειδή το pairs[i] είναι ορισμένο ως τύπος infoT από το:
Κώδικας: Επιλογή όλων

infoT pairs[MAXWORDS];

και μετά πας να το κάνεις allocate ως δείκτη σε infoT, με το:
Κώδικας: Επιλογή όλων

pairs[i] = (infoT*) malloc( MAXWORDS * sizeof(infoT) );

Οπότε συντακτικά είναι λάθος.

Πέρα όμως από το συντακτικό λάθος, είναι και λογικό σφάλμα. Ο ορισμός του pairs ως πίνακα από MAXWORDS στοιχεία τύπου infoT έχει ήδη δεσμεύσει χώρο στη μνήμη γι όλα τα στοιχεία του πίνακα. Σε πίνακες δεν μπορείς να κάνεις malloc, μόνο σε δείκτες.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό Tasudo » 27 Ιούλ 2011, 21:46

Κατάλαβα,ευχαριστώ...

Δηλαδή μια λύση θα ήτανε τον πίνακα pairs να τον αλλάξω και να τον κάνω πίνακα από δείκτες;;
Συγγνώμη αν πρήζω με ερωτήσεις...
Tasudo
babeTUX
babeTUX
 
Δημοσιεύσεις: 16
Εγγραφή: 24 Ιούλ 2011, 18:27
Εκτύπωση

Re: Δυναμική μνήμη μαζί με typedef struct δομή

Δημοσίευσηαπό migf1 » 27 Ιούλ 2011, 22:15

Λοιπόν, σου έγραψα καθαρό και σωστό τον κώδικα:
Spoiler: show
Κώδικας: Επιλογή όλων

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

#define MAX_INBUFFER (255+1)

#define WORDSIZE (20+1)
#define MAXWORDS 5

typedef struct {
char word[ WORDSIZE]; /* metabliti xaraktiron*/
char digits[ WORDSIZE ]; /* metabliti psifion*/
} infoT;

// char *new_string(char input_word[MAXWORDS],int number);

// -----------------------------------------------------------------------------------
char *read_line(char *line, int len)
{
if ( len == 0 )
return NULL;

if ( fgets(line, len, stdin) == NULL )
return NULL;

line[ strlen(line) - 1 ] = '\0';

return line;
}

// -----------------------------------------------------------------------------------
int main (void )
{
char inbuffer[ MAX_INBUFFER ] = "";

infoT *pairs = NULL;
int numwords = 0;
int i;

do {
printf("Enter number of words (1-%d): ", MAXWORDS);
read_line(inbuffer, MAX_INBUFFER);
numwords = atoi( inbuffer );
} while ( numwords < 1 || numwords > MAXWORDS );

pairs = calloc( numwords, sizeof(infoT) );
if ( !pairs ) {
printf("Memory allocation error\n");
return 1;
}

for (i=0; i < numwords; i++)
{
do {
printf("Enter word #%d: ", i+1);
read_line( inbuffer, MAX_INBUFFER );
strncpy( pairs[i].word, inbuffer, WORDSIZE-1 );
} while ( pairs[i].word[0] == '\0' );
}

puts("you entered:");
for (i=0; i < numwords; i++)
printf("\t\t%s\n", pairs[i].word);

free( pairs );
printf("END\n");

return 0;
}

Ελπίζω αυτή τη φορά να το διαβάσεις γιατί νομίζω πως την προηγούμενη φορά δεν τον διάβασες ή δεν του έδωσες την προσοχή που έπρεπε.

Σε ότι αφορά τη διαχείριση της δυναμικής μνήμης, πιστεύω πως πρέπει να είναι ξεκάθαρος. Όσο για τα υπόλοιπα που θα δεις, δεν είναι τίποτα άλλο από το ΠΕΤΑΜΑ ΣΤΑ ΣΚΟΥΠΙΔΙΑ συναρτήσεις όπως η scanf η sprintf και το format_str που χρησιμοποιούσες για να διαβάσεις το input από τον χρήστη.

Το κόλπο με το format_str δεν σε γλιτώνει από το γνωστό πρόβλημα του line-buffering και των απομειναριών, που έχουμε κατά κόρο αναλύσει στο φόρουμ. Ο πλέον συμβατός και αποτελεσματικός τρόπος να διαβάζεις την είσοδο από κονσόλα στη C είναι να διαβάζεις μονοκόμματη τη γραμμή εισόδου σε ένα δικό σου, πολύ μεγάλο string, και κατόπιν να κρατάς μόνο ότι χρειάζεσαι από τη γραμμή αυτή και να το βάζεις στισ μεταβλητές σου.

Στο παραπάνω κώδικα το string αυτό το ονομάζω inbuffer με μέγιστο μήκος MAX_INBUFFER και η ανάγνωσή του γίνεται με τη συνάρτηση: read_line. Στον προηγούμενο κώδικα που σου είχα δώσει έκανα ακριβώς το ίδιο πράγμα, μόνο που εκεί τη συνάρτηση ανάγνωσης της γραμμής την ονόμαζα: s_get (ή οποία λειτουργεί πολύ πιο γρήγορα από την τωρινή: read_line, γιατί η τωρινή χρησιμοποιεί την fgets, η οποία βάζει μέσα στο string και το ENTER που πατάει ο χρήστης... οπότε αναγκάζομαι να πηγαίνω και να το σβήνω μετά το διάβασμα).

Την 1η φορά που τη χρησιμοποιώ είναι όταν θέλω να διαβάσω το: numwords. Διαβάζω πρώτα τη γραμμή εισόδου: inbuffer με την read_line και κατόπιν μετατρέπω το inbuffer σε int με την συνάρτηση: atoi.

Τη 2η φορά που τη χρησιμοποιώ είναι όταν διαβάζω μέσα στο for-loop τα: pairs[i].word. Διαβάζω πρώτα τη γραμμή εισόδου μέσα στο inbuffer και κατόπιν αντιγράφω τους WORDSIZE-1 πρώτους χαρακτήρες της μέσα στο pairs[i].word.

Με αυτή την τεχνική, για να γίνει overflow η γραμμή εισόδου πρέπει ο χρήστης να πληκτρολογεί πάνω από 255 χαρακτήρες (MAX_INBUFFER-1) σε κάθε είσοδο. Πράγμα σπάνιο έως απίθανο, οπότε αποφεύγεται το πρόβλημα που παρουσιάζεται με τις scanf, getchar, κλπ
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Επόμενο

Επιστροφή στο Μαθήματα C

cron