fork download
  1. /* ============================================================================
  2.  * Από: migf1
  3.  *
  4.  * Γράψτε ένα πρόγραμμα που θα διαβάζει από το πληκτρολόγιο τυχαίο πλήθος λέξεων (μια
  5.  * λέξη ανά γραμμή) και σε τυχαία σειρά μέχρι να διαβάσει τη λέξη stop. Για ευκολία
  6.  * θεωρήστε δεδομένο πως οι λέξεις αποτελούνται από λατινικούς χαρακτήρες και πως η
  7.  * κάθε γραμμή περιέχει μια μόνο λέξη.
  8.  *
  9.  * Κάθε λέξη (συμπεριλαμβανομένης της stop) θα μετατρέπεται πρώτα σε πεζά γράμματα και
  10.  * κατόπιν ανάλογα με το γράμμα από το οποίο αρχίζει θα καταχωρείται στην λίστα που
  11.  * αντιστοιχεί στο γράμμα αυτό, σε αντίστροφη χρονολογική σειρά (δηλαδή οι πιο πρόσφατα
  12.  * πληκτρολογημένες λέξεις θα εμφανίζονται πρώτες στη λίστα τους).
  13.  *
  14.  * Δηλαδή όσες λέξεις ξεκινάνε με το λατινικό γράμμα a θα καταχωρούνται στη λίστα του
  15.  * a, όσες ξεκινάνε από b θα καταχωρούνται στη λίστα του b, και ούτω καθ' εξής. Αν μια
  16.  * λέξη αρχίζει από χαρακτήρα με ASCII code μικρότερο του 'a' θα μπαίνει στη λίστα του
  17.  * a, ενώ αν αρχίζει από χαρακτήρα με ASCII code μεγαλύτερο του 'z' θα μπαίνει στη
  18.  * λίστα του z.
  19.  *
  20.  * Πριν τερματίσει το πρόγραμμα θα τυπώνει τα περιεχόμενα (λέξεις) μόνο όσων λιστών δεν
  21.  * είναι άδειες, καθώς και το σε ποιο γράμμα αντιστοιχούν και πόσες λέξεις περιέχουν.
  22.  * Στο τέλος θα τυπώνει το συνολικό πλήθος των λέξεων που περιέχονται σε όλες τις λίστες.
  23.  *
  24.  * Περισσότερα: http://x...content-available-to-author-only...s.gr/prg/c-notes/linked-lists/intro/
  25.  * ============================================================================
  26.  */
  27. #include <stdio.h>
  28. #include <stdlib.h> // για calloc(), free(), exit()
  29. #include <string.h> // για strncmp()
  30. #include <ctype.h> // για tolower()
  31.  
  32. #define MAXINBUF 255+1 // μέγιστο μήκος γραμμής εισόδου + '\0'
  33. #define listempty(head) ( (head) == NULL ) // συνθήκη άδειας λίστας
  34.  
  35. typedef enum { FALSE=0, TRUE } Bool; // ο δικός μας τύπος boolean
  36.  
  37. typedef struct node { // δομή για κάθε κόμβο της λίστας
  38. char data[ MAXINBUF ]; // c-string μιας λέξης
  39. struct node *next; // δείκτης στον επόμενο κόμβο
  40. } Node;
  41.  
  42. typedef struct { // η δομή της λίστας
  43. Node *head, *tail; // δεικτες στην αρχή και στο τέλος
  44. int len; // μήκος λίστας
  45. } List;
  46.  
  47. // -----------------------------------------------------------------------------------
  48. // ΣΥΝΑΡΤΗΣΗ: s_getflushed
  49. // βελτιωμένη παραλλαγή της fgets για την κύρια είσοδο (σβήνει το '\n' + fflush)
  50. //
  51. // Διαβάζει από την κύρια είσοδο έως len-1 χαρακτήρες ή μέχρι να πατηθεί ENTER,
  52. // τους καταχωρεί στο s και το επιστρέφει με μηδενισμένο τον τελικό χαρακτήρα.
  53. // Αν πληκτρολογήθηκαν len-1 χαρακτήρες πριν πατηθεί το ENTER, τότε οι περιττοί
  54. // χαρακτήρες αφαιρούνται από το buffer της εισόδου (stdin).
  55. //
  56. char *s_getflushed(char *s, size_t len)
  57. {
  58. char *cp;
  59. for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
  60. ;
  61.  
  62. if ( *cp != '\n') { // len reached withoutn '\n'
  63. *cp = '\0'; // null terminate s and
  64. while (getc(stdin) != '\n') // flush remaining chars
  65. ;
  66. }
  67. else // '\n' found
  68. *cp = '\0'; // null-terminate
  69.  
  70. return s;
  71. }
  72.  
  73. // ------------------------------------------------------------------------------
  74. // ΣΥΝΑΡΤΗΣΗ: s_tolower
  75. // μετατρέπει όλους τους χαρακτήρες του c-string s σε πεζούς και το επιστρέφει
  76. //
  77. char *s_tolower(char *s)
  78. {
  79. char *ret;
  80.  
  81. for ( ret=s; (*s=tolower(*s)); s++ );
  82. return ret;
  83. }
  84.  
  85. // ------------------------------------------------------------------------------
  86. // ΣΥΝΑΡΤΗΣΗ: s_ncopy
  87. // παραλλαγή της strncpy με εγγυημένο μηδενισμό του τελικού χαρακτήρα
  88. // (αντιγράφει έως n-1 χαρακτήρες από το c-string dst στο src, και το επιστρέφει)
  89. //
  90. char *s_ncopy( char *dst, const char *src, size_t n )
  91. {
  92. char *save = dst;
  93.  
  94. while ( (dst-save) < n-1 && (*dst=*src) != '\0' )
  95. dst++, src++;
  96.  
  97. if ( *dst )
  98. *dst = 0;
  99.  
  100. return save;
  101. }
  102.  
  103. // ------------------------------------------------------------------------------
  104. // ΣΥΝΑΡΤΗΣΗ: list_prepend
  105. // δημιουργεί νέο κόμβο για τη λέξη data, τον εισαγάγει στην αρχή της list και
  106. // ενημερώνει το μήκος της (επιστρέφει FALSE σε περίπτωση σφάλματος, αλλιώς TRUE)
  107. //
  108. Bool list_prepend( List *list, char *data )
  109. {
  110. Node *new = calloc(1, sizeof(Node) ); // δημιουργία νέου κόμβου
  111. if ( !new ) // αποτυχία δέσμευσης μνήμης
  112. return FALSE; // επιστροφή σφαλματος
  113.  
  114. s_ncopy(new->data, data, MAXINBUF); // αρχικοποίηση νέου κόμβου
  115.  
  116. // εισαγωγή νέου κόμβου στην αρχή της λίστας
  117.  
  118. if ( list->head == NULL ) { // σε κενή λίστα
  119. new->next = NULL; // ...
  120. list->head = list->tail = new; // ...
  121. }
  122. else { // σε μη κενή λίστα
  123. new->next = list->head; // ...
  124. list->head = new; // ...
  125. }
  126. (list->len)++; // ενημέρωση μήκους λίστας
  127.  
  128. return TRUE; // επιστροφή επιτυχίας
  129. }
  130.  
  131. // ------------------------------------------------------------------------------
  132. // ΣΥΝΑΡΤΗΣΗ: list_print
  133. // τυπώνει τα περιεχόμενα της list
  134. //
  135. void list_print( List list )
  136. {
  137. while ( list.head ) {
  138. printf("%s ", list.head->data );
  139. list.head = list.head->next;
  140. }
  141. putchar('\n'); // αλλαγή γραμμής
  142.  
  143. return;
  144. }
  145.  
  146. // ------------------------------------------------------------------------------
  147. // ΣΥΝΑΡΤΗΣΗ: list_destroy
  148. // αποδεσμεύει όση μνήμη είχε δεσμευτεί για την list
  149. //
  150. void list_destroy( List *list )
  151. {
  152. if ( list->head == NULL )
  153. return;
  154.  
  155. Node *dummy = NULL;
  156. while ( list->head ) {
  157. dummy = list->head->next;
  158. free( list->head );
  159. list->head = dummy;
  160. }
  161.  
  162. return;
  163. }
  164.  
  165. // ------------------------------------------------------------------------------
  166. // ΣΥΝΑΡΤΗΣΗ: hashtab_init
  167. // αρχικοποιεί τον διαχωριστικό πίνακα hashtab με μηδενικές τιμές
  168. //
  169. void hashtab_init( List hashtab[] )
  170. {
  171. register int i;
  172. for (i=0; i < 26; i++) {
  173. hashtab[ i ].head = NULL;
  174. hashtab[ i ].tail = NULL;
  175. hashtab[ i ].len = 0;
  176. }
  177.  
  178. return;
  179. }
  180.  
  181. // ------------------------------------------------------------------------------
  182. // ΣΥΝΑΡΤΗΣΗ: hashtab_destroy
  183. // αποδεσμεύει τη μνήμη όλων τις λιστών του διαχωριστικού πίνακα hashtab
  184. //
  185. void hashtab_destroy( List hashtab[] )
  186. {
  187. register int i;
  188. for (i=0; i < 26; i++)
  189. list_destroy( &hashtab[ i ] );
  190.  
  191. return;
  192. }
  193.  
  194. // ------------------------------------------------------------------------------
  195. int main( void )
  196. {
  197. List hashtab[ 26 ]; // διαχωριστικός πίνακας 26 λιστών
  198. char inbuf[ MAXINBUF ] = ""; // γραμμή κύριας εισοόδου
  199. int i, total; // total = συνολικό πλήθος λέξεων
  200.  
  201. hashtab_init( hashtab ); // αρχικοποίηση διαχωριστικού πίνακα
  202.  
  203. /*
  204. * είσοδος, επεξεργασία & καταχώρηση λέξεων στις λίστες του διαχωριστικού πίνακα
  205. */
  206.  
  207. puts("Πληκτρολογήστε μια λέξη ανά γραμμή ή \"stop\" για τερματισμό (λατινικά γράμματα)\n");
  208. do {
  209. printf("> ");
  210. s_getflushed( inbuf, MAXINBUF ); // ανάγνωση γραμμής από stdin
  211. if ( !*inbuf ) // ... κενή γραμμή
  212. continue; // ...
  213.  
  214. i = (int)( *s_tolower(inbuf) - 'a' ); // μετατροπή σε πεζά γράμματα
  215.  
  216. if ( i < 0 ) { // αντιμετώπιση κάτω υπερχείλισης
  217. puts("\tοι λέξεις πρέπει να αρχίζουν από λατινικό γράμμα");
  218. puts("\t( η λεξη σας καταχωρήθηκε στη λίστα του 'a' )");
  219. i = 0;
  220. }
  221. else if ( i > 'z' - 'a') { // αντιμετώπιση άνω υπερχείλισης
  222. puts("\tοι λέξεις πρέπει να αρχίζουν από λατινικό γράμμα");
  223. puts("\t( η λεξη σας καταχωρήθηκε στη λίστα του 'z' )");
  224. i = 'z' - 'a';
  225. }
  226. // εισαγωγή στην κατάλληλη λίστα
  227. if ( !list_prepend( &hashtab[ i ], inbuf ) ) {
  228. puts("*** Σφάλμα: Ανεπαρκής μνήμη, τερματισμός προγράμματος...");
  229. hashtab_destroy( hashtab );
  230. }
  231. } while ( !*inbuf || strncmp(inbuf, "stop", MAXINBUF ) );
  232.  
  233. /*
  234. * τύπωμα των λέξεων και του πλήθους τους ανά λίστα και συνολικά
  235. */
  236.  
  237. putchar('\n');
  238.  
  239. total = 0;
  240. for (i=0; i < 26; i++)
  241. {
  242. if ( !listempty( hashtab[i].head ) ) { // γεμάτη λίστα
  243. printf("%c (%d λέξεις): ", i+'a', hashtab[i].len);
  244. list_print( hashtab[ i ] );
  245. total += hashtab[i].len;
  246. }
  247. }
  248. printf("\nΔώσατε %d λέξεις συνολικά (συμπεριλαμβανομένης της \"stop\")\n",total);
  249.  
  250. /*
  251. * εκκαθάριση και τερματισμός προγράμματος
  252. */
  253.  
  254. hashtab_destroy( hashtab ); // αποδέσμευση μνήμης
  255.  
  256. exit(EXIT_SUCCESS );
  257. }
  258.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty