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

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

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

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

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

Εν τω μεταξύ, κοιτάζοντας στη σελίδα 181 που είπες για να δω τι ζητάει η άσκηση 17, πήρε το μάτι μου την άσκηση 16 την οποία την έχω ήδη υλοποιημένη, στη βιβλιοθήκη: libs (συνάρτηση: int s_isanagram( const char *s1, const char *s2).

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

Spoiler: show
Μορφοποιημένος Κώδικας: Επιλογή όλων
/* -------------------------------------------------------------------------------
* int s_isanagram( const char *s, const char *t )
*
* -------------------------------------------------------------------------------
*/
int s_isanagram( const char *s, const char *t )
{
int val = 0, hgram[ 256 ] = {0}; /* histogram for the ASCII table*/
register char *ps = (char *) s; /* temp char-pointer to s */
register char *pt = (char *) t; /* temp char-pointer to t */

/* sanity checks */
if ( !s || !t ) { errno = EFAULT; return 0; }
if ( !*s || !*t ) { errno = EINVAL; return 0; }

memset( hgram, 0, 256 * sizeof(int) ); /* clear histogram */
for (; *s || *t; ) { /* update histogram */
if ( *s ) /* ... */
hgram[(int)*s++]++; /* ... +1 for every char in s */
if ( *t ) /* ... */
hgram[(int)*t++]--; /* ... -1 for every char in t */
}
/* check in histogram for */
while( *ps && *pt++ && !(val=hgram[(int)*ps++]) )/* 1st non-zero mapped val */
; /* of all chars in s */
return val || *pt ? 0 : 1; /* val || *pt != 0 ? FALSE:TRUE */

}

ΥΓ. Ο κώδικας της βιβλιοθήκης libs είναι ελεύθερος: http://x-karagiannis.gr/prog/libs/conte ... wnload.php
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

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

Την έχω υλοποιήσει και εγώ ήδη: https://github.com/Ilias95/C-Exercises/ ... 08/pp_16.c
Όταν μάθω για pointers θα επιστρέψω. :)
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

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

Ilias95 έγραψε:Την έχω υλοποιήσει και εγώ ήδη: https://github.com/Ilias95/C-Exercises/ ... 08/pp_16.c
Όταν μάθω για pointers θα επιστρέψω. :)

Δεν λειτουργεί σωστά.

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

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

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

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

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

Δημοσίευσηαπό Ilias95 » 06 Μαρ 2012, 00:06

Υπάρχει στην C κάποιος καλύτερος τρόπος να ελέγξουμε αν όλα τα στοιχεία μιας array επαληθεύουν κάποια συνθήκη από; :

Μορφοποιημένος Κώδικας: Επιλογή όλων
flag = 0;
for (i = 0; i < len; i++) {
if (array[i] == 5)
flag = 1;
break;
}

if (flag == 0)
...
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό Ilias95 » 06 Μαρ 2012, 00:56

migf1 έγραψε:
Ilias95 έγραψε:Την έχω υλοποιήσει και εγώ ήδη: https://github.com/Ilias95/C-Exercises/ ... 08/pp_16.c
Όταν μάθω για pointers θα επιστρέψω. :)

Δεν λειτουργεί σωστά.

Π.χ. τα "aa" και "aaa" μου τα δίνει ως αναγραμματισμό (ενώ δεν είναι). Επίσης, αν η 1η λέξη είναι μεγαλύτερου μήκους από την 2η, κρασάρει το πρόγραμμα.

Αλλάζοντας μόνο την σύγκριση στο τελευταίο for πρέπει να δουλεύει σωστά:
Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <ctype.h> // isalpha(), tolower()

#define NUM_ARR sizeof(string) / sizeof(string[0])

int main(void)
{
int i, string[26] = {};
char ch;

printf("Enter first word: ");
while ((ch = tolower(getchar())) != '\n') {
if isalpha(ch) {
for (i = 0; i < (int) NUM_ARR; i++) {
if (ch - 'a' == i)
string[i]++;
}
}
}

printf("Enter second word: ");
while ((ch = tolower(getchar())) != '\n') {
if isalpha(ch) {
for (i = 0; i < (int) NUM_ARR; i++) {
if (ch - 'a' == i)
string[i]--;
}
}
}

for (i = 0; i < (int) NUM_ARR; i++) {
if (string[i] != 0) {
printf("The two words are not anagrams");
return 0;
}
}

printf("The two words are anagrams");

return 0;
}

(Δηλαδή αλλάζοντας μόνο το "if (string[i] > 0)" σε " if (string[i] != 0)".)

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

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

Δημοσίευσηαπό migf1 » 06 Μαρ 2012, 14:08

Ilias95 έγραψε:
...
Πάντως και με τον προηγούμενο κώδικα δοκίμασα πολλές περιπτώσεις με την 1η λέξη μεγαλύτερη απ' την δεύτερη και δεν κράσαρε.

Έχεις δίκιο Ηλία! Στα Windows κλείνει αμέσως το παράθυρο της κονσόλας μόλις τελειώσει το πρόγραμμα ή αν κρασάρει πριν τελειώσει. Ενώ λοιπόν είχα προσθέσει ένα system("pause") πριν από το τελευταίο return, είχα ξεχάσει να το βάλω πριν από το προτελευταίο σου return. Οπότε μου έκλεινε το παράθυρο και νόμιζα πως είχε κρασάρει το πρόγραμμα.

Λοιπόν, κοίταξα σήμερα τον κώδικά σου. Το for-loop που φωλιάζεις μέσα στο loop ανάγνωσης της κάθε λέξης, επιβαρύνει αχρείαστα το execution speed του προγράμματος (συν ότι κάνει τη διαίρεση του NUM_ARR σε κάθε επιτυχημένο γράμμα). Δεν το χρειάζεσαι καθόλου το for-loop, μπορείς να κάνεις απευθείας indexing το αναγνωσμένο γράμμα μέσα στον πίνακα:

Μορφοποιημένος Κώδικας: Επιλογή όλων
...
string[ ch - 'a' ]++;
...
string[ ch - 'a' ]--;
...

Παραθέτω μια βελτιωμένη εκδοχή του κώδικά σου που βελτιώνει το παραπάνω, καθώς επίσης μετράει και τυπώνει στο αποτέλεσμα πόσους μη-έγκυρους χαρακτήρες έχει απορρίψει συνολικά κι από τις 2 λέξεις. Επίσης, αναγνωρίζει και απορρίπτει κενές λέξεις (π.χ. όσες περιέχουν μονάχα μη-έγκυρους χαρακτήρες ή σε όσες ο χρήστης πατήσεις σκέτο ENTER)...

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <ctype.h> // isalpha(), tolower()
#include <stdbool.h> // bool, true, false

#define ABLEN 26 // alphabet length (lower latin)
#define CHR2ABi(c) ( tolower((c)) - 'a' ) // char to lower alpahabet index

int main( void )
{
int c, hgram[ ABLEN ] = {0}; // hgram: letters' histogram
int noalpha = 0; // non-letter chars counter
bool arenot = false;
bool w1empty = true, w2empty = true; // was either word given empty?

printf("Enter first word: ");
while ( (c = getchar()) != '\n' ) {
if ( isalpha( c ) ) {
hgram[ CHR2ABi(c) ]++; // increase char's histo-sum by 1
w1empty = false;
}
else noalpha++;
}

printf("Enter second word: ");
while ( (c = getchar()) != '\n') {
if ( isalpha(c) ) {
hgram[ CHR2ABi(c) ]--; // decrease char's histo-sum by 1
w2empty = false;
}
else noalpha++;
}

if ( w1empty || w2empty )
goto empty_exit;

for (int i=0; i < ABLEN; i++) {
if ( hgram[i] != 0 ) {
arenot = true; // are not anagrams
break;
}
}

if ( noalpha != 0 ) // 1 or both words had non-letters
printf( "(%d non-letter chars ignored from both words)\n", noalpha );

printf("The words are %sanagrams\n", arenot ? "not " : "\0");

return 0;

empty_exit:
puts("*** one or both empty words, no result!");
return 0;
}

ΥΓ. Γίνομαι ιδιαίτερα αναλυτικός, ενδεχομένως και σπαστικός, όχι για να το παίξω έξυπνος αλλά για να σε βάλω στο πνεύμα του C programming, όπου η προσοχή στη λεπτομέρεια κάνει μεγάλη διαφορά. Είναι από τα χαρακτηριστικά που ξεχωρίζουν τους καλούς προγραμματιστές από τους λιγότερους καλούς, σε όλες τις γλώσσες (απλά στη C τα κέρδη/ζημιές είναι μεγαλύτερα, λόγω της low-level αμεσότητάς της).

EDIT:
Έκανα μια μικρο-αλλαγή στον κώδικα, πέρασα το tolower() μέσα στον ορισμό του macro: CHR2ABi()
Τελευταία επεξεργασία από migf1 και 06 Μαρ 2012, 14:18, έχει επεξεργασθεί 2 φορά/ες συνολικά
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

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

Ilias95 έγραψε:Υπάρχει στην C κάποιος καλύτερος τρόπος να ελέγξουμε αν όλα τα στοιχεία μιας array επαληθεύουν κάποια συνθήκη από; :

Μορφοποιημένος Κώδικας: Επιλογή όλων
flag = 0;
for (i = 0; i < len; i++) {
if (array[i] == 5)
flag = 1;
break;
}

if (flag == 0)
...

Δεν γνωρίζω άλλον τρόπο εγώ (δεν πρέπει να υπάρχει κιόλας) άλλα έχεις ξεχάσει 2 άγκιστρα (στο if)...

Μορφοποιημένος Κώδικας: Επιλογή όλων
flag = 0;
for (i = 0; i < len; i++) {
if (array[i] == 5) {
flag = 1;
break;
}
}
...
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 06 Μαρ 2012, 14:24

Με την ευκαιρία του κώδικα με το flag και το break, θα έχεις παρατηρήσει πως στους κώδικες που ποστάρω, στις ισότητες βάζω πρώτα τη σταθερά και μετά την μεταβλητή.

Δηλαδή αντί για...
Μορφοποιημένος Κώδικας: Επιλογή όλων
if (array[i] == 5) ...

έτσι...
Μορφοποιημένος Κώδικας: Επιλογή όλων
if (5 == array[i]) ...

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

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

Δημοσίευσηαπό Ilias95 » 06 Μαρ 2012, 14:41

migf1 έγραψε:Το for-loop που φωλιάζεις μέσα στο loop ανάγνωσης της κάθε λέξης, επιβαρύνει αχρείαστα το execution speed του προγράμματος (συν ότι κάνει τη διαίρεση του NUM_ARR σε κάθε επιτυχημένο γράμμα). Δεν το χρειάζεσαι καθόλου το for-loop, μπορείς να κάνεις απευθείας indexing το αναγνωσμένο γράμμα μέσα στον πίνακα:

Έχεις δίκιο. Θα διορθωθεί και αυτό σύμφωνα με τη λογική του κώδικα που ποσταρες.

migf1 έγραψε:Με την ευκαιρία του κώδικα με το flag και το break, θα έχεις παρατηρήσει πως στους κώδικες που ποστάρω, στις ισότητες βάζω πρώτα τη σταθερά και μετά την μεταβλητή.

Ναι το παρατήρησα και το διάβασα και στο βιβλίο ότι είναι συνήθεια πολλών προγραμματιστών.
Βέβαια να πω την αλήθεια δεν μου αρέσει το οπτικό αποτέλεσμα, αλλά μάλλον το τίμημα θα είναι μεγαλύτερο αν δεν το υιοθετήσω.
(btw, ο interpreter της python δίνει syntax error αν δοκιμάσεις να κάνεις εκχώρηση όταν γίνεται έλεγχος για συνθήκη)

migf1 έγραψε:ΥΓ. Γίνομαι ιδιαίτερα αναλυτικός, ενδεχομένως και σπαστικός, όχι για να το παίξω έξυπνος αλλά για να σε βάλω στο πνεύμα του C programming, όπου η προσοχή στη λεπτομέρεια κάνει μεγάλη διαφορά. Είναι από τα χαρακτηριστικά που ξεχωρίζουν τους καλούς προγραμματιστές από τους λιγότερους καλούς, σε όλες τις γλώσσες (απλά στη C τα κέρδη/ζημιές είναι μεγαλύτερα, λόγω της low-level αμεσότητάς της).

Σπαστικός; Γιατί σπαστικός; Ίσα, ίσα.
Φυσικά και χρειάζεται προσοχή στις λεπτομέρειες (αν και αυτά δεν είναι ακριβώς λεπτομέρειες, αλλά πιο χτυπητά "λάθη").
Και σε ευχαριστώ κιόλας για τον χρόνο και κόπο σου, το εκτιμώ.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

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