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

fgets(), while loops & problems..


Keydo

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

Δημοσ.

>Random_Keys = (char*)malloc(Encryption_Strength*sizeof(char));
while (strcmp(Key_Acception, "No") == 0) {
for (i = 0 ; i < Encryption_Strength ; i++){
	temp = (rand()%36);
	Random_Keys[i] = Keys[temp];
}
printf("Key: %s will be used for the encryption\n", Random_Keys);
printf("Do you want to keep it?\n");
printf("Yes/No: ");
fgets(Key_Acception, 4, stdin);
}

Δουλεύει κανονικά το while-loop αλλά συμπεριφέρεται σαν να μην βλέπει την fgets(). Όλες οι παραπάνω εντολές δουλεύουνε κανονικότατα, αλλά με το που φτάνει στο fgets() βγαίνει από το loop χωρίς να περιμένει κάποιο input από τον χρήστη. Αν σβήσω την fgets() το loop επαναλαμβάνεται χωρίς να σταματάει. Καμιά ιδέα για το τι φταίει? :roll:

Δημοσ.

Υπάρχει fgets() και πιο πάνω αλλά ότι input δίνω από το πληκτρολόγιο το αποθηκεύει, μέχρι και το \n πιάνει.

Δημοσ.
δοκίμασε πριν την fgets να κάνεις fflush το stdin......fflush(stdin)

 

Τώρα δουλεύει αλλά την πρώτη φορά κάνει 2 επαναλήψεις χωρίς να πάρει input από το πληκτρολόγιο. Μετά όμως κανονικά.. :???:

Δημοσ.

αν θες, και μπορεις, δωσε μας τον κωδικα πριν απο το σημείο αυτό....

Η ιδεα του fflush ειναι οτι καθαρίζει τον buffer του stdin...

Γιατι όμως χρησιμοποιείς την fgets για να πάρεις είσοδο απο το πληκτρολόγιο;

Δημοσ.
αν θες, και μπορεις, δωσε μας τον κωδικα πριν απο το σημείο αυτό....

Η ιδεα του fflush ειναι οτι καθαρίζει τον buffer του stdin...

Γιατι όμως χρησιμοποιείς την fgets για να πάρεις είσοδο απο το πληκτρολόγιο;

 

Θέλω να πάρω ολόκληρο string ως είσοδο που πιθανώς να έχει κενά. Η gets() μπορεί να δημιουργήσει overrun του buffer, η scanf() δεν διαβάζει κενά, οπότε η μόνη λύση είναι η fgets() (ή κάποια άλλη εντολή που δεν ξέρω :lol:).

 

Σκοπός του προγράμματος είναι να κωδικοποιήσει ένα αρχείο που θα του δωθεί, αλλά μέχρι στιγμής ότι έχω κάνει αφορά φρου-φρου κι αρώματα και όχι κάτι επί της ουσίας μιας και σκανάρει το αρχείο & δημιουργεί το κλειδί που θα χρησιμοποιηθεί για την κωδικοποίηση. Ο κώδικας μπορεί να κατέβει από εδώ για όσους ενδιαφέρεστε. :D

Δημοσ.

παλεψα λιγο με τον κωδικα αλλα δεν καταφερα να το λυσω,μου αγνοουσε ακομα κ δοκιμαστικα printf που εβαζα.Πολυ σπαστικο,κ γω την ειχα παθει ετσι μια φορα,δεν υπολογιζε το scanf("%c",&a) αλλα το scanf("%1s",&a)...ειναι για τον πο*τσο μερικες φορες...

Δημοσ.

Μια εναλλακτική λύση της fgets είναι η scanf(“%10s”,string); όπου ζητούμε από την scanf να περιορίσει το μέγεθος των εισαχθέντων στοιχείων ως τους 9 πρώτους χαρακτήρες της εισόδου.

Βέβαια αν μας ενδιαφέρει το formation του προγράμματος τότε η scanf από όσο γνωρίζω δεν βοηθά ιδιαίτερα καθώς αγνοεί «επιδεικτικά» περιπτώσεις κενής εισόδου (πχ. Enter δίχως είσοδο άλλων χαρακτήρων).

Εάν η scanf διαγνώσει λανθασμένη μορφή εισόδου (πχ. κείμενο αντί αριθμού) επιστρέφει 0 τόσες φορές όσες και οι λανθασμένες τιμές εισόδου μας (για αυτό άμα επιστρέψει 0 κάνουμε ένα fflush ώστε να ξεμπερδέψουμε από όλο το περιεχόμενο του STDIN μας).

 

Από εκεί και πέρα, ο κώδικας σου σε γενικές γραμμές δουλεύει καλά, με την σημείωση όμως πως α) έχεις ορισμένα λάθει όσον αφορά την δήλωση στο μέγεθος των μεταβλητών τύπου char τόσο των σταθερών (Keys – είναι 37 αντί 36) όσο και των δυναμικά δεσμευμένων (Random_Keys – δέσμευσε +1 χαρακτήρα και φρόντισε να καθαρίσεις να το καθαρίσεις ώστε να είναι \0-Termineted όπως θέλει η C τα String της), β) χρειάζεται μια αναδιάρθρωση στα σημεία που περιμένεις και ελέγχεις την είσοδο του χειριστή ώστε να μην χρειάζεται να δηλώνεις δυο φορές το prompt εισόδου σου (πχ. «Enter the file you want to be encrypted:») και γ) μπορεί εύκολα να ελέγξεις για το “no” ανεξάρτητα του τρόπου γραφής του (κεφαλαία ή μικρά κτλ) με την stricmp, ενώ για να αφαιρέσεις το \n της fgets μπορείς απλά να διαγράψεις με \0 το προ-τελευταίο χαρακτήρα του string).

 

Καλή συνέχεια.

 

Ο κώδικας δοκιμάστηκε σε CodeGear C/C++ Builder 6.0 (MS-Windows) (όπου for(;;) να θυμάσαι πως ισούται με while(1)).

 

>
//Made by Kid
//kid.blogotropia.gr
//[email protected]

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

int main(){

  // Variables

  char Filename[256]="a", Buffer[256];

  // Directx: Set from 36 to 37
  char Keys[37]="abcdefghijklmnopqrstuvwxyz0123456789";

  char *Random_Keys = NULL;  // Directx: Always set free * to NULL
  int Encryption_Strength = 5;
  int i, x, y, temp;
  FILE *fopen(), *Source_File;
  srand((unsigned int)time((time_t *)NULL));

  // Options

  printf("In order to encrypt a file, it must be \n");
  printf("in the same folder with the executable file.\n");
  printf("Dictionary: %s", Keys);
  printf("\n");

  // File Scanning
  for(; // directx
   {
     printf("Enter the file you want to be encrypted:");
     scanf("%255s",Filename);

     if((Source_File = fopen(Filename, "r"))!=NULL)
      break;
     printf("%s: File does not exist.\n", Filename);
   }

  // Encryption Strength

  printf("\n");
  printf("How strong encryption do you want to use?\n");
  printf("(Value must be between 1 and 10, default is 5)\n");
  printf("(10 is the strongest possible encryption)\n");
  printf("If you don't want to change that, enter 0\n");

  for(; // directx
   {
   printf("Value:");
  	if(!scanf("%d", &Encryption_Strength))
      {
        fflush(stdin); // Ignore rest of possible bad input chars of STDIN
        Encryption_Strength = -1;
      }

     if(Encryption_Strength < 0 || Encryption_Strength > 10)
      printf("Value must be between 1 and 10.\n");
     else
      break;
   }

  if (Encryption_Strength == 0)
   Encryption_Strength = 5;

  // Key Randomizer

  // directx: +1 one byte to reserved \0 (C NULL-Terminator)
  Random_Keys = (char*)malloc((Encryption_Strength*sizeof(char))+1);
  // directx: Set entire buffer to \0 (safeguard of rest C functions) 
  memset(Random_Keys,0,(Encryption_Strength*sizeof(char))+1);

  do // directx
   {
     for (i = 0 ; i < Encryption_Strength ; i++)
      {
  	   temp = (rand()%36);
     	Random_Keys[i] = Keys[temp];
     }

     printf("Key: %s will be used for the encryption.\n", Random_Keys);
     printf("If you want to use it, press any key, otherwise type No:");

     fflush(stdin);
     fgets(Buffer, 256, stdin);
     Buffer[strlen(Buffer)-1] = '\0';

   }while(!stricmp(Buffer,"no"));

  printf(" ... Encrypting ...\n");

  // directx: Free program resources
  fclose(Source_File);
  free(Random_Keys);

  return 0;
}

Δημοσ.

Κάνοντας c/p το πρόγραμμα με τις διορθώσεις του DirectX έκανε πάλι το ίδιο, προσπέρασε το fgets() μέσα στην while. Μήπως είναι θέμα compiler? gcc χρησιμοποιώ.. :roll:

Δημοσ.

Ενδεχομένως διότι δοκίμασα τον κώδικα σε:

 

α) CodeGear C/C++ Builder 6.0 -είναι compiler του 2002 για MS-Windows.

β) CodeGear Turbo C++ Explorer -είναι compiler του 2006 για MS-Windows.

γ) Borland Turbo C++ 3.0 -είναι compiler του 1991 για MS-DOS.

δ) Microsoft-C 6.0 -είναι compiler του 1990 για MS-DOS (!)

 

Και στους 4 Compiler ο κώδικας δουλεύει κανονικά..

 

-

 

Και μια μικρή διόρθωση ώστε να είμαστε 100% ANSI-C συμβατοί:

 

Ψάχνοντας το θέμα περισσότερο παρατηρώ πως η εντολή stricmp θεωρείται από πολλούς ως μη ANSI-C συμβατή - από την άλλη πλευρά για άλλους ορίζεται ως ANSI-C συμβατή (μπάχαλο δηλαδή).

 

Σε αυτή την περίπτωση, μιας και δουλεύεις με τον GCC για κάθε ενδεχόμενο καλού - κακού προτίμησε την παρακάτω αλλαγή (η strlwr μετατρέπει το Buffer σε μικρά γράμματα & ελέγχει με την strcmp για "no"):

 

>
  do
   {
     for (i = 0 ; i < Encryption_Strength ; i++)
      {
  	   temp = (rand()%36);
     	Random_Keys[i] = Keys[temp];
     }

     printf("Key: %s will be used for the encryption.\n", Random_Keys);
     printf("If you want to use it, press any key, otherwise type No:");

     fflush(stdin);
		fgets(Buffer, 256, stdin);
		Buffer[strlen(Buffer)-1] = '\0';
		strlwr(Buffer);

	}while(!strcmp(Buffer,"no"));

 

Τώρα όσον αφορά το fgets πιστεύω ότι κάτι συμβαίνει με το GCC και το STDIN (φαίνεται πως παρ' όλο το fflush -ορισμένοι θεωρούν παράνομο να γίνεται σε STDIN έτσι και αλλιώς..- μένει κάποιο \r\n escape-sequency μάλλον..) όμως δεν δουλεύω με Unix/Linux και δεν μπορώ να σε βοηθήσω περαιτέρω :(

Δημοσ.

Σε gcc δεν μου αναγνώρισε την stricmp αλλά θεώρησα ότι ήταν απλά κάποιο typo και έσβησα το i. Η strlwr επίσης δεν αναγνωρίστηκε. Όπως θα πρόσεξες, οι βιβλιοθήκες που έχω ορίσει είναι οι stdio/stdlib/time/string, μήπως πρέπει να προσθέσω κάποια ακόμα? Κατά τα άλλα, τα ίδια, ουδεμία αλλαγή, συνεχίζει να βγαίνει από το while-loop. :(

Δημοσ.

Φίλε μου, από ότι βλέπω στον κόσμο του Unix ούτε η strlwr υπάρχει στην string.h -αν και μέχρι σήμερα όλοι οι compiler μου (στα documentation τους) την έδιναν και αυτή ως ANSI-C .. θα ξεχάσω και αυτά που ξέρω.. :(

 

Δεν έχει νόημα να σε ταλαιπωρώ περισσότερο - δεν δουλεύω τον GCC (όπως είδες δουλεύω χρόνια σε DOS/Windows platforms) και από ότι βλέπω ο κόσμος του είναι πολύ διαφορετικός από τους δικούς μου compiler για να μην πω από την δικιά μου C ;)

 

Ελπίζω όσοι τον δουλεύουν να σε βοηθήσουν.. άλλωστε το πρόβλημα της fgets που είναι το βασικό σου όπως είπα μάλλον σχετίζεται με την διαχείριση console stdin του Linux σου..

 

Αν κάποια στιγμή γυρίσεις σε DOS/Windows ο κώδικας δουλεύει με αυτούς τους compiler που σου έγραψα..

 

Καλή τύχη!

Δημοσ.

Στο αρχικό πρόβλημα:

> scanf("%d", &Encryption_Strength);

 

Η scanf σταματάει με το που βλέπει το enter μετά τον αριθμό.

Η επόμενη fgets,

> fgets(Key_Acception, 4, stdin);

διαβάζει απλά το enter και γι' αυτό σου φαίνεται σαν να μην εκτελείται.

 

Επομένως πρέπει πριν από την fgets να βάλεις το enter από το input buffer.

 

Το fflush(stdin) δουλεύει μερικές φορές, αλλά το πρότυπο της C προτείνει ξεκάθαρα να μην χρησιμοποιείται.

 

Εναλλακτικές:

> scanf("%d ", &Encryption_Strength);

Έχει ένα κενό μετά το %d και λέει στην scanf να προσπεράσει το enter.

 

> while (!feof(stdin)) getchar();

Αδειάζεις τον input buffer με compliant τρόπο.

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

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