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

C απορία.


ntellos

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

Δημοσ.

Έχω μία εργασία για την σχολή, η οποία μας ζητάει να υλοποιήσουμε τον αλγόριθμο της ουράς(queue) σε C. Έχω γράψει το παρακάτω κομμάτι πρόγραμμα

 

>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RAM 3

typedef struct
{
char *contents; 
   	int *front;
   	int *rear; 
   	int maxsize; 
}myqueue;   	

int main()
{
	myqueue *queue; 
queue->contents = (char*) malloc(RAM * sizeof(char)); 
queue->front = (int*) malloc(sizeof(int));  	
queue->rear = (int*) malloc(sizeof(int));

   	*(queue->maxsize)=RAM;
   	*(queue->front)=-1;
   	*(queue->rear)=-1;

//τα υπόλοιπα δεν χρειάζονται
   	
   	return 0;
}

 

και θα ήθελα να φτιάξω μια συνάρτηση queue_init με την οποία να κάνω κάτι τέτοιο (σαφώς και δεν είναι σωστός ο παρακάτω κώδικας)

 

 

>
//Μέχρι εδώ ίδια με πριν

int main()
{
myqueue *queue;

queue_init(queue);

//τα υπόλοιπα δεν χρειάζονται

return 0;
}
void queue_init(type queue))
{
queue->contents = (char*) malloc(RAM * sizeof(char)); 
queue->front = (int*) malloc(sizeof(int));	
queue->rear = (int*) malloc(sizeof(int));

*(queue->maxsize)=RAM;
*(queue->front)=-1;
*(queue->rear)=-1;

}

Δημοσ.

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

Δημοσ.

Θέλεις δλδ αυτό που κάνει στην αρχή της main εσύ να το κάνεις συνάρτηση που θα την καλείς στην main()?

 

Αν απλά θες να αρχικοποιήσεις την "ουρά μέσω μιας συνάρτησης, γίνεται ως εξής:

 

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

#define RAM 3

typedef struct {
       char *contents; 
       int *front;
       int *rear; 
       int maxsize; 
}myqueue;

// ---------------------------
// initialize the queue
//
void queue_init( myqueue *queue )
{
       // queue->contents = (char*) malloc(RAM * sizeof(char)); 
       // queue->front = (int*) malloc(sizeof(int));      
       // queue->rear = (int*) malloc(sizeof(int));

       queue->maxsize = RAM;
       queue->front = NULL;
       queue->rear = NULL;

return;
}

// -------------------------
//
int main( void )
{
myqueue	*queue;

queue_init( queue );

return 0;
}

 

Υποθέτω τα -1 που είχες βάλει, ήθελες να μη δείχνουν πουθενά. Τους pointers όταν δεν θες να δείχνουν πουθενά τους βάζεις την τιμή NULL. Αλλά άμα δεν θες να δείχνουν πουθενά, δεν πρέπει να τους κάνεις καν malloc().

 

Βασικά με έχει μπερδέψει ο κώδικάς σου. Δεν καταλαβαίνω τι ακριβώς θες να κάνεις.

 

Θες όντως οι front και rear να έχουν την τιμή -1 ή να μη δείχνουν πουθενά; Αν δεν θες να δείχνουν πουθενά, τους βάζεις NULL και δεν τους κάνεις καν malloc() μέσα στην queue_init. Ομοίως και για το contents string (έκανα edit και τα έβαλα μέσα σε σχόλια).

 

Αν θες να υπάρχουν όμως με αρχική τιμή -1, τότε το είχες σωστά (malloc'ed δλδ και μετά εκχώρηση της τιμής -1). Αλλά στην αρχικοποίηση συνήθως δεν κάνουμε malloc().

 

Και θυμήσου πως για κάθε malloc() που κάνεις θα πρέπει στο τέλος να κάνεις κι ένα free().

Δημοσ.

Με τα -1 (και RAM) τιμές έδινα πάντως μου έδωσες ιδέα τώρα. O κώδικας δίνει σφάλμα κατάτμησης(segmation fault) και τώρα τον δουλέυω

Δημοσ.

>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RAM 3

typedef struct
{
char *contents;
int *maxsize;
int *front;
int *rear;

}myqueue;
//initialize the queue
void queue_init(myqueue *queue)
{
queue->contents = (char*) malloc(RAM * sizeof(char));
queue->maxsize = (int*) malloc(sizeof(int));
queue->front = (int*) malloc(sizeof(int));
queue->rear = (int*) malloc(sizeof(int));

*(queue->maxsize)=RAM;
*(queue->front)=-1;
*(queue->rear)=-1;

return;
}
//destroy the queue
void queue_destroy(myqueue *queue)
{
free(queue->contents);
free(queue->maxsize);
free(queue->front);
free(queue->rear);

return;
}
int main()
{
myqueue *queue;

queue_init(queue);
printf("aasd\n");
queue_destroy(queue);

return 0;
}

Σφάλμα κατάτμησης στην συνάρτηση queue_init. Αν κάνω comment τις malloc τότε περνάει

Δημοσ.

Πριν χρησιμοποιήσεις τα queue-> πρέπει πρώτα να κάνεις malloc() την queue. Για αυτό σε ρώτησα τι ακριβώς θες να κάνεις....

 

τέσπα, πάω να την πέσω εγώ... καλή συνέχεια.

Δημοσ.

Πριν χρησιμοποιήσεις τα queue-> πρέπει πρώτα να κάνεις malloc() την queue. Για αυτό σε ρώτησα τι ακριβώς θες να κάνεις....

 

τέσπα, πάω να την πέσω εγώ... καλή συνέχεια.

Ευχαριστώ πολύ. 4 το πρωί το μυαλό δεν σκέφτεται :-D

Δημοσ.

Δεν μπορούσα να κοιμηθώ και να σε αφήσω να παιδεύεσαι...

 

ξεκίνα με τον παρακάτω κώδικα, που ελπίζω να αποτελέσει καλή μαγιά για να συνεχίσεις... :mrgreen:

 

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

#define RAM 3

typedef struct {
       char *contents;
       int *maxsize;
       int *front;
       int *rear;
}myqueue;

//---------------------
// create q
//
myqueue *queue_create( myqueue *q )
{
q = malloc( sizeof(myqueue) );
if ( !q )
	return NULL;

q->contents = (char *) malloc(RAM * sizeof(char)) ;
if ( !q->contents ) {
	free( q );
	return NULL;
}

q->maxsize = (int *) malloc( sizeof(int)) ;
if ( !q->maxsize ) {
	free( q->contents);
	free( q );
	return NULL;
}

       q->front = (int *) malloc( sizeof(int) );
if ( !q->front ) {
	free( q->maxsize);
	free( q->contents);
	free( q );
	return NULL;
}

q->rear = (int *) malloc(sizeof(int));
if ( !q->rear ) {
	free( q->front);
	free( q->maxsize);
	free( q->contents);
	free( q );
	return NULL;
}

strncpy(q->contents, "ab", RAM);
*(q->maxsize) = RAM;
*(q->front) = -1;
*(q->rear) = -1;

return q;
}


// -------------------------------
// print q
//
void queue_print( myqueue *q )
{
printf("contents = %s\n", q->contents );
printf("maxsize = %d\n", *(q->maxsize) );
printf("maxsize = %d\n", *(q->front) );
printf("maxsize = %d\n", *(q->rear) );

return;
}

// ---------------------------
// destroy q
//
void queue_destroy(myqueue *q)
{
       free(q->contents);
       free(q->maxsize);
       free(q->front);
       free(q->rear);
free(q);

       return;
}
// ----------------------------
int main( void )
{
myqueue *queue;

queue = queue_create(queue);
if ( !queue ) {
	puts("queue failed to be created");
	return 1;
}

queue_print( queue );
queue_destroy( queue );

printf("\npress ENTER to exit...");
fflush(stdin); 	getchar();

return 0;
}

 

Κανονικά στην create_queue() πρέπει να περνάς σαν παραμέτρους και τις τιμές που θέλεις να πάρουν τα q->contents, q->maxsize, q->front και q->rear πριν σου επιστραφεί το q από τη συνάρτηση.

 

Σημείωσε επίσης πως αυτές οι συναρτήσεις διαχειρίζονται ένα στοιχείο της "ουράς" κάθε φορά. Οπότε πρέπει να τις καλείς κάθε φορά που θες να προσθέσεις νέο στοιχείο στην "ουρά" σου (που το καθένα θα είναι struct myqueue).

 

Και να ενημερώνεις σωστά τους pointers q->rear και q-front για το καθένα που προσθέτεις. Πχ πριν βάλεις ένα καινούριο q στην "ουρά", φρόντισε να ενημερώσεις πρώτα τον ->rear pointer του τελευταίου στοιχείου, ώστε να δείχνει στο νέο q που πας να προσθέσεις (και το ->front του νέου να δείχνει φυσικά στο προηγουμένως τελευταίο στοιχείο της "ουράς"... και το ->rear του νέου στοιχείου να είναι NULL)

 

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

Δημοσ.

Ευχαριστώ για την βοήθεια.

Ουσιαστικά η εργασία μου είναι να υλοποιήσω κάποιες δομές δεδομένων και με ένα μενού να επιλέγει ο χρήστης με ποια δομή θα δουλέψει. Έχω φτιάξει τις δομές που μου ζητάζει. Άρα τώρα η απορία μου είναι πως μπορώ να τρέξω πχ. τα queue.c και stack.c μέσα από ένα τρίτο *.c αρχείο(header file;)

Δημοσ.

Ευχαριστώ για την βοήθεια.

Ουσιαστικά η εργασία μου είναι να υλοποιήσω κάποιες δομές δεδομένων και με ένα μενού να επιλέγει ο χρήστης με ποια δομή θα δουλέψει. Έχω φτιάξει τις δομές που μου ζητάζει. Άρα τώρα η απορία μου είναι πως μπορώ να τρέξω πχ. τα queue.c και stack.c μέσα από ένα τρίτο *.c αρχείο(header file;)

 

 

 

Η δική μου γνώμη είναι να χρησιμοποιηθεί ο κώδικας που παρέθεσε ο παπι.

 

Δηλαδή, θα έχεις μία function για initialisation και από εκεί και πέρα θα έχεις ξεχωριστή function για εισαγωγή κόμβων στην δομή σου.

 

Έτσι, θα μπορείς να ελέγχεις και εάν μπήκε ο κόμβος ή/και εάν έγινε η αρχικοποίηση.

 

Π.χ.,

 

int myStackInitialise(myStack** theStck)

 

όπου εάν έγινε η δέσμευση μνήμης για τον δείκτη που θα δείχνει σε ένα struct τύπου Queue ή Stacκ θα επιστρέφει 1 αλλιώς 0 και έτσι με ένα if θα μπορείς να ελέγχεις εάν έγινε η αρχικοποίηση (π.χ. check = myStackInitiaslise(&theStack); if(~check){error;})

 

Μετά, με μία function int stackAddNode(myStack** theStack) θα εισάγεις κόμβους κτλ κτλ κτλ

Δημοσ.

Πρέπει να τα βάλεις όλα μέσα στο ίδιο project του IDE σου ή αν είσαι σε γραμμή εντολών να φτιάξεις ένα makefile, ώστε να γίνονται compile όλα και ο linker να τα ενώνει στο τέλος σε ένα εκτελέσιμο αρχείο.

 

Είτε έτσι είτε αλλιώς, θα πρέπει να φτιάξεις ένα .h αρχείο με τα πρωτότυπα των συναρτήσεων που έχεις σε όλα σου τα .c αρχεία, και να το κάνεις include στο καθένα ξεχωριστά. Πρωτότυπο μιας συνάρτησης είναι το όνομά της μαζί με τη λίστα και τον τύπο των παραμέτρων της. Π.χ. τα πρωτότυπα των συναρτήσεων στο παράδειγμά μας είναι:

 

>
myqueue *queue_create( myqueue *q );
void queue_print( myqueue *q );
void queue_destroy(myqueue *q);

 

Κάτι άλλο τώρα, που μου έχει κάνει εντύπωση με τον κώδικα που έχεις παρουσιάσει μέχρι τώρα για την "ουρά". Κανονικά οι q->front και q->rear πρέπει να είναι pointers σε myqueue (και όχι pointers σε integer που το έχεις εσύ) και να δείχνουν στον επόμενο και τον προηγούμενο κόμβο της "ουράς", αντίστοιχα. Προφανώς ο ->rear του τελευταίου και ο ->front του πρώτου θα είναι NULL (σε απλές υλοποιήσεις "ουρών").

 

>
typedefef struct qnode{
sometype data;	// τα data του node
struct qnode *front;
struct qnode *rear;
} queueType;

 

Οπότε για να δημιουργήσεις ένα νέο q που θα μπει στο τέλος της "ουράς" (αυτό είναι το νόημα της "ουράς") η queue_create() μπορεί να μετονομαστεί σε queue_insert() που θα δημιουργεί και θα προσθέτει ταυτόχρονα έναν νέο κόμβο q στο τέλος της "ουράς" (που στον κώδικα είναι η αρχή της, αφού θεωρούμε πως το τέλος της είναι αριστερά και η αρχή της δεξιά).

 

Στον παρακάτω κώδικα δείχνω αυτό ακριβώς σε μια απλή "ουρά" από integers. Είναι η πιο απλή, η πιο συνηθισμένη, η πιο γρήγορη και πιστεύω και η πιο κατανοητή υλοποίηση "ουράς" με pointers. Δεν υπάρχει κανένας λόγος να έχεις ξεχωριστές συναρτήσεις για δημιουργία, αρχικοποίηση και προσθήκη.

 

Αυτό που θα εξυπηρετούσε θα ήταν μια ξεχωριστή συνάρτηση για την εκχώρηση τιμών στη μεταβλητή data, πριν την περάσεις ως παράμετρο της queue_insert(), σε περίπτωση που πχ. αντί για int είναι κάποιο struct ή κάποιο array ή κάποια άλλη σύνθετη δομή. Σε αυτή την περίπτωση εξυπηρετεί καλύτερα να περνάς την data ως pointer (και να αλλάξεις αντίστοιχα σε pointer και τη δήλωσή της στο struct qnode) αλλά εκεί τα πράγματα μπορεί να γίνουν αρκετά σύνθετα, αν δεν έχεις κατανοήσει πλήρως τη λειτουργία των pointers.

 

>
#include <stdio.h>
#include <stdlib.h>				// για το malloc()

typedef struct qnode{
       int data;
       struct qnode *front;
       struct qnode *rear;
} queueType;

// ------------------------------------------------------------
queueType *queue_insert( queueType *queue, int data )
{
       queueType *q;

// δημιουργία χώρου για το νέο q
       q = malloc( sizeof(queueType) );	// δεν χρειάζεται casting το malloc()
       if ( !q )				// αποτυχία του malloc()
               return queue;			// επιστρέφουμε την queue ατόφια, όπως μας περάστηκε

       q->data = data;				// ενημέρωση του data
       q->rear = NULL;				// ενημέρωση του q->rear (πάντα NULL στον τελευταίο κόμβο)

// ενημέρωση του q->front
if ( queue ) {				// η "ουρά" έχει ήδη τουλάχιστον έναν ακόμα κόμβο, άρα...
	q->front = queue;		// κάνε το q->front να δείχνει στον πρώην τελευταίο κόμβο
	queue->rear = q;		// και το ->rear του πρώην τελευταίου να δείχνει στο νέο q
}
else					// η "ουρά" είναι άδεια, άρα το q θα είναι ο μόνος κόμβος
	q->front = NULL;		// ενημέρωση του q->front (πάντα NULL στον πρώτο κόμβο) 

// επιστροφή του δημιουργηθέντος q
       return q;
}

// ------------------------------------------------------------
void queue_print( queueType *queue )
{
queueType *q = queue;

while ( q ) {
	printf("%d ", q->data);
	q = q->front;
}
putchar('\n');

return;
}

// ------------------------------------------------------------
void queue_destroy( queueType *queue )
{
queueType *dummy;

if ( !queue )
	return;

while ( queue )
{
	dummy = queue->front;
	free( queue );
	queue = dummy;
}

return;
}
// ------------------------------------------------------------
int main(void)
{
int i;
queueType *queue = NULL;		// σημαντική η αρχικοποίηση σε NULL

// γέμισμα της ουράς με 10 ακεραίους από το 0 έως το 9
for (i=0; i<10; i++)
{
               queue = queue_insert(queue, i);
               if ( !queue ) {
                       printf("error: insertion of %dth element failed\n", i+1);
		break;
	}
}

queue_print(queue);
queue_destroy(queue);

printf("\npress ENTER to exit...");
fflush(stdin); getchar();

   return 0;
}

Δημοσ.

Ξέχασα μια διευκρίνηση για την παραπάνω υλοποίηση της queue_insert(queue, data). Πως επιστρέφει NULL (αποτυχία δλδ) μόνο όταν αποτύχει το malloc() κατά την προσθήκη του πρώτου (μόνου) κόμβου. Στις υπόλοιπες περιπτώσεις επιστρέφει την ενημερωμένη ουρά queue, είτε έχει προστεθεί επιτυχώς ο νέος κόμβος είτε όχι.

 

Αυτός είναι ένας αποδεκτός αυτοματισμός για χάρη της απλοποίησης του κώδικα σε μια μόνο συνάρτηση και άρα της ταχύτερης εκτέλεσης του προγράμματος.

 

Αν μετά το...

 

>
queue = queue_insert(queue, data);

 

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

 

Η πρώτη (και καλύτερη) είναι να ελέγξουμε αν ο τελευταίος κόμβος της ουράς μας έχει τα data του νέου κόμβου, μετά το κάλεσμα της συνάρτησης:

 

>
queue = queue_insert(queue, data);
if (queue->data != data)
	// ο νέος κόμβος δεν προστέθηκε

 

Η δεύτερη είναι να προσθέσουμε μια boolean παράμετρο στην συνάρτηση (π.χ. failed) να τροποποιήσουμε την αρχή της συνάρτησης ως εξής:

 

>
queueType *queue_insert( queueType *queue, int data, int *failed)
{
       queueType *q;
       *failed = 0;

// δημιουργία χώρου για το νέο q
q = malloc( sizeof(queueType) );	// δεν χρειάζεται casting το malloc()
if ( !q ) {				// αποτυχία του malloc()
	*failed = 1;			// ΕΝΗΜΕΡΩΣΗ ΤΗΣ failed ΓΙΑ ΤΗΝ ΑΠΟΤΥΧΙΑ
               return queue;                   // επιστρέφουμε την queue ατόφια, όπως μας περάστηκε
}
...
}

 

και να ελέγξουμε την failed μετά το κάλεσμα της συνάρτησης, ως εξής:

 

>
queue = queue_insert(queue, data, &failed);
if ( failed )
	// ο νέος κόμβος δεν προστέθηκε

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

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

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