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

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

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

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

Δημοσίευσηαπό migf1 » 28 Ιούλ 2011, 14:55

Άψογος φίλε Σταματίου ! :) :) :)

Μια μικρή προσθήκη χρειάζεται, στην switch να βάλεις κι ένα deafult στο τέλος για περιπτώσεις που το σύμβολο πράξης είναι κάτι άσχετο από τα 4 που θέλουμε. Δηλαδή...

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

...
...
switch (i3) {
case '*':
printf("%d * %d = %d\n",i1,i2,i1*i2);
break;
...
...
default:
puts("den yparxei tetoia prajh");
break;
}

(το default πρέπει να το βάζουμε πάντα πριν κλείσουμε ένα switch, έστω και με σκέτο break).

Πολύ χάρηκα φίλε Σταματίου, γιατί με είχες φοβήσει την 1η φορά :) Άψογος!

Δίνω και τη δική μου υλοποίηση (χρησιμοποιώ 2 συναρτήσεις εγώ, αλλά δεν έχει σημασία... η ουσία ήταν η χρήση της s_get και η μετατροπή του inbuf στις μεταβλητές που χρειαζόμαστε)
Spoiler: show
Κώδικας: Επιλογή όλων

/* ******************************
* Άσκηση #2
* ******************************/

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

#define BUFFER_SIZE (255+1)

// ------------------------------------------------------------------------------
char *s_get(char *s, size_t len)
{
char *cp;
for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
; // for-loop with empty body
*cp = '\0'; // null-terminate last character

return s;
}

// ------------------------------------------------------------------------------
void get_char(char *c)
{
char buffer[BUFFER_SIZE] = "";

s_get( buffer, BUFFER_SIZE );
*c = buffer[0];

return;
}

// ------------------------------------------------------------------------------
void get_float(float *x)
{
char buffer[BUFFER_SIZE] = "";

s_get( buffer, BUFFER_SIZE );
*x = atof( buffer );

return;
}

// ------------------------------------------------------------------------------
int main( void )
{
char prajh;
float x, y;

printf("Dwste 1o arithmo: ");
get_float( &x );

printf("Dwste 2o arithmo: ");
get_float( &y );

printf("Dwste symbolo prajhs: ");
get_char( &prajh );

switch ( prajh )
{
case '+':
printf("%f %c %f = %f\n", x, prajh, y, x+y);
break;
case '-':
printf("%f %c %f = %f\n", x, prajh, y, x-y);
break;
case '*':
printf("%f %c %f = %f\n", x, prajh, y, x*y);
break;
case '/':
printf("%f %c %f = %f\n", x, prajh, y, x/y);
break;
default:
puts("\tden yparxei tetoia prajh");
break;
}

return 0;
}

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

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

Δημοσίευσηαπό stamatiou » 28 Ιούλ 2011, 14:59

migf1 έγραψε:Άψογος φίλε Σταματίου ! :) :) :)

Μια μικρή προσθήκη χρειάζεται, στην switch να βάλεις κι ένα deafult στο τέλος για περιπτώσεις που το σύμβολο πράξης είναι κάτι άσχετο από τα 4 που θέλουμε. Δηλαδή...

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

...
...
switch (i3) {
case '*':
printf("%d * %d = %d\n",i1,i2,i1*i2);
break;
...
...
default:
puts("den yparxei tetoia prajh");
break;
}

(το default πρέπει να το βάζουμε πάντα πριν κλείσουμε ένα switch, έστω και με σκέτο break).

Πολύ χάρηκα φίλε Σταματίου, γιατί με είχες φοβήσει την 1η φορά :) Άψογος!

Δίνω και τη δική μου υλοποίηση (χρησιμοποιώ 2 συναρτήσεις εγώ, αλλά δεν έχει σημασία... η ουσία ήταν η χρήση της s_get και η μετατροπή του inbuf στις μεταβλητές που χρειαζόμαστε)
Spoiler: show
Κώδικας: Επιλογή όλων

/* ******************************
* Άσκηση #2
* ******************************/

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

#define BUFFER_SIZE (255+1)

// ------------------------------------------------------------------------------
char *s_get(char *s, size_t len)
{
char *cp;
for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
; // for-loop with empty body
*cp = '\0'; // null-terminate last character

return s;
}

// ------------------------------------------------------------------------------
void get_char(char *c)
{
char buffer[BUFFER_SIZE] = "";

s_get( buffer, BUFFER_SIZE );
*c = buffer[0];

return;
}

// ------------------------------------------------------------------------------
void get_float(float *x)
{
char buffer[BUFFER_SIZE] = "";

s_get( buffer, BUFFER_SIZE );
*x = atof( buffer );

return;
}

// ------------------------------------------------------------------------------
int main( void )
{
char prajh;
float x, y;

printf("Dwste 1o arithmo: ");
get_float( &x );

printf("Dwste 2o arithmo: ");
get_float( &y );

printf("Dwste symbolo prajhs: ");
get_char( &prajh );

switch ( prajh )
{
case '+':
printf("%f %c %f = %f\n", x, prajh, y, x+y);
break;
case '-':
printf("%f %c %f = %f\n", x, prajh, y, x-y);
break;
case '*':
printf("%f %c %f = %f\n", x, prajh, y, x*y);
break;
case '/':
printf("%f %c %f = %f\n", x, prajh, y, x/y);
break;
default:
puts("\tden yparxei tetoia prajh");
break;
}

return 0;
}

Αν δεν έχει άλλο παιδί κάποια απορία, δώστε μου 5 λεπτά να γράψω τον 3ο τρόπο υλοποίησης της προηγούμενης άσκησης, όπου εκεί πλέον έχουμε εμπεδώσει τη χρήση της s_get και απλά θέλω να δείξω έναν διαφορετικό τρόπο χρήσης συναρτήσεων.

Ευχαριστώ πολύ migf1, με ανακούφησες γιατί δεν είχα και πολλές επιτυχίες μέχρι τώρα... :D
Αυτό με το default το σκέφτηκα και εγώ αλλά ήταν αφότου κάνω το ποστ και έτσι είπα να μην το κάνω edit....
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

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

Δημοσίευσηαπό Star_Light » 28 Ιούλ 2011, 15:00

Δηλαδη για να καταλαβω ας πουμε... υπαρχει προβλημα με την getchar εκτος και αν βαλεις σε περιβαλλον windows πριν απο αυτην ενα fflush(stdin) ?
Και στον Γκιουρδα μεσα δεν αναφερει τιποτα για αυτο.... ολοκληρο βιβλιο!

Π.Σ Ρε παιδια.... χυμαροι ειστε!!!!!!!! Δεν το αφηνουμε μια μερουλα μεχρι αυριο να τα ξαναδουμε παλι ολα μαζι μηπως παιζει καμια απορια... με την ησυχια μας????? :D
Γνώσεις ⇛ 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/C++

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

Star_Light έγραψε:Δηλαδη για να καταλαβω ας πουμε... υπαρχει προβλημα με την getchar εκτος και αν βαλεις σε περιβαλλον windows πριν απο αυτην ενα fflush(stdin) ?
Και στον Γκιουρδα μεσα δεν αναφερει τιποτα για αυτο.... ολοκληρο βιβλιο!

Και όχι μόνο με την getchar() (getc() και fgetc() ) αλλά και με την scanf(). Το πρόβλημα παρουσιάζεται όταν ο χρήστης (είτε κατά λάθος είτε επίτηδες) πληκτρολογήσει στην είσοδο περισσότερα πράγματα από ότι περιμένουμε να διαβάσουμε. Τα έξτρα αυτά πράματα παραμένουν στο buffer της εισόδου με αποτέλεσμα το επόμενο scanf (getchar, κλπ) του προγράμματός μας αντί να διαβάσει φρέσκο πράμα από τον χρήστη, διαβάζει αυτόματα τα έξτρα πράματα από την προηγούμενη είσοδο. Το fflush(stdin) σε Windows αυτό που κάνει είναι να καθαρίζει τελείως το buffer, οπότε καλώντας το πριν από κάθε scanf (getchar, κλπ) εξασφαλίζουμε πως θα διαβάσουμε φρέσκο πράμα από τον χρήστη. Μόνο που η fflush(stdin) δεν λειτουργεί σε περιβάλλον gcc/unix/linux.

Πέρα όμως από το παραπάνω, αυτό που έχει μεγαλύτερη σημασία είναι ότι μάθαμε πως να μετατρέπουμε strings σε αριθμούς, κάτι που χρησιμοποιείται κατά κόρον σε όλα τα GUI, γιατί εκεί δεν διαβάζεις με τις στάνταρ συναρτήσεις εισόδου της C. Τα GUI έχουν δική τους συνάρτηση διαβάσματος και κατά συντριπτική πλειοψηφία διαβάζουν τα πάντα ως strings (συνήθως μέσα από πεδία κειμένου σε γραφικές φόρμες) οπότε πρέπει να ξέρουμε πως να τα μετατρέπουμε σε αριθμούς εμείς όταν χρειαστεί.

Και τώρα που το σκέφτομαι, τον 3ο τρόπο λύσης της προηγούμενης άσκησης δεν θα τον γράψω όπως είχα σκεφτεί, δηλαδή με στόχο να δείξω διαφορετική χρήση των συναρτήσεων get_, αλλά θα τον κάνω με χρήση της συνάρτησης sscanf() που δουλεύει σαν την scanf() αλλά αντί να διαβάζει από την κύρια είσοδο, διαβάζει από ένα string (στη δική μας περίπτωση θα είναι το: inbuf που θα το έχουμε διαβάσει πρώτα κλασικά με την s_get εδώ πέρα, γιατί είμαστε σε κονσόλα.... αν ήμασταν σε GUI, αντί για την s_get θα χρησιμοποιούσαμε την αντίστοιχη του GUI).

έγραψε:
Π.Σ Ρε παιδια.... χυμαροι ειστε!!!!!!!! Δεν το αφηνουμε μια μερουλα μεχρι αυριο να τα ξαναδουμε παλι ολα μαζι μηπως παιζει καμια απορια... με την ησυχια μας????? :D

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

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

Δημοσίευσηαπό Star_Light » 28 Ιούλ 2011, 15:30

migf1 έγραψε:
Star_Light έγραψε:Δηλαδη για να καταλαβω ας πουμε... υπαρχει προβλημα με την getchar εκτος και αν βαλεις σε περιβαλλον windows πριν απο αυτην ενα fflush(stdin) ?
Και στον Γκιουρδα μεσα δεν αναφερει τιποτα για αυτο.... ολοκληρο βιβλιο!

Και όχι μόνο με την getchar() (getc() και fgetc() ) αλλά και με την scanf(). Το πρόβλημα παρουσιάζεται όταν ο χρήστης (είτε κατά λάθος είτε επίτηδες) πληκτρολογήσει στην είσοδο περισσότερα πράγματα από ότι περιμένουμε να διαβάσουμε. Τα έξτρα αυτά πράματα παραμένουν στο buffer της εισόδου με αποτέλεσμα το επόμενο scanf (getchar, κλπ) του προγράμματός μας αντί να διαβάσει φρέσκο πράμα από τον χρήστη, διαβάζει αυτόματα τα έξτρα πράματα από την προηγούμενη είσοδο. Το fflush(stdin) σε Windows αυτό που κάνει είναι να καθαρίζει τελείως το buffer, οπότε καλώντας το πριν από κάθε scanf (getchar, κλπ) εξασφαλίζουμε πως θα διαβάσουμε φρέσκο πράμα από τον χρήστη. Μόνο που η fflush(stdin) δεν λειτουργεί σε περιβάλλον gcc/unix/linux.

Πέρα όμως από το παραπάνω, αυτό που έχει μεγαλύτερη σημασία είναι ότι μάθαμε πως να μετατρέπουμε strings σε αριθμούς, κάτι που χρησιμοποιείται κατά κόρον σε όλα τα GUI, γιατί εκεί δεν διαβάζεις με τις στάνταρ συναρτήσεις εισόδου της C. Τα GUI έχουν δική τους συνάρτηση διαβάσματος και κατά συντριπτική πλειοψηφία διαβάζουν τα πάντα ως strings (συνήθως μέσα από πεδία κειμένου σε γραφικές φόρμες) οπότε πρέπει να ξέρουμε πως να τα μετατρέπουμε σε αριθμούς εμείς όταν χρειαστεί.

Και τώρα που το σκέφτομαι, τον 3ο τρόπο λύσης της προηγούμενης άσκησης δεν θα τον γράψω όπως είχα σκεφτεί, δηλαδή με στόχο να δείξω διαφορετική χρήση των συναρτήσεων get_, αλλά θα τον κάνω με χρήση της συνάρτησης sscanf() που δουλεύει σαν την scanf() αλλά αντί να διαβάζει από την κύρια είσοδο, διαβάζει από ένα string (στη δική μας περίπτωση θα είναι το: inbuf που θα το έχουμε διαβάσει πρώτα κλασικά με την s_get εδώ πέρα, γιατί είμαστε σε κονσόλα.... αν ήμασταν σε GUI, αντί για την s_get θα χρησιμοποιούσαμε την αντίστοιχη του GUI).



Κατσε ομως... εγω στον παρακατω κωδικα δεν πληκτρολογησα κατι παραπανω... εναν χαρακτηρα την φορα δινω

Κώδικας: Επιλογή όλων
#include<stdio.h>

int main()
{

char x;
int i;

for(i=0; i<4; i++)
{
printf("Dwste enan xaraktira\n");
x=getchar();
putchar(x);
}



return 0;
}


και μου το εμφανιζει 2 φορες ας πουμε :/
Γνώσεις ⇛ 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/C++

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

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

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

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

migf1 έγραψε:Διαβάζει και το ENTER που πατάς μετά τον χαρακτήρα, και το παίρνει σαν είσοδο του επόμενου getchar()... αν έχεις Windows, βάλε ένα fflush(stdin) μπροστά από το getchar() και θα δεις πως θα φτιάξει ;)


Ή για να το καταλάβεις καλύτερα, τρέξε αυτό τον κώδικα σε όποια πλατφόρμα θέλεις:
Κώδικας: Επιλογή όλων

#include<stdio.h>

int main()
{
char x=' ';
int i;

for(i=0; x != '\n' && i<4; i++)
{
printf("Dwste enan xaraktira\n");
x = getchar();
putchar(x);
}

return 0;
}

Θα δεις πως μόλις δώσεις την 1η είσοδο, θα σου ζητήσει 2η αλλά αντί να περιμένει να τη δώσεις, θα προχωρήσει μόνο του και θα τερματίσει. Αυτό διότι του έχω πει να σταματάει το loop είτε όταν το i γίνει 4 είτε όταν το χ γίνει '\n'... στην περίπτωσή μας διαβάζει ως 2η είσοδο το '\n' από την 1η είσοδο (το ENTER που πατάς στο τέλος δηλαδή) και τερματίζει.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

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

Δες τώρα τον ίδιο κώδικα με χρήση της s_get() ... θα δουλέψει μια χαρά (σε οποιαδήποτε πλατφόρμα και χωρίς ανάγκη για fflush(stdin) )...

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

#include<stdio.h>

#define MAXINBUF (255+1)

// ------------------------------------------------------------------------------
char *s_get(char *s, size_t len)
{
char *cp;
for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
; // for-loop with empty body
*cp = '\0'; // null-terminate last character

return s;
}

// ------------------------------------------------------------------------------
int main()
{
char inbuf[ MAXINBUF ] = "";
char x = ' ';
int i;

for(i=0; x != '\n' && i<4; i++)
{
printf("\nDwste enan xaraktira\n");
s_get(inbuf, MAXINBUF);
x = *inbuf;
putchar(x);
}

return 0;
}

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

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

Δημοσίευσηαπό Star_Light » 28 Ιούλ 2011, 16:22

migf1 έγραψε:Διαβάζει και το ENTER που πατάς μετά τον χαρακτήρα, και το παίρνει σαν είσοδο του επόμενου getchar()... αν έχεις Windows, βάλε ένα fflush(stdin) μπροστά από το getchar() και θα δεις πως θα φτιάξει ;)


αααααα τωρα καταλαβα...... εδω το καταλαβαινω καλυτερα !!!!!
Γνώσεις ⇛ 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/C++

Δημοσίευσηαπό migf1 » 28 Ιούλ 2011, 16:55

Λοιπόν, πάμε τώρα να βελτιώσουμε την λύση της 1ης μας άσκησης, χρησιμοποιώντας την στάνταρ συνάρτηση:
Κώδικας: Επιλογή όλων

int sscanf (const char *s, const char *template, …); // #include <stdio.h>

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

Άρα για να την χρησιμοποιήσουμε θα πρέπει πρώτα να διαβάσουμε την γραμμή εισόδου μέσα σε ένα μεγάλο string (το inbuf στην περίπτωσή μας) το οποίο κατόπιν θα το περάσουμε σαν 1ο όρισμα της sscanf(). Τα υπόλοιπα θα είναι ακριβώς ότι θα γράφαμε στην scanf() αν διαβάζαμε απευθείας από την κύρια είσοδο.

Υπάρχουν πολλά πλεονεκτήματα σε αυτόν τον τρόπο!

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

Έπειτα, δεν χρειάζεται να χρησιμοποιήσουμε τις συναρτήσεις atoi, atol, atof, κλπ για να μετατρέψουμε την είσοδο σε αριθμούς, γιατί αυτές οι μετατροπές γίνονται αυτόματα από την sscanf() ανάλογα τα % που θα χρησιμοποιήσουμε μέσα στην sscanf (%d, %c, %f, %ld, κλπ, κλπ).

Ακόμα, η sscanf (όπως και η scanf) μας επιστρέφει το πλήθος των εκχωρήσεων που έγιναν σε μεταβλητές. Οπότε αν για παράδειγμα ο χρήστης μας πληκτρολογήσει λιγότερες ή περισσότερες από τις τιμές που περιμένουμε να διαβάσουμε, έχουμε τρόπο να το ελέγξουμε και να πράξουμε ανάλογα.

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

Δείτε ένα μικρό απόσπασμα κώδικα...

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

...
char inbuf[ MAXINBUF ] = "";
int n1, n2;

printf("dwste 2 akeraioys arithmoys: ");
s_get( inbuf, MAXINBUF );
sscanf( inbuf, "%d %d", &n1, &n2);
printf("dwsate toys arithmoys: %d kai %d\n", n1, n2);
...

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

Επίσης, από μόνη της η scanf αν ο χρήστης μας πληκτρολογήσει έναν αντί για δυο αριθμούς που περιμένουμε και πατήσει ENTER, η συνάρτηση θα διαβάσει τον πρώτο στην μεταβλητή n1 και στην μεταβλητή n2 θα βάλει την τιμή 0 (δοκιμάστε το να το δείτε και μόνοι σας). Ακόμα, αν ο χρήστης μας πληκτρολογήσει περισσότερα από 2 νούμερα, τότε η συνάρτηση θα κρατήσει μονάχα τα 2 πρώτα και θα τα εκχωρήσει στις μεταβλητές n1 και n2, αγνοώντας τα υπόλοιπα (δοκιμάστε το κι αυτό μόνοι σας).

Αν τώρα θέλουμε να ελέγξουμε επί τούτου την περίπτωση που θα μας δώσει μονάχα ένα νούμερο, ώστε να του πούμε να ξαναπροσπαθήσει από την αρχή, μπορούμε να ελέγξουμε την τιμή που μας επιστρέφει η sscanf.

Στο απόσπασμα κώδικα που ακολουθεί, κάνω ότι και στο προηγούμενο με την προσθήκη ενός do-while loop στην περίπτωση που ο χρήστης μας δώσει λιγότερα από 2 νούμερα. Το loop θα συνεχίσει να τον ρωτάει μέχρι να μας δώσει τουλάχιστον 2 νούμερα.

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

...
char inbuf[ MAXINBUF ] = "";
int n1, n2;
int plithos = 0;

do {
printf("dwste 2 akeraioys arithmoys: ");
s_get( inbuf, MAXINBUF );
plithos = sscanf( inbuf, "%d %d", &n1, &n2);
} while (plithos < 2);

printf("dwsate toys arithmoys: %d kai %d\n", n1, n2);
...


Οπότε, θέλετε να προσπαθήσετε τώρα να τροποποιήσετε τον κώδικα της 1ης άσκησης ώστε να διαβάζει σε μια γραμμή το εκάστοτε ζευγάρι αριθμών (int, long και float) με την sscanf και να τυπώνει τις πράξεις μεταξύ των ζευγαριών κάθε φορά;

Μπορείτε επίσης να τροποποιήσετε και τον κώδικα της 2ης άσκησης, που διαβάζει δυο αριθμούς και μια πράξη και τυπώνει το αποτέλεσμα. Αυτή τη φορά διαβάστε και τα 3 μαζί σε μια γραμμή (προφανώς με χρήση των s_get και sscanf).

Αν έχετε απορίες, μέχρι τώρα γράψτε τες να τις λύσουμε. Αν δυσκολευτείτε με την βελτίωση των λύσεων στις 2 ασκήσεις πείτε μου να δώσω εγώ τον κώδικα. Ή πείτε μου αν θέλετε να δώσω εγώ τον κώδικα της μιας από τις δυο ασκήσεις και να γράψετε εσείς την άλλη.

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

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

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