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

C έλεγχος για χαρακτήρα.


Spiroslp

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

Δημοσ.

Καλησπέρα. Η άσκηση την έχεις ένας φίλος μου και δεν θυμάμαι να το βοηθήσω σε μια μικρή λεπτομέρεια. Η Άσκηση ζητάει να δηλώνουμαι έναν δυαδικό πίνακα και να τον γεμίζουμε και τον εκτυπώνουμε. Αλλά αυτό που ζητάει και δεν θυμάμαι είναι ότι άμα δώσουμε χαρακτήρα να βγάζει μήνυμα λάθους και να συνεχίζει. Πως το κάνουμε αυτό;

Εδώ ο κώδικας που δεν μου βγαίνει:

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

int main()
{
   int i,j, pin [2][3];
char c;


   for(i=0;i<2;i++)
   {
       for(j=0;j<3;j++)
       {
   printf("Dose noymero\n");
   scanf ("%d",&pin[i][j]);
   if( pin[i][j] == c)
   printf("Akyro\n");
       }
   }

    for(i=0;i<2;i++)
   {
       for(j=0;j<3;j++)
       {
           printf("[%d] [%d] %d\n",i,j,pin[i][j]);
       }
   }


   return 0;
}

Δημοσ.

Αντί να διαβάζεις integers, διάβαζε strings και κράτα τα μόνο αν είναι αριθμοί. Θα χρειαστεί να χρησιμοποιήσεις τη στάνταρ βιβλιοθήκη ctype.

Δημοσ.

Σωστό αλλα μας είχε πει η καθηγήτρια παλιά ότι γίνεται και χωρίς να προσθέσεις το ctype απλά μόνο με το stdio και το stdlib.

Δημοσ.

1ον

Στο if, συγκρίνεις κάτι που έχει τιμή με κάτι που δεν έχει τιμή (τι τιμή έχει το c ; )

 

2ον

Μπορείς να διαβάζεις χαρακτήρες και να ελέγχεις εάν η τιμή τους είναι μέσα στα όρια του

αλφάβητου (δεν θυμάμαι από που μέχρι που είναι.... ) συμπεριλαμβάνοντας και τα

κεφαλαία.

 

Φυσικά θα πρέπει να βρεις και τα σημεία στίξης κτλ κτλ κτλ.

 

Οπότε δες απλά ποια είναι τα όρια των χαρακτήρων που είναι αριθμοί, δηλαδή τι τιμή

έχει μία μεταβλητή char, με το char να είναι '1', '2', κτλ κτλ κτλ

Δημοσ.

Θα μπορούσες να χρησιμοποιήσεις την strspn, αν επιτρέπεται βέβαια (είναι δηλωμένη στο string.h) ώστε να εξετάσεις αν η είσοδος του χρήστη αποτελείται μόνο από αριθμητικούς χαρακτήρες και τούτο σκεπτόμενος ότι καθώς η strspn επιστρέφει το μήκος του κειμένου που απαρτίζεται από ένα ορισμένο σετ χαρακτήρων (πχ. 0123456789) αν υπάρχουν άλλοι άγνωστοι χαρακτήρες τότε το μήκος αυτό θα διαφέρει από το ανάλογο της strlen. Από εκεί και πέρα η ανάγνωση του πληκτρολογίου μπορεί να γίνει με την βοήθεια της fgets η οποία είναι αρκετά σταθερή κατά την ανάγνωση του stdin (με μόνο μειονέκτημα ότι προσθέτει το CR/LN '\n' στο τέλος του string) και την sscanf η οποία δρα σαν την scanf μόνο που διαβάζει πληροφορίες από το string-buffer (μεγέθους BUFSIZ -δηλωμένο constant στην stdio.h) που ορίζουμε (αντί του stdin).

 

Ακολουθεί ένα μικρό παράδειγμα γραμμένο σε C++ Builder 2009:

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

int main(void)
{
int i,j, pin [2][3];
char c, szNum[bUFSIZ];

for(i=0;i<2;i++)
{
	for(j=0;j<3;j++)
	{
		/* Loop until valid number */
		while(1)
		{
               printf("Dose noymero\n");
			/* Read stdin, up to BUFSIZ, into szNum buffer */
			fgets(szNum, BUFSIZ, stdin);
			/* Anything to process (fgets appends \n auto.)? */
			if(!strcmp(szNum, "\n"))
				continue; /* No.. */
			/* szNum should only contain numeric chrs. (minus fgets \n) */
			if(strspn(szNum, "0123456789") != strlen(szNum) - 1)
				printf("Bad input - %s\n", szNum);
			else
				break;
		}
		/* Works like scanf but instead of stdin uses szNum */
		sscanf(szNum, "%d", &pin[i][j]);

		if( pin[i][j] == c)
			printf("Akyro\n");
	}
}

 for(i=0;i<2;i++)
{
	for(j=0;j<3;j++)
	{
		printf("[%d] [%d] %d\n",i,j,pin[i][j]);
	}
}


getchar();
return 0;
}

 

ΕΞΟΔΟΣ:

>
Dose noymero
1
Dose noymero
2a
Bad input - 2a

Dose noymero
2
Dose noymero
3
Dose noymero
4
Dose noymero
5.000
Bad input - 5.000

Dose noymero
5000
Dose noymero
6000
[0] [0] 1
[0] [1] 2
[0] [2] 3
[1] [0] 4
[1] [1] 5000
[1] [2] 6000

 

Υ.Γ.

Φυσικά, όπως ελέχθη, μπορεί να γραφθεί πολύ απλά, δίχως καν την stdlib.h ή την ctype ή string.h κτλ. με απλό έλεγχο κάθε chr. του string για ASCII τιμές 0 ως 9 (ή \n λόγο fgets) και απόρριψη της εισόδου σε κάθε διαφορετικό χαρακτήρα:

>
/* Return 0 on first non numeric P character */
int _isNumber(char *P)
{
while(*P)
{
	if((*P < '0' || *P > '9') && *P != '\n')
		return 0;
	P++;
}
return 1;
}

Δημοσ.

[snip]

Υ.Γ.

Φυσικά, όπως ελέχθη, μπορεί να γραφθεί πολύ απλά, δίχως καν την stdlib.h ή την ctype ή string.h κτλ. με απλό έλεγχο κάθε chr. του string για ASCII τιμές 0 ως 9 (ή \n λόγο fgets) και απόρριψη της εισόδου σε κάθε διαφορετικό χαρακτήρα:

[snip]

 

Κάτι τέτοιο σκεφτόμουν κι εγώ, όταν ο φίλος Spiroslp διευκρίνισε πως του είπαν να γίνει μόνο με stdio.h και stdlib.h, αλλά με λίγο διαφορετική υλοποίηση. Η αναφορά στην stdlib.h έγινε κατά πάσα πιθανότητα για τις συναρτήσεις atoi(), atol(), strtol() κλπ που μετατρέπουν strings σε αριθμούς.

 

Επίσης αντί για fgets() και sscanf() εγώ χρησιμοποιώ μια δική μου συνάρτηση: s_get() που δουλεύει σαν την fgets(), αλλά δεν χρειάζεται filestream στα ορίσματα και σβήνει και το '\n' στο τέλος, πριν επιστρέψει (την συμπεριλαμβάνω σχεδόν σε όλα τα παραδείγματα που έχω ποστάρει :))

 

Επίσης, εφόσον μας έχουν αποκλείσει την ctype.h, φτιάχνω τη δική μου έκδοση του macro isdigit(), που το ονομάζω is_digit(). Και τέλος, φτιάχνω και μια συνάρτηση s_isnumber() η οποία επιστρέφει TRUE (μη μηδενική τιμή) αν το string περιέχει μονάχα αριθμητικούς χαρακτήρες (αλλιώς FALSE).

 

>
#include <stdio.h>
#include <stdlib.h>								// για το atoi()

#define MAX_INPUTLEN	255
#define is_digit(c)	( (c) >= '0' && (c) <= '9' )

// ------------------------------------------------------------------------------------
// Διαβάζει μέχρι len-1 χαρακτήρες από το πληκτρολόγιο, μηδενίζει τον len-οστο
// και τους αποθηκεύει στο string s
//
char *s_get(char *s, size_t len)
{
       char *cp;
       for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
               ;								// for-loop με κενό σώμα
       *cp = '\0';								// μηδενισμός τελικού χαρακτήρα

       return s;
}

// ------------------------------------------------------------------------------------
// Επιστρέφει TRUE αν όλοι οι χαρακτήρες του string s είναι αριθμοί, αλλιώς FALSE
//
int s_isnumber(const char *s)
{
if ( !s )
	return 0;

register char *cp;
for (cp=s; *cp && is_digit(*cp); cp++)
	;

return (*cp && cp != s);
	
}

// ------------------------------------------------------------------------------------
int main( void )
{
int i,j, pin[2][3];
char s[MAX_INPUTLEN] = "";

// Είσοδος
for(i=0;i<2;i++)
{
	for(j=0;j<3;j++)
	{
		printf("Dwste noymero gia th thesh [%d][%d]: ", i,j);
		s_get(s, MAX_INPUTLEN);
		while ( !s_isnumber(s) )
		{
			printf("\tden dwsate noymero, janadokimaste: ");
			s_get(s, MAX_INPUTLEN);
		}
		pin[i][j] = atoi(s);		// μετατρέπει το s σε integer
	}
}

putchar('\n');

// Έξοδος
for(i=0; i<2; i++)
	for(j=0; j<3; j++)
		printf("[%d] [%d] %d\n",i,j,pin[i][j]);

putchar('\n');

printf("pathste ENTER gia termatismo...");
fflush(stdin); getchar();

exit(0);
}

Δημοσ.

Παιδιά με την ctype πως θα το κάνω; Ποιος θα είναι ο κώδικας;

Μπορείς να χρησιμοποιήσεις την isdigit της ctype.h η οποία επιστρέφει μηδέν σε περίπτωση μη αριθμητικού χαρακτήρα. Από εκεί και πέρα λοιπόν με την βοήθεια ενός for ή while loop (ειδικά σε περίπτωση που παίζεις με δείκτες) μπορείς να εξετάσεις τους χαρακτήρες που εισήγαγε ο χρήστης στο πρόγραμμα διακόπτοντας στον πρώτο μη αριθμητικό χαρακτήρα και ζητώντας εκ νέου εισαγωγή.

 

Ακολουθεί ένα απλό παράδειγμα (δοκιμασμένο σε C++ Builder 2009) το οποίο λύνει το ζήτημα είτε με την ctype (αν ορίσεις το _USE_CTYPE ως #define) είτε δίχως αυτή.

 

>
#include <stdio.h>

#define _USE_CTYPE

#ifdef _USE_CTYPE
#include <ctype.h>
#endif

int main(void)
{
int i,j, pin [2][3];
char c, szNum[bUFSIZ] = "";

/* CType version? */
#ifdef _USE_CTYPE
printf("CTYPE VERSION\n");
#endif

for(i=0;i<2;i++)
	for(j=0;j<3;j++)
	{

		/* Loop until valid number */
		while(1)
		{
               char *ptrNum, cBadInput = 0;
			printf("Dose noymero\n");
			/* Read stdin, up to BUFSIZ, into szNum buffer (returns ptr. to szNum) */
			ptrNum = fgets(szNum, BUFSIZ, stdin);
			/* Remove trailing \n from szNum (if szNum not NULL) */
			while(ptrNum && *ptrNum)
				if(*ptrNum == '\n' && !*(ptrNum + 1))
				{
					*ptrNum = 0;
					break;
				}
				else ptrNum++;
			/* Empty string? */
			if(!szNum[0])
				continue; /* Yes, redo input! */
               /* Get a pointer to szNum buffer */
			ptrNum = (char*)szNum;
			/* Check each ptrNum chr. for not been a numeric and if so stop! */
			while(ptrNum && *ptrNum)
			{

				#ifdef _USE_CTYPE	/* CType depended version */
				if(!isdigit(*ptrNum))
				{
					cBadInput = 1;
					break;
				}
				#else				/* Plain stdio.h version */
				if(*ptrNum < '0' || *ptrNum > '9')
				{
					cBadInput = 1;
					break;
				}
				#endif

				ptrNum++;
			}
			/* Good input? */
			if(cBadInput)
				printf(" Bad input - %s\n", szNum);
			else
				/* Works like scanf but instead of stdin uses szNum */
				if(!sscanf(szNum, "%d", &pin[i][j]))
					printf(" Invalid input - %s\n", szNum); /* Ooops! */
				else break;
		}

		if(pin[i][j] == c)
			printf("Akyro\n");
	}

   printf("\n");
for(i=0;i<2;i++)
	for(j=0;j<3;j++)
		printf("[%d] [%d] %d\n",i,j,pin[i][j]);

printf("\nPress Enter to exit..");
getchar();
return 0;
}

 

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

 

Υ.Γ.

Αν σε δυσκολεύουν οι pointers μπορεί να υλοποιηθεί και δίχως αυτούς.

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

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

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