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

Πρόγραμμα σε C


geodark

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

Δημοσ. (επεξεργασμένο)
#include <stdio.h>

#define MAXBUFSIZE 5+1

// -----------------------------------------------------------------------
int main( void )
{
char buffer[MAXBUFSIZE] = {'\0'};
int h = 0, m = 0; // hours, minutes

for (;
{
printf("Enter time in 24h format (e.g.: 23:45): ");
fflush(stdout);
fgets(buffer, MAXBUFSIZE, stdin);

// if buffer-overflow attempted, flush the stdin
if ('\0' != buffer[MAXBUFSIZE-2]
&& '\n' != buffer[MAXBUFSIZE-2]
){
while ('\n' != getchar() )
; // void
}

// demand valid input
if ( 2 != sscanf(buffer, "%d:%d", &h, &m)
|| h < 0 || h > 24
|| m < 0 || m > 59
){
puts( "Bad input, try again..." );
continue;
}

break;
}
printf( "%02d:%02d\n", h, m );

return 0;
}
EDIT: Διόρθωση της περίπτωσης επιχειρούμενου buffer overflow. Επεξ/σία από migf1
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αυτο δεν τον εμποδίζει να πατήσει ότι θέλει απλά του κάνει υπόδειξη ότι έδωσε λάθο Input.

Ναι, απαντάει δηλαδή στην αρχική ερώτηση του poster πως μπορεί να διαχειριστεί bad input ώστε να μην κρασάρει ο κώδικάς του. Γίνεται επίσης compile παντού μιας και είναι cross-platform, στάνταρ C... δεν περιέχει π.χ. fflush(stdin) που δουλεύει μόνο σε Windows.

 

Απλώς τώρα που ξανακοιτάω τον κώδικα, σε περίπτωση buffer-overflow δεν τον ειδοποιεί, απλά του κόβει το περιττό input... δλδ αν του δώσει π.χ. 12:345 δεν θα παραπονεθεί κι απλώς θα κόψει το 5άρι από το τέλος (ώστε να μην κρασάρει). Επίσης δεν κάνει reset το buffer (κακό αυτό).

 

Για να το κάνουμε λίγο πιο strict και safe μπορούμε να αυξήσουμε κατά 1 τη χωρητικότητα του buffer και να το αλλάξουμε σε κάτι τέτοιο...

 

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

#define MAXBUFSIZE	6+1

// -----------------------------------------------------------------------
int main( void )
{
	char buffer[MAXBUFSIZE];  // = {'\0'} replaced by memset() inside the loop
	int h = 0, m = 0; // hours, minutes
	
	for (;
	{
		memset(buffer, '\0', MAXBUFSIZE);
		printf("Enter time in 24h format (e.g.: 23:45): ");
		fflush(stdout);
		fgets(buffer, MAXBUFSIZE, stdin);

		// if buffer-overflow detected: warn, flush the stdin and ask for new input
		if ('\0' != buffer[MAXBUFSIZE-2]
		&& '\n' != buffer[MAXBUFSIZE-2]
		){
			puts( "*** buffer-overflow attempt detected" )
			puts( "*** flushing stdin..." );
			while ('\n' != getchar() )
				; // void
			puts("*** try again...");
			continue;
		}

		// demand valid input
		if ( 2 != sscanf(buffer, "%d:%d", &h, &m)
		|| h < 0 || h > 24
		|| m < 0 || m > 59
		){
			puts( "** bad input, try again..." );
			continue;
		}

		break;
	}
	printf( "%02d:%02d\n", h, m );

	return 0;
}

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Γιατί να μπεις σε όλη αυτή την διαδικασία, με overflows κτλ αφού το να του επιτρεπει να πατάει μόνο ότι πρέπει είναι το καλύτερο. Ο χρήστης το ρώτησε έτσι γιατί δεν ήξερε ότι μπορούσε να γίνει και με αυτό τον τρόπο. Τώρα που το είδε δεν νομίζω να θέλει να χρησιμοποιήσει την scanf για σοβαρό input. Μόνο για πρόχειρα προγραμματάκια.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ούτε εγώ χρησιμοποίησα scanf()... χρησιμοποίησα συνδυασμό fgets() με sscanf(). Προσωπικά το θεωρώ πολύ πιο βατό από το να φτιάχνει από την αρχή custom command-line editing mode.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Είναι πολύ λιγότερο user friendly. Και η ρουτίνα είναι πιο εύκολη και λιγότερο δύσκολο να έχεις κάποιο λάθος.

Εγώ την έφτιαξα χωρίς compiler και έχοντας να γράψω c και c++ 8 χρόνια.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Διαφωνώ!

 

3 γραμμές definitions...

#define MAXBUFSIZE ...
char buffer[MAXBUFSIZE];
int n=0, temp;
2 γραμμές είσοδος...

if ( fgets(buffer, MAXBUFSIZE, stdin) ) {
    n = sscanf(buffer, "...", ...);

5 γραμμές για stdin flushing & απόρριψη τελικού ENTER ελέω fgets()...

    temp = strlen(buffer);
    if (temp > 0) --temp;
    if ( '\n' != buffer[temp] )
        while ('\n' != getchar() ) ; /* flush stdin */
    buffer[temp] = '\0';   // reject trailing '\n' or extra input
}
Όσες έξτρα γραμμές χρειάζεσαι για input validation συγκεκριμένα για τον κώδικά σου (το overflow το κάνει handle έτσι κι αλλιώς η fgets()... εμείς απλά το κάναμε detect απλά και μόνο για να φλασάρουμε τα σκουπίδια από την κύρια είσοδο)

if ( n != number_of_args_passed_in_sscanf
/* put here code specific extra checks */
) {
    /* error */
}
Σύνολο: 10 γραμμές + όσους custom ελέγχους χρειάζεται ο εκάστοτε κώδικας

για μια στανταρισμένη μεθοδολογία που δουλεύει σε όλες τις πλατφόρμες, και για τη συντριπτική πλειοψηφία των input από command-line οποιουδήποτε προγράμματος. Crossplatform user-friendly και στανταρισμένα λιγότερο επιρρεπής σε λάθη.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μάλιστα, από ότι κατάλαβα κατά την άποψή σου το 2013 η ενδεδειγμένη μέθοδος εισόδου από την γραμμή εντολών είναι να γράφεις ξεχωριστό char-based command-line editing mode για κάθε διαφορετικό input type που χρειάζεται το πρόγραμμά σου. Δηλαδή αν έχεις 20 διαφορετικά input types στο πρόγραμμά σου θα γράψεις 20 διαφορετικά editing-modes ελέγχοντας έναν-έναν τον κάθε χαρακτήρα με μια σειρά από if (nested or not) για τον κάθε χαρακτήρα! Κι όλα αυτά με κώδικα που τρέχει μόνο σε Windows.

 

Προφανώς έχω μείνει πολύ πίσω!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μάλιστα, από ότι κατάλαβα κατά την άποψή σου το 2013 η ενδεδειγμένη μέθοδος εισόδου από την γραμμή εντολών είναι να γράφεις ξεχωριστό char-based command-line editing mode για κάθε διαφορετικό input type που χρειάζεται το πρόγραμμά σου. Δηλαδή αν έχεις 20 διαφορετικά input types στο πρόγραμμά σου θα γράψεις 20 διαφορετικά editing-modes ελέγχοντας έναν-έναν τον κάθε χαρακτήρα. Κι όλα αυτά με κώδικα που τρέχει μόνο σε Windows.

 

Προφανώς έχω μείνει πολύ πίσω!

 

Σε παρακαλώ σημασια έχει MONO ο αλγοριθμος :P

 

ασχετα αμα αυτος που ανοιξε το θεμα το ζητησε σε C. Και ο φιλος του προτεινε συναρτηση η οποια δεν ειναι portable.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

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