Τα πάντα για την C

...του ubuntu και έργων ΕΛ/ΛΑΚ (Έργα-Οδηγοί-Προτάσεις)

Συντονιστής: konnn

Re: Τα πάντα για την C

Δημοσίευσηαπό Ilias95 » 04 Μαρ 2012, 21:50

Να λοιπόν η άσκηση με two dimensional array:

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // memset()
#include <stdlib.h> // srand(), rand()
#include <time.h> // time()

#define ALPHABETA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define NUM_ALPHABETA sizeof(ALPHABETA) / sizeof(ALPHABETA[0])

#define NUM_ROWS 10
#define NUM_COLUMNS 10

int main(void)
{
int row = 0, col = 0;
char table[NUM_ROWS][NUM_COLUMNS];

memset(table, '.', sizeof(table)); // init table with dots
table[0][0] = ALPHABETA[0];

srand((unsigned) time(NULL));

for (int i = 1; i < NUM_ALPHABETA - 1; i++) {
if ((table[row+1][col] != '.' || row == NUM_ROWS-1) && (table[row-1][col] != '.' || row == 0) && \
(table[row][col+1] != '.' || col == NUM_COLUMNS-1) && (table[row][col-1] != '.' || col == 0)) {
break; // terminate if there is no available position
}

while (1) {
int move = rand() % 4;

if (move == 0 && row > 0 && table[row-1][col] == '.') {
row--; // UP
break;
}
else if (move == 1 && col < NUM_COLUMNS-1 && table[row][col+1] == '.') {
col++; // RIGHT
break;
}
else if (move == 2 && row < NUM_ROWS-1 && table[row+1][col] == '.') {
row++; // DOWN
break;
}
else if (move == 3 && col > 0 && table[row][col-1] == '.') {
col--; // LEFT
break;
}
}
table[row][col] = ALPHABETA[i];
}

for (row = 0 ; row < NUM_ROWS; row++) {
for (col = 0; col < NUM_COLUMNS; col++)
printf("%c ", table[row][col]);
putchar('\n');
}

return 0;
}


ΥΓ. Με έσκασε μέχρι να το κάνω να δουλέψει. Δύο ώρες μου πήρε για να καταλάβω στο τέλος ότι είχα συντακτικό λάθος! :wtf:
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό konnn » 04 Μαρ 2012, 21:58

Ilias95 έγραψε:Ποιο είναι το πλεονέκτημα του να δηλώνουμε μεταβλητές σαν const;

http://en.wikipedia.org/wiki/Constant_(programming)
1 Linux: Μέτριος ┃ Προγραμματισμός: Μέτριος ┃ Αγγλικά: Προχωρημένος
2 Desktop : Ubuntu 16.04 64bit
a Intel Core i3 CPU 530 2.93GHz ‖ RAM 3824 MiB ‖ Intel DH55HC -
b nVidia Device [10de:1040] (rev a1)
c eth0: Intel 82578DC Gigabit Network Connection
3 Notebook : Ubuntu 16.04 64 bit
a Intel Core i3-2365M CPU @ 1.40GHz ‖ RAM 3854 MiB ‖ LENOVO 20197
b Intel 2nd Generation Core Processor Family Integrated Graphics Controller
c 5 wlan0: Intel Centrino Wireless-N 2230 ⋮ eth0: Realtek RTL8101E/RTL8102E

Αυτόματη υπογραφή.
Άβαταρ μέλους
konnn
Συντονιστής
Συντονιστής
 
Δημοσιεύσεις: 3568
Εγγραφή: 12 Ιούλ 2010, 17:54
Τοποθεσία: Καλαμάτα
Launchpad: konnn
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 02:18

Ilias95 έγραψε:
Θα μπορούσε να γίνει one-liner:
Spoiler: show
Μορφοποιημένος Κώδικας: Επιλογή όλων
_Bool pos_isblocked( const int pos, const char tab[] )
{
return (ROW(pos) == 0 || '.' != tab[POSUP(pos)]) && (ROW(pos) == NROWS-1 || '.' != tab[POSDN(pos)]) && (COL(pos) == 0 || '.' != tab[POSLF(pos)]) && (COL(pos) == NCOLS-1 || '.' != tab[POSRT(pos)]);
}

Έτσι θα επιστέψει αμέσως μόλις βρει μία κατεύθυνση που δεν είναι μπλοκαρισμένη.

Yeap :)
Επειδή όμως δεν είμαι σε θέση τώρα να κάνω εκτεταμένο debugging (έχω κοπανήσει κάτι ούζα :lol:) αφήνω και την συνάρτηση στον κώδικα, σε περίπτωση που παρουσιάσει προβλήματα το one-liner ... το οποίο, btw, το υλοποίησα ως macro...
1η πλήρης λύση της άσκησης: http://ideone.com/5bsaB

Τώρα, έφτιαξα και μια 2η υλοποίηση της άσκησης, η οποία θεωρητικά εκτελείται πολύ ταχύτερα (αλλά όπως είπα και πριν, δεν είμαι τώρα σε θέση να κάνω benchmarks, λόγω ούζων :lol:) ...
2η πλήρης λύση της άσκησης (ταχύτερη και πιο λιτή): http://ideone.com/fT57L

Αυτή η 2η υλοποίηση λειτουργεί ως εξής:

Για κάθε τετράγωνο στη θέση pos που επισκέπτεται, καλεί την συνάρτηση...
Μορφοποιημένος Κώδικας: Επιλογή όλων
int avail_count( const int pos, const char tab[], int avail[ NDIRS ] )
η οποία αποθηκεύει μέσα στον πίνακα avail[ NDIRS ] τις θέσεις των ελεύθερων γειτονικών τετραγώνων, κι επιστρέφει το πλήθος τους στη μεταβλητή: navail.

Αν το επιστρεφόμενο πλήθος είναι 0, τότε σημαίνει πως όλα τα γειτονικά τετράγωνα ήταν μπλοκαρισμένα, οπότε τερματίζεται το loop. Αλλιώς, επιλέγεται τυχαία μια θέση του πίνακα avail[NDIRS] από την 0 έως την navail-1 : ( rand() % navail ) και το περιεχόμενο της εκχωρείται στην μεταβλητή pos...
Μορφοποιημένος Κώδικας: Επιλογή όλων
pos = avail[ rand() % navail ];

Η pos είναι πλέον η νέα θέση στον βασικό μας πίνακα tab[] ;)

ΥΓ1. Το const Ηλία απλώς εγγυάται πως τα περιεχόμενα της μεταβλητής δεν μπορούν να αλλάξουν, ούτε και κατά λάθος. Οποιαδήποτε απόπειρα μεταβολής στην τιμή μιας μεταβλητής που έχει οριστεί με πρόθεμα const προκαλεί compiler-error (constant σημαίνει σταθερά, και σε ορισμένες περιπτώσεις μπορείς να τα σκεφτείς ως εναλλακτικές επιλογές των #define ).

Π.χ. στην 2η λύση έχω χρησιμοποιήσει const για να ορίσω την μεταβλητή: NMOVES ίση με το μήκος του string USED (τα γράμματα της αλφαβήτου). Αν το είχα ορίσει με #define στον προ-επεξεργαστή, τότε στη συνθήκη του while-loop...

Μορφοποιημένος Κώδικας: Επιλογή όλων
while ( imove < NMOVES ) ...

θα έτρεχε συνεχώς η συνάρτηση strlen() σε ΚΑΘΕ επανάληψη του loop (η strlen() διατρέχει όλους τους χαρακτήρες του string-ορίσματός της, μέχρι να συναντήσει μηδενικό χαρακτήρα κι επιστρέφει το πλήθος τους). Ο προ-επεξεργαστής κάνει απλό search & replace στον κώδικά σου ότι του έχεις ορίσει στα #define, πριν ξεκινήσει το compilation.

Δηλαδή στην προκειμένη περίπτωση, αν είχα ορίσει το NMOVES με #define...
Μορφοποιημένος Κώδικας: Επιλογή όλων
#define NMOVES   strlen(USED)

τότε η συνθήκη στο while θα μεταφραζόταν ΠΡΙΝ το compilation έτσι...
Μορφοποιημένος Κώδικας: Επιλογή όλων
while ( imove < strlen(USED) ) ...

μέτρημα του μήκους του USED σε κάθε επανάληψη!

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

Υπάρχουν κι άλλες και ουσιώδεις διαφορές μεταξύ const και #define, αλλά υποθέτω θα τα καταλάβεις καλύτερα όταν φτάσεις στο κεφάλαιο που μιλάει αποκλειστικά για τον προ-επεξεργαστή.

ΥΓ2. Όντως πολύ ωραία η άσκηση :)
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό Star_Light » 05 Μαρ 2012, 07:09

@migf1 ειχανε και μεζεκλίκια διπλα τα ουζάκια ή τα ήπιες ξεροσφύρι? :lol: :lol:

ΤΗν πρωτη φορα που δοκιμασα ουζο ηταν οταν ενα βραδυ ξύπνησα με ασχημο πονοδοντο... οποτε πηγα να κανω μερικες γαργαρες για
να με μουδιάσει και μ αρεσε και άρχισα να πινω στις 3... 4 το πρωι!!!!!!!!!!!!!!!!!!!!!! Μετα επεσα για υπνο καθως ειχε φυγει ο πονος απο το δοντι
αλλα το πρωι σηκωθηκα με ενα στομαχι καζανι :lol: :lol:
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 12:52

Καλή φάση Κώστα :lol: (όχι ξεροσφύρι, ξεσκίστηκα στα θαλασσινά :lol:)

Κοίταγα πριν τον κώδικα της 2ης λύσης κι έχει bug στην συνάρτηση avail_count().
Η γραμμή...

Μορφοποιημένος Κώδικας: Επιλογή όλων
/* is row-dn'ed pos available? */
if ( ROW(pos) < NROWS && ...

πρέπει να αλλάξει σε...

Μορφοποιημένος Κώδικας: Επιλογή όλων
/* is row-dn'ed pos available? */
if ( ROW(pos) < NROWS-1 && ...

Την διόρθωσα και στο ideone.com.

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

Μέσα στο κεντρικό loop της main() η 1η υλοποίηση κάνει συγκρίσεις α) με το macro ISBLOCKED() β) με τη συνάρτηση: get_nextpos() και γ) στη συνθήκη του φωλιασμένου do-while loop. Επίσης καλεί συνέχεια την rand() μέχρι να βρει διαθέσιμο τετράγωνο

Ας πούμε για παράδειγμα ότι υπάρχουν 2 διαθέσιμα τετράγωνα γειτονικά του τρέχοντος. Με την 1η υλοποίηση η rand() μπορεί κάλλιστα τις πρώτες 10 φορές να "βαρέσει" στα 2 άλλα μη-διαθέσιμα, οπότε θα χρειαστεί να επαναλάβει 11 φορές τόσο τις συγκρίσεις της get_nextpos() όσο και τη σύγκριση της συνθήκης του do-while loop.

Αντίθετα, η 2η υλοποίηση θα κάνει μια και μόνη φορά τις συγκρίσεις της avail_count() και κατόπιν χρησιμοποιήσει την επιστρεφόμενη τιμή της συνάρτησης ως όριο μιας και μόνης κλήσης της rand(). Η 2η υλοποίηση έχει ένα έξτρα overhead το γέμισμα του πίνακα avail[] μέσα στην avail_count(), το οποίο όμως είναι πολύ μικρό τίμημα συγκριτικά με τις τόσο πολύ περισσότερες συγκρίσεις που κάνει η 1η υλοποίηση.

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

Re: Τα πάντα για την C

Δημοσίευσηαπό Star_Light » 05 Μαρ 2012, 14:43

Τρέχετε λιγο ή ειναι η ιδέα μου???? Εγω τωρα θα μπω στο 4ο chapter το οποιο απο οσο βλεπω με τα expressions θα βγει σχετικα γρηγορα...
απλα στο 3ο πεσαμε πανω στην scanf και μας "ζορισε" καπως.

@migf1 ποια εταιρεια προτεινεις για domain? απαντησε αν ειναι στο θεμα μου εκει με τις εφαρμογες για αναπτυξη λογισμικου.
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 16:10

Ilias95 έγραψε:Να λοιπόν η άσκηση με two dimensional array:
Spoiler: show
Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // memset()
#include <stdlib.h> // srand(), rand()
#include <time.h> // time()

#define ALPHABETA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define NUM_ALPHABETA sizeof(ALPHABETA) / sizeof(ALPHABETA[0])

#define NUM_ROWS 10
#define NUM_COLUMNS 10

int main(void)
{
int row = 0, col = 0;
char table[NUM_ROWS][NUM_COLUMNS];

memset(table, '.', sizeof(table)); // init table with dots
table[0][0] = ALPHABETA[0];

srand((unsigned) time(NULL));

for (int i = 1; i < NUM_ALPHABETA - 1; i++) {
if ((table[row+1][col] != '.' || row == NUM_ROWS-1) && (table[row-1][col] != '.' || row == 0) && \
(table[row][col+1] != '.' || col == NUM_COLUMNS-1) && (table[row][col-1] != '.' || col == 0)) {
break; // terminate if there is no available position
}

while (1) {
int move = rand() % 4;

if (move == 0 && row > 0 && table[row-1][col] == '.') {
row--; // UP
break;
}
else if (move == 1 && col < NUM_COLUMNS-1 && table[row][col+1] == '.') {
col++; // RIGHT
break;
}
else if (move == 2 && row < NUM_ROWS-1 && table[row+1][col] == '.') {
row++; // DOWN
break;
}
else if (move == 3 && col > 0 && table[row][col-1] == '.') {
col--; // LEFT
break;
}
}
table[row][col] = ALPHABETA[i];
}

for (row = 0 ; row < NUM_ROWS; row++) {
for (col = 0; col < NUM_COLUMNS; col++)
printf("%c ", table[row][col]);
putchar('\n');
}

return 0;
}

ΥΓ. Με έσκασε μέχρι να το κάνω να δουλέψει. Δύο ώρες μου πήρε για να καταλάβω στο τέλος ότι είχα συντακτικό λάθος! :wtf:

Ωραίος Ηλία! :)

Ακόμα έχεις όμως νομίζω ένα προβληματάκι, επειδή στη συνθήκη if μέσα στο κεντρικό σου for-loop ξεκινάς...
Μορφοποιημένος Κώδικας: Επιλογή όλων
for (int i = 1; i < NUM_ALPHABETA - 1; i++) {
if ((table[row+1][col] != '.' || row == NUM_ROWS-1) && (table[row-1][col] != '.' || row == 0) && \ ...

ενώ κανονικά πρέπει να πάνε πρώτα οι έλεγχοι για την τρέχουσα γραμμή (row) ...
Μορφοποιημένος Κώδικας: Επιλογή όλων
for (int i = 1; i < NUM_ALPHABETA - 1; i++) {
if ( (row == NUM_ROWS-1 || table[row+1][col] != '.') && (row == 0 || table[row-1][col] != '.') && \ ...

διότι έτσι όπως το έχεις τώρα, αν βρίσκεσαι ήδη π.χ. στην row NUM_ROWS-1, τότε το ξεκίνημα της if με: table[ row+1 ][ col ] != '.' ... βγάζει το row+1 εκτός ορίων του table.

Άλλο τώρα, έγραψα τη δική σου λύση αφενός με ορολογίες από τη δική μου 2η λύση, κι αφετέρου με εκτεταμένη χρήση του προ-επεξεργαστή...

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // memset()
#include <stdlib.h> // srand(), rand()
#include <time.h> // time()

#define USED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // used squares contain letters
#define EMPTY '.' // empty squares contain a dot
#define NMOVES sizeof(USED) / sizeof(USED[0]) // max moves allowed

#define NROWS 10 // board height in rows
#define NCOLS 10 // board width in coloumns

// is current square blocked in all directions?
#define ISBLOCKED(table, row, col) \
( \
((row) == NROWS-1 || (table)[(row)+1][(col)] != EMPTY) \
&& ((row) == 0 || (table)[(row)-1][(col)] != EMPTY) \
&& ((col) == NCOLS-1 || (table)[(row)][(col)+1] != EMPTY) \
&& ((col) == 0 || (table)[(row)][(col)-1] != EMPTY) \
)

// is 1 row up available?
#define UP_ISAVAIL(table, row, col) \
( (row) > 0 && (table)[(row)-1][(col)] == EMPTY )

// is 1 col to the right available?
#define RT_ISAVAIL(table, row, col) \
( (col) < NCOLS-1 && (table)[(row)][(col)+1] == EMPTY )

// is 1 row down available?
#define DN_ISAVAIL(table, row, col) \
( (row) < NROWS-1 && (table)[(row)+1][(col)] == EMPTY )

// is 1 col to the left available?
#define LT_ISAVAIL(table, row, col) \
( (col) > 0 && (table)[(row)][(col)-1] == EMPTY )

// all possible directions for the next move
enum Dir { UP=0, RT, DN, LT };

int main( void )
{
int row = 0, col = 0;
char table[NROWS][NCOLS];

memset(table, EMPTY, sizeof(table)); // init table with EMPTY
table[0][0] = USED[0];

srand( (unsigned) time(NULL) );

for (int imove = 1; imove < (int)(NMOVES - 1); imove++)
{
if ( ISBLOCKED(table, row, col) )
break;

while (1)
{
int move = rand() % 4; // pick a random direction

if ( move == UP && UP_ISAVAIL(table, row, col) ) {
row--;
break;
}
if ( move == RT && RT_ISAVAIL(table, row, col) ) {
col++;
break;
}
if ( move == DN && DN_ISAVAIL(table, row, col) ) {
row++;
break;
}
if ( move == LT && LT_ISAVAIL(table, row, col) ) {
col--;
break;
}
}
table[row][col] = USED[imove];
}

/* print the table */
for (row = 0; row < NROWS; row++) {
for (col = 0; col < NCOLS; col++)
printf("%c ", table[row][col]);
putchar('\n');
}

return 0;
}

Ακολουθεί πιστά (πιστότατα) την λογική της λύσης σου (με μόνη διόρθωση την παραπάνω) και το έκανα απλά και μόνο για να σε βάλω στο πνεύμα του προ-επεξεργαστή, ο οποίος χρησιμοποιείται ευρέως στο C programming (χωρίς αυτό να σημαίνει πως δεν υπάρχουν αδυναμίες, κυρίως η έλλειψη type-checking σε όσα macros δέχονται ορίσματα).

Δεν ξέρω αν το γνωρίζετε, αλλά η C++ ξεκίνησε τη ζωή της γραμμένη αποκλειστικά στον προ-επεξεργαστή της C.

Το πλεονέκτημα με τον προ-επεξεργαστή, είναι πως αν χρησιμοποιηθεί σωστά και βάσει πλάνου (όχι δηλαδή απλά ορίζουμε στην τύχη σταθερές και macros ) τότε αφενός ανεβάζει κατακόρυφα το ευανάγνωστο του υπόλοιπου κώδικα (μειώνεται δραματικά η ανάγκη σχολίων στον υπόλοιπο κώδικα) και αφετέρου διευκολύνει αφάνταστα την παραμετροποίηση του προγράμματος. Δηλαδή σωστά οργανωμένες & ονοματισμένες σταθερές & macros(), συγκεντρωμένα σε ένα σημείο ή σε μεγάλα πρότζεκτ σε ένα header file, μας επιτρέπουν να αλλάζουμε αρχικές τιμές και όρια μέσα στα οποία δρα το πρόγραμμά μας.

Για παράδειγμα, στη προκειμένη περίπτωση, ορίζοντας με #define τον κενό χαρακτήρα '.' ως EMPTY, και χρησιμοποιώντας EMPTY στον υπόλοιπο κώδικα, μπορούμε κατόπιν με μια και μόνη κίνηση (στον ορισμό του EMPTY) να αλλάξουμε τον χαρακτήρα που μαρκάρει τα άδεια τετράγωνα, από τελεία ας πούμε σε παύλα '-'. Ομοίως το πλάτος ή/και ύψος του πίνακά μας, και ούτω καθ' εξής.

Στην ίδια φιλοσοφία, τα macros που δέχονται ορίσματα, μας επιτρέπουν να βελτιώνουμε/διορθώνουμε/εξετάζουμε τον κώδικά τους σε ένα μόνο μέρος, αντί να τον ψάχνουμε σε όλα τα σημεία που τον χρησιμοποιούμε (αυτό είναι κοινό χαρακτηριστικό με τη χρησιμότητα των συναρτήσεων, αλλά για τα macros δεν κάνει check τους τύπους των ορισμάτων ο compiler... επικίνδυνο πράγμα όταν είσαι αρχάριος, αλλά και γενικότερα).

Επίσης, η σωστή χρήση του προ-επεξεργαστή συνδυασμένη με ευέλικτο κώδικα, σου επιτρέπει να ελέγξεις την ευελιξία του κώδικά σου (την προσαρμοστικότητά του) σε διάφορες καταστάσεις, αλλάζοντας απλώς κάποιες τιμές στα #define σου. Για παράδειγμα, αν το NUM_ALPHABETA δεν ήταν ορισμένο έτσι ευέλικτα όπως το έχεις (σε συνάρτηση δηλαδή με το ALPHABETA) και ήταν ας πούμε ορισμένο hard-coded στην τιμή 26, τότε αν πρόσθετες αργότερα π.χ. και τα πεζά λατινικά γράμματα στη συνέχεια των κεφαλαίων μέσα στον ALPHABETA, το πρόγραμμά σου θα τα αγνοούσε. Ενώ τώρα αν τα προσθέσεις τα πεζά στο ALPHABETA θα προσαρμοστεί αυτόματα το πρόγραμμά σου... όχι μόνο θα τα συμπεριλαμβάνει στο output του αυτόματα, αλλά θα αυξήσει επίσης αυτόματα τον αριθμό επιτρεπόμενων κινήσεων.

Α btw, μια που το είπα αυτό, έχουμε και οι 2 μια σημαντική έλλειψη στους κώδικές μας... δεν εξετάζουμε ο αριθμός κινήσεων να ΜΗΝ ξεπερνάει το μέγιστο πλήθος του πίνακά μας (NROWS * NCOLS). Αν στο ALPHABET χρησιμοποιήσουμε πάνω από 100 γράμματα, τα προγράμματά μας κάποια στιγμή θα κρασάρουν! . Ένας εύκολος τρόπος να το δοκιμάσουμε είναι να αλλάξουμε τα NROWS και NCOLS σε 3 και 3 (από 10 και 10). Θα έχουμε έτσι 9 συνολικά τετράγωνα στον πίνακα, αλλά 26 επιτρεπόμενες κινήσεις... ΜΠΟΥΜ !!!!! :lol:

Και κάτι τελευταίο για τον κώδικα αυτόν, στο infinite-loop που κάνεις break μέσα σε κάθε if-else, τα else είναι περιττά... από τη στιγμή που κάνεις break δεν υπάρχει περίπτωση να συνεχίσει στα επόμενα ... οπότε δεν χρειάζονται τα else. Έτσι κι αλλιώς με ή χωρίς else, θα τα πιάσει με τη σειρά από πάνω μέχρι κάτω ;)

Έγραψα κι άλλη εκδοχή του κώδικα της λύσης σου, βελτιώνοντας τον προηγούμενο που περιέγραψα παραπάνω. ΟΙ βασικές βελτιώσεις είναι α) στα macros που διαχειρίζονται πιθανά μπλοκαρίσματα, κάνοντας τα και πιο ομοιογενή ως προς τις ονομασίες και τη λειτουργία τους, αλλά και χρησιμοποιώντας τα βασικά macros μέσα στο γενικότερο β) κατάργησα τα break σε εκείνα τα if-else του infinite loop, αντικαθιστώντας την λογική τους με μια boolean μεταβλητή: success.

Δεν υπάρχει κάποιο ουσιαστικό πλεονέκτημα ή μειονέκτημα συγκριτικά με τον προηγούμενο κώδικα, πέρα από τον πιο ευανάγνωστο (και πιο δομημένο) κώδικα. Ο πιο δυσανάγνωστος (και λιγότερο δομημένος) κώδικας είναι ελαφρώς πιο efficient (και σε μνήμη και σε ταχύτητα)... σε αμελητέες ποσότητες, αλλά υπαρκτές.

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // memset()
#include <stdlib.h> // srand(), rand()
#include <time.h> // time()
#include <stdbool.h> // _Bool, true, false

#define USED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // used squares contain letters
#define EMPTY '.' // empty squares contain a dot
#define NMOVES sizeof(USED) / sizeof(USED[0]) // max moves allowed

#define NROWS 10 // board height in rows
#define NCOLS 10 // board width in coloumns
enum Dir { UP=0, RT, DN, LT }; // next-move possible directions

// is current square blocked in all directions?
#define ISBLOCKED(table, row, col) \
( \
UP_ISBLOCKED( (table), (row), (col) ) \
&& RT_ISBLOCKED( (table), (row), (col) ) \
&& DN_ISBLOCKED( (table), (row), (col) ) \
&& LT_ISBLOCKED( (table), (row), (col) ) \
)

// is 1 row up blocked?
#define UP_ISBLOCKED(table, row, col) \
( (row) == 0 || (table)[(row)-1][(col)] != EMPTY )

// is next col blocked?
#define RT_ISBLOCKED(table, row, col) \
( (col) == NCOLS-1 || (table)[(row)][(col)+1] != EMPTY )

// is 1 row down blocked?
#define DN_ISBLOCKED(table, row, col) \
( (row) == NROWS-1 || (table)[(row)+1][(col)] != EMPTY )

// is previous col blocked?
#define LT_ISBLOCKED(table, row, col) \
( (col) == 0 || (table)[(row)][(col)-1] != EMPTY )

/*********************************************************//**
*
************************************************************/
int main(void)
{
int row = 0, col = 0;
char table[NROWS][NCOLS];

memset(table, EMPTY, sizeof(table)); // init table to EMPTY
table[0][0] = USED[0];

srand( (unsigned) time(NULL) );

for (int imove = 1; imove < (int)(NMOVES - 1); imove++)
{
_Bool success = false;

if ( ISBLOCKED(table, row, col) ) // blocked in all dirs
break;

while ( !success )
{
int move = rand() % 4; // pick a random direction
success = false;

if ( move == UP && !UP_ISBLOCKED(table, row, col) ) {
row--;
success = true;
}
else if ( move == RT && !RT_ISBLOCKED(table, row, col) ) {
col++;
success = true;
}
else if ( move == DN && !DN_ISBLOCKED(table, row, col) ) {
row++;
success = true;
}
else if ( move == LT && !LT_ISBLOCKED(table, row, col) ) {
col--;
success = true;
}
}

table[row][col] = USED[imove];
}

/* print the table */
for (row = 0; row < NROWS; row++) {
for (col = 0; col < NCOLS; col++)
printf("%c ", table[row][col]);
putchar('\n');
}

return 0;
}


ΥΓ. Έχω παρατηρήσει πως αποφεύγεις τη χρήση συναρτήσεων, γιατί; Οι συναρτήσεις είναι ο θεμελιώδεις λίθος των procedural γλωσσών.
Τελευταία επεξεργασία από migf1 και 05 Μαρ 2012, 16:24, έχει επεξεργασθεί 2 φορά/ες συνολικά
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 16:13

Star_Light έγραψε:Τρέχετε λιγο ή ειναι η ιδέα μου???? Εγω τωρα θα μπω στο 4ο chapter το οποιο απο οσο βλεπω με τα expressions θα βγει σχετικα γρηγορα...
απλα στο 3ο πεσαμε πανω στην scanf και μας "ζορισε" καπως.

Δεν νομίζω πως τρέχουμε. Αντίθετα, νομίζω πως μόνος σου επέλεξες να μείνεις πίσω, κολλημένος σε μια συνάρτηση που δεν χρησιμοποιεί κανείς.

έγραψε:@migf1 ποια εταιρεια προτεινεις για domain? απαντησε αν ειναι στο θεμα μου εκει με τις εφαρμογες για αναπτυξη λογισμικου.

Εγώ είμαι στην ITN Design/ΙΤΝ Networks (Κυπριακή) η οποία όμως είναι ακριβή.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό Ilias95 » 05 Μαρ 2012, 16:25

migf1 έγραψε:ΥΓ. Έχω παρατηρήσει πως αποφεύγεις τη χρήση συναρτήσεων, γιατί; Οι συναρτήσεις είναι ο θεμελιώδεις λίθος των procedural γλωσσών.

Γιατί έχω διαβάσει μέχρι το 8ο κεφάλαιο και οι συναρτήσεις είναι στο 9ο. :P
Παρ' όλα αυτά κατάλαβα πως δουλεύουν στους κώδικες που παρέθεσες.

Θα δω την τελευταία λύση σου και τα ποστ σου καθώς και το λινκ που παρέθεσε ο konnn και θα επανέλθω.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

Re: Τα πάντα για την C

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 16:38

migf1 έγραψε:
...
Α btw, μια που το είπα αυτό, έχουμε και οι 2 μια σημαντική έλλειψη στους κώδικές μας... δεν εξετάζουμε ο αριθμός κινήσεων να ΜΗΝ ξεπερνάει το μέγιστο πλήθος του πίνακά μας (NROWS * NCOLS). Αν στο ALPHABET χρησιμοποιήσουμε πάνω από 100 γράμματα, τα προγράμματά μας κάποια στιγμή θα κρασάρουν! . Ένας εύκολος τρόπος να το δοκιμάσουμε είναι να αλλάξουμε τα NROWS και NCOLS σε 3 και 3 (από 10 και 10). Θα έχουμε έτσι 9 συνολικά τετράγωνα στον πίνακα, αλλά 26 επιτρεπόμενες κινήσεις... ΜΠΟΥΜ !!!!! :lol:

Το διόρθωσα μόλις, στην 2η λύση μου, προσθέτοντας το macro...

Μορφοποιημένος Κώδικας: Επιλογή όλων
#define myMIN(x,y)		( (x) < (y) ? (x) : (y) )

και αρχικοποιώντας κατάλληλα την σταθερά NMOVES στην αρχή της main()...

Μορφοποιημένος Κώδικας: Επιλογή όλων
...
/* total # of moves allowed */
const int NMOVES = myMIN( NROWS*NCOLS, (int)(strlen(USED) - 1) );
...


Ilias95 έγραψε:
migf1 έγραψε:ΥΓ. Έχω παρατηρήσει πως αποφεύγεις τη χρήση συναρτήσεων, γιατί; Οι συναρτήσεις είναι ο θεμελιώδεις λίθος των procedural γλωσσών.

Γιατί έχω διαβάσει μέχρι το 8ο κεφάλαιο και οι συναρτήσεις είναι στο 9ο. :P
Παρ' όλα αυτά κατάλαβα πως δουλεύουν στους κώδικες που παρέθεσες.

Α, λέω κι εγώ :lol: Ωραίος!

Ilias95 έγραψε:
Θα δω την τελευταία λύση σου και τα ποστ σου καθώς και το λινκ που παρέθεσε ο konnn και θα επανέλθω.

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

ΠροηγούμενηΕπόμενο

Επιστροφή στο Ανάπτυξη Λογισμικού / Αλγόριθμοι