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

C --> Πόσες φορές εμφανίζεται ένας χαρακτήρας


Penthesilea

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

  • Απαντ. 35
  • Δημ.
  • Τελ. απάντηση
Δημοσ.

Ε, αυτό είναι άλλο πράγμα! Εκεί αλλάζεις τον ορισμό του πίνακα, εγώ μιλούσα για invalid παράμετρο, όχι για invalid ορισμό του freq.

 

Πάντως, κι αυτό λύνεται, πρόσθεσε ένα ακόμα sanity check κάτω από τα υπάρχοντα, στις 2 συναρτήσεις...

 

>
if ( freqmaxlen < FREQ_MAXLEN )			/* sanity check   */
	return 0;				/* ... early exit */

 

ΥΓ1. Πάω να το βάλω και στον προηγούμενο κώδικα :)

 

ΥΓ2. Το έβαλα! Τώρα επιστρέφει άμεσα σφάλμα, αλλά αν θέλουμε μπορούμε στο 2ο αυτό sanity check να βάζουμε το freqmaxlen να παίρνει την ελάχιστη τιμή μεταξύ του εαυτού του και του FREQ_MAXLEN.

 

ΥΓ3. @ts: οι απλές λύσεις είναι στην 1η σελίδα ;)

 

 

 

Τωρα εχεις μια παραμετρο που αν ειναι κατω απο 10, ή πανω απο 10 τοτε ο αλγοριθμος δεν θα δουλεψει (if maxfreq != 10 then fail). Τεσπα το point μου ειναι:

@mig too much. Ανεβαζεις την πολυπλοκοτητα χωρις λογο, με αποτελεσμα να κανεις λογικα λαθη

Δημοσ.

...

ΥΓ2. Το έβαλα! Τώρα επιστρέφει άμεσα σφάλμα, αλλά αν θέλουμε μπορούμε στο 2ο αυτό sanity check να βάζουμε το freqmaxlen να παίρνει την ελάχιστη τιμή μεταξύ του εαυτού του και του FREQ_MAXLEN.

...

 

>
#define myMIN(x,y)	( (x) < (y) ? (x) : (y) )

/* ----------------------------------------------------------------------------------- */
int analyze( const char *str, unsigned short int freq[], int freqmaxlen )
{
register int len = 0, ifreq = 0;
							/* sanity checks  */
if ( !str || !freq || freqmaxlen < 0 || freqmaxlen > FREQ_MAXLEN )
	return 0;					/* ... early exit */

//	if ( freqmaxlen < FREQ_MAXLEN )
//		return 0;
freqmaxlen = myMIN( freqmaxlen, FREQ_MAXLEN );

memset(freq, 0, freqmaxlen * sizeof(unsigned short int) );

for (len=0; *str; str++,len++)
	if ( isdigit( *str ) && (ifreq = (int)(*str - '0')) < freqmaxlen )
		freq[ ifreq ]++;

return len;
}
/* ----------------------------------------------------------------------------------- */
int print_freqs( const unsigned short freq[], int freqmaxlen )
{
register int i = 0;
						/* sanity checks  */
if ( !freq || freqmaxlen < 0 || freqmaxlen > FREQ_MAXLEN )
	return 0;	/* FALSE */		/* ... early exit */

//	if ( freqmaxlen < FREQ_MAXLEN )			/* sanity check   */
//		return 0;				/* ... early exit */
freqmaxlen = myMIN( freqmaxlen, FREQ_MAXLEN );

for (i=0; i < freqmaxlen; i++)
	printf("digit %d found %u times\n", i, freq[i] );

return 1;		/* TRUE  */
}

και προφανώς έχει φύγει και το const μπροστά από το freqmaxlen στις λίστες παραμέτρων των 2 συναρτήσεων. Με αυτό τον το freq μετράει και τυπώνει μονάχα όσα ψηφία επιτρέπει το μέγεθος του freq[] ... π.χ. αν το μέγεθος είναι 4, θα μετρήσεις συχνότητες μονάχα για τα 0,1,2,3 και ούτω κάθε εξής... εδώ όμως όντως γίνεται πολύπλοκη η analyze(), αφού θέλει κι έξτρα μεταβλητή ( ifreq ) κι έξτρα έλεγχο στο for-loop της για να μη κάνει overflow τον freq[] με ψηφία μεγαλύτερου του πληθάριθμού του.

 

Τωρα εχεις μια παραμετρο που αν ειναι κατω απο 10, ή πανω απο 10 τοτε ο αλγοριθμος δεν θα δουλεψει (if maxfreq != 10 then fail). Τεσπα το point μου ειναι:

Ναι, την ώρα που έγραφες πόσταρα πως μπορείς να το κάνεις να δουλεύει με maxfreq < 10 safely (αλλά προφανώς incompletely)!

 

Το ότι δεν δουλεύει ο αλγόριθμος με maxfreq != 10 αν βάλεις το 2ο sanity check, είναι πλήρως αποδεκτή επιλογή αν είναι να μη κρασάρει το πρόγραμμα σου σε invalid input. Η όλη ιστορία έγινε για το safety εξαρχής. Βασικά είναι στο χέρι του προγραμματιστή αν και τι trade-off θα κάνει μεταξύ ασφάλειας και λειτουργικότητας... η πολυπλοκότητα είναι 2ο στάδιο, ανάλογα με την επιλογή που θα κάνει στο 1ο στάδιο.

 

ΥΓ. Το 2ο sanity-check το άφησα σε σχόλια, γιατί μπορεί να επιλέξεις το myMIN να το βάλεις μέσα στο κυρίως σώμα του sanity check, αντί για return.

Δημοσ.

 

αφού θέλει κι έξτρα μεταβλητή ( ifreq ) κι έξτρα έλεγχο στο for-loop της για να μη κάνει overflow τον freq[] με ψηφία μεγαλύτερου του πληθάριθμού του.

Πω πω αυτη η τσιγκουνια σου στις μεταβλητες ΔΕΝ περιγραφεται happy.gif

Ναι, την ώρα που έγραφες πόσταρα πως μπορείς να το κάνεις να δουλεύει με maxfreq < 10 safely (αλλά προφανώς incompletely)!

Αυτο σου λεω απο την αρχη "πολυπλοκοτητα = λαθη"

Η όλη ιστορία έγινε για το safety εξαρχής. Βασικά είναι στο χέρι του προγραμματιστή αν και τι trade-off θα κάνει μεταξύ ασφάλειας και λειτουργικότητας... η πολυπλοκότητα είναι 2ο στάδιο, ανάλογα με την επιλογή που θα κάνει στο 1ο στάδιο.

 

Γνωμη μου, στη C πρεπει να λαβεις αυτο το παραγοντα στα σοβαρα. Σε αλλη περιπτωση, για το παραπανω θα επρεπε να το περασεις απο τον debugger για καμια ωρα, επειδη υπαρχουν bugs που δεν τα βλεπει ουτε εσυ αλλα ουτε και ο compiler (Θα σου γραψω ενα).

 

 

Δημοσ.

 

αφού θέλει κι έξτρα μεταβλητή ( ifreq ) κι έξτρα έλεγχο στο for-loop της για να μη κάνει overflow τον freq[] με ψηφία μεγαλύτερου του πληθάριθμού του.

Πω πω αυτη η τσιγκουνια σου στις μεταβλητες ΔΕΝ περιγραφεται happy.gif

Ναι, την ώρα που έγραφες πόσταρα πως μπορείς να το κάνεις να δουλεύει με maxfreq < 10 safely (αλλά προφανώς incompletely)!

Αυτο σου λεω απο την αρχη "πολυπλοκοτητα = λαθη"

Η όλη ιστορία έγινε για το safety εξαρχής. Βασικά είναι στο χέρι του προγραμματιστή αν και τι trade-off θα κάνει μεταξύ ασφάλειας και λειτουργικότητας... η πολυπλοκότητα είναι 2ο στάδιο, ανάλογα με την επιλογή που θα κάνει στο 1ο στάδιο.

 

Γνωμη μου, στη C πρεπει να λαβεις αυτο το παραγοντα στα σοβαρα. Σε αλλη περιπτωση, για το παραπανω θα επρεπε να το περασεις απο τον debugger για καμια ωρα, επειδη υπαρχουν bugs που δεν τα βλεπει ουτε εσυ αλλα ουτε και ο compiler (Θα σου γραψω ενα).

 

 

Δημοσ.

Πω πω αυτη η τσιγκουνια σου στις μεταβλητες ΔΕΝ περιγραφεται happy.gif

Χεχε, είναι αλήθεια αυτό, προδίδει την ηλικία μου και τις καταβολές μου (το μινιμαλιστικό στυλ γραφής είναι χαρακτηριστικό των προγραμματιστών της C).

 

Αυτο σου λεω απο την αρχη "πολυπλοκοτητα = λαθη"

 

 

Γνωμη μου, στη C πρεπει να λαβεις αυτο το παραγοντα στα σοβαρα. Σε αλλη περιπτωση, για το παραπανω θα επρεπε να το περασεις απο τον debugger για καμια ωρα, επειδη υπαρχουν bugs που δεν τα βλεπει ουτε εσυ αλλα ουτε και ο compiler (Θα σου γραψω ενα).

Κι αυτό είναι αλήθεια! Το τίμημα του να προγραμματίζει κανείς σε C (ριχτο, να το φτιάξουμε κι αυτό :) )

Δημοσ.

Προσοχη! τεραστιος κωδικας.

 

>int main(int ,char**)
{
int i = 0;
int arr[4] = { 0 };
for(i = 0; i < 7 ; i++)
	arr[i] = 1;
return 0;}

 

 

Τι είν' τούτο, ωρέ; :lol:

κλασικό buffer overflow είναι αυτό. Ο κλασικός τρόπος αποφυγής τους στη C είναι με ορισμό ενός #define για τον πληθάριθμο του arr, και χρήση του #define από εκεί και πέρα για οποιαδήποτε αναφορά σε αυτόν...

 

 

 

>
#define ARR_MAXLEN        10   // ο πληθάριθμος του πίνακα arr
int main( void )
{
   int i = 0, arr[ ARR_MAXLEN ] = {0};

   for (i=0; i < ARR_MAXLEN; i++)
       arr[i] = 1;

   return 0;
}

 

 

Δημοσ.

Κοίτα, καταρχήν η άσκηση αναφέρει ρητώς ως δεδομένο πως το string περιέχει μόνο ψηφία. Έπειτα, οι υλοποιήσεις που δώσαμε, συνειδητά δεν ήταν συναρτήσεις (τουλάχιστον σε ότι αφορά εμένα) μιας και η εκφώνηση δεν ζητάει συνάρτηση επί τούτου. Αν ήταν να το κάνουμε με συνάρτηση, τότε έχουμε πολλά περισσότερα να σκεφτούμε και να ελέγξουμε εκτός του isdigit(). Π.χ. ο πίνακας freq[] θα είναι καθολικός ή θα περνάει σαν όρισμα στη συνάρτηση; Ακόμα, τι γίνεται αν το string περαστεί ως NULL; Επίσης, αν το κάνουμε συνάρτηση, δεν χρειαζόμαστε καθόλου τον δείκτη p.

 

Δεν είναι ανάγκη να είμαστε τόσο υπερβολικοί όπως είπε και το παπί, για τις ανάγκες του εγχειρήματος (άσκηση προγραμματισμού) αρκεί να πάρουμε μερικές λογικές αποφάσεις και το τελικό αποτέλεσμα να (θα το πω με δικά μου λόγια) να μπορείς να πεις ότι είναι μια καλή προσπάθεια. Δε ζητάμε να μας φτιάξει application framework.

 

Απλώς για μένα το να μην κρασάρει όταν του δώσεις κάποιο διαφορετικό (ούτε καν malicious) input εννοείται πάντα, άσχετα από το τι λέει η εκφώνηση.

Δημοσ.

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

 

Ζημιώνεται κάποιος από αυτήν σε ενημερωτικό επίπεδο;

 

Εγώ νομίζω πως όποιος έχει τον χρόνο και το κέφι να συμμετέχει ή έστω απλά να διαβάζει μόνο κέρδος θα έχει.

Δημοσ.

Στην αρχή ήμουν έτοιμος να απαντήσω... αλλά σκέφτηκα ότι "Ασ' το τώρα, έχεις άλλα που προηγούνται"

 

Μετά, δεν κρατιόμουν και είπα να κάνω χαβαλέ για να μην κάτσω να το σκεφτώ και απαντήσω τελικά... (όπου και το μήνυμα παραπάνω, και δεν ήταν απαξίωση :) )

 

Εν τέλει... (να σας πάρει η ευχή :P ) η δική μου λύση για τα ζητούμενα της άσκησης:

 

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

int main(int argc, char** argv) {

   unsigned int freq[10] = { 0 };
   unsigned int indx;
   int c;

   while( ((c = getchar()) != '\n') && (c > 47) && (c < 58) )
   {
       freq[c-48]++;
   }

   for( indx = 0; indx < 10; indx++){
       printf("%d", freq[indx]);
   }

   return (EXIT_SUCCESS);
}

 

Χμ.. μόλις είδα ότι ξέχασα το πλήθος. Μπορεί να γίνει με την προσθήκη στο body της main του:

 

unsigned int theCounter = 0;

 

Και μέσα στο block του while του:

theCounter++;

Δημοσ.

Στην αρχή ήμουν έτοιμος να απαντήσω... αλλά σκέφτηκα ότι "Ασ' το τώρα, έχεις άλλα που προηγούνται"

 

Μετά, δεν κρατιόμουν και είπα να κάνω χαβαλέ για να μην κάτσω να το σκεφτώ και απαντήσω τελικά... (όπου και το μήνυμα παραπάνω, και δεν ήταν απαξίωση :) )

 

Εν τέλει... (να σας πάρει η ευχή :P ) η δική μου λύση για τα ζητούμενα της άσκησης:

 

 

 

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

int main(int argc, char** argv) {

   unsigned int freq[10] = { 0 };
   unsigned int indx;
   int c;

   while( ((c = getchar()) != '\n') && (c > 47) && (c < 58) )
   {
       freq[c-48]++;
   }

   for( indx = 0; indx < 10; indx++){
       printf("%d", freq[indx]);
   }

   return (EXIT_SUCCESS);
}

 

 

Θα ήταν μια χαρά λύση, αν η εκφώνηση δεν ζήταγε συμβολοσειρά :)

 

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

 

Αν τη θέλουμε σε ολοκληρωμένο πρόγραμμα, τότε κάτι σαν αυτό...

 

>
#include <stdio.h>

int main( void )
{
char str[] = "0369345608754609806970110978654", *cp = str;
unsigned short freq[10] = { 0 }, i = 0;

for (; *cp; cp++)
	freq[ (int)(*cp -'0') ]++;

printf("\"%s\" contains %d digits\n", str, (int)(cp-str) );

for (; i < 10; i++)
	if ( freq[i] )
		printf("\tdigit %u : %u times\n", i, freq[ i ] );

return 0;
}

 

Έξοδος:

>
"0369345608754609806970110978654" contains 31 digits
digit 0 : 6 times
digit 1 : 2 times
digit 3 : 2 times
digit 4 : 3 times
digit 5 : 3 times
digit 6 : 5 times
digit 7 : 3 times
digit 8 : 3 times
digit 9 : 4 times

Δημοσ.

Μα την συμβολοσειρά την παίρνεις από τον χρήστη. Το εάν σου επιστρέφει το "νουμερικό" αντίστοιχο η getchar γιατί να έχει σημασία;

 

Ούτως η άλλως, η μόνη διαφορά από τον νέο σου κώδικα με τον δικό μου είναι ότι παίρνεις predefined την "είσοδο" :P

Δημοσ.

Μα την συμβολοσειρά την παίρνεις από τον χρήστη. Το εάν σου επιστρέφει το "νουμερικό" αντίστοιχο η getchar γιατί να έχει σημασία;

Τυπικά το "συμβολοσειρά" (string) παραπέμπει σε πίνακα χαρακτήρων ή έστω έτσι πιστεύω :)

 

Ούτως η άλλως, η μόνη διαφορά από τον νέο σου κώδικα με τον δικό μου είναι ότι παίρνεις predefined την "είσοδο" :P

Συν ότι δεν ελέγχω για μη ψηφία στο string, συν ότι δεν τυπώνω συχνότητες ψηφίων που δεν υπάρχουν στο string :)

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

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

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