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

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

Δημοσ.

Υπάρχει κάνα θέμα εδω με την goto ?

Υπάρχει θέμα ναι. Στις γλώσσες που παρέχουν loops η χρήση του goto αντί για loop θεωρείται και είναι bad-practice.

  • Απαντ. 1,6k
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.

Υπάρχει θέμα ναι. Στις γλώσσες που παρέχουν loops η χρήση του goto αντί για loop θεωρείται και είναι bad-practice.

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

 

Η κλασική χρήση της goto σε error handling έχει ως αποτέλεσμα πιο ευανάγνωστο κώδικα.

>
f1 = fopen(blah);
if (f1 == NULL) {
  printf("src file error\n");
  return -1;
}

f2 = fopen(blah);
if (f2 == NULL) {
  printf("dest file error\n");
  fclose(f1);
  return -2;
}

buf = malloc(blah);
if (buf == NULL) {
  printf("no memory\n");
  fclose(f2);
  fclose(f1);
  return -3;
}

 

>
f1 = fopen(blah);
if (f1 == NULL) {
  printf("src file error\n");
  err = -1;
  goto err1;
}

f2 = fopen(blah);
if (f2 == NULL) {
  printf("dest file error\n");
  err = -2;
  goto err2;
}

buf = malloc(blah);
if (buf == NULL) {
  printf("no memory\n");
  err = -3;
  goto err3;
}

err3:
   fclose(f2);
err2:
   fclose(f1);
err1:
   return err;

 

Επίσης βοηθάει να αποφύγουμε το πολύ nesting από loops και ifs.

Ένας μπακάλικος κανόνας λέει "όλα τα goto να πηγαίνουν προς μία κατεύθυνση" όπως στο παραπάνω error handling παράδειγμα.

Δημοσ.

...

Συμφωνώ ότι καλό είναι να αποφεύγεται αλλά αυτό όμως δεν σημαίνει ότι η goto είναι πάντα κακή πρακτική και δεν πρέπει να χρησιμοποιείται ποτέ.

...

Για αυτό έγραψα πως θεωρείται και είναι bad-practice όταν χρησιμοποιείται αντί για loops (και όχι γενικώς και πάντα).

 

EDIT:

 

Οι 2 βασικές, θεμιτές, χρήσεις της goto είναι αυτή που έγραψες για το error-handling καθώς επίσης και για να σπας (break) τη ροή μέσα από nested loops όταν δεν θες να τερματίσει η συνάρτηση/πρόγραμμα (μιας και η γλώσσα δεν παρέχει άλλον τρόπο).

Δημοσ.

θένξ γκάιζ B)

 

Με αφορμη αυτην εδω την άσκηση -> http://www.insomnia.gr/topic/437533-%CE%B5%CF%81%CF%89%CF%84%CE%AE%CF%83%CE%B5%CE%B9%CF%82-%CE%B3%CE%B9%CE%B1-c/page__st__220

 

σκέφτηκα μια υλοποιηση με συναρτήσεις. Επειδη το να βάλεις και εισοδο και επεξεργασια σε μια συναρτηση νομιζω ειναι άσχημο παραφουσκωνοντας την σκεφτηκα να το σπάσω σε 2... μια συναρτηση για γέμισμα και αλλη μια για επεξεργασια αλλα αν δωσω πχ Hello man μου το βγάζει ακριβως έτσι Hello man ενω θα επρεπε man Hello. Η ανάλυση του κώδικα έχει γινει σε προηγούμενες σελιδες και εννοειται πως γνωριζω τι υλοποιούν αμφότερες οι phras_rev και phrase_fill .

 

>

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#define MAXLEN        (200+1)

void phrase_rev( char []);
void phrase_fill( char [] , int );

int main( void )
{
       char input[ MAXLEN ] = {'\0'};

       printf(" Give a sentence: ");
       
       phrase_fill(input , MAXLEN );
       phrase_rev(input);
       
      return 0;
}
void phrase_fill( char input[] , int len)
{
char c  ;
   int i ;
   
   for (i=0; i < len-1 && '\n' != (c = getchar()) && c != '.' && c != '?'; i++)
               input[i] = c;
               
       input[i] = '\0';
       
       return ;
}

void phrase_rev( char input[])
{
int     i ;
   bool    onspace = false;
  // char c;

       printf(" The reversal of the sentence: ");
          
       for (i=0 ; i > -1; i--)
       {
               if ( isspace(input[i]) && !onspace ) {          /* on space-area        */
                       printf( "%s%c", &input[i+1] , input[i]);
                       input[i] = '\0';
                       onspace = true;
               }
               else if ( isspace( input[i] ) )                 /* space-area has >1 chars*/
                      putchar( input[i] );                     /* For two consecutive spaces*/
              else                                            /* on non-space area    */
                       onspace = false; 
       }
       printf("%s" , input );            // printf αντι της puts επειδη η τελευταία προσαρτά και έναν χαρακτήρα αλλαγής γραμμής.
      // putchar(c);
       
return ;
}

 

p.s Αμα ενοποιήσω τις 2 συναρτήσεις σε μια δουλεύει μια χαρα αλλα οπτικά και προγραμματιστικα πιστευω ειναι άσχημο.

Δημοσ.

>
void phrase_rev( char input[])
{
...       	
       for (i=0; i > -1; i--)
...       	

 

Ωπ σωστός.

 

Θέλει

 

> for (i= len-1 ; i > -1; i--) 

 

άρα και στην δήλωση του πρωτοτυπου πρέπει να αλλάξει σε

 

> void phrase_rev( char [] , int ); 

 

αλλα και στην κλήση

 

> phrase_rev(input , MAXLEN ); 

 

Αυτα για οποιον θελήσει να την χρησιμοποιήσει , να κάνει αυτες τις τροποποιήσεις

στον παραπάνω.

  • 3 εβδομάδες αργότερα...
Δημοσ. (επεξεργασμένο)

Καλησπέρα!

 

Υπάρχει περιπτωση οπου η σειρά των κλήσεων των συναρτήσεων μεσα στην main (αφου ηδη έχουν ορισθει ή δηλωθει πρωτυτερα) θα έχει σημασία / θα πρεπει να ειναι ορισμένη με κάποια σειρά?

 

>

#include <stdio.h>
void f2()
{
	printf(" Inside f2() ");
	
	return ;
}

void f1()
{
printf(" Inside f1() ");

return ;
}

void f3()
{
printf(" Inside f3() ");

return ;
}

int main( void )
{
f3();
f2();
f1();

return 0;
}

πιο πανω δεν υπάρχει σειρά στις κλήσεις ας πουμε. Υπαρχει ποτε περιπτωση το παραπανω να μην ειναι έγκυρο?

 

EDIT: Άκυρη η ερώτηση.

Επεξ/σία από Star_Light
Δημοσ.

Έχω βγει με άδεια απο το στρατο και έχω μαζέψει κάποιες απορίες :shock: μερικες ισως ειναι ανόητες .

 

Ελπιζω να βρεθει κανεις με υπομονη να κάνουμε συζήτηση. Έχω τα εξής :

 

1. Στην δηλωση μιας συναρτησης μπορεις να παραλείψεις τα ονοματα ενω στους ορισμους όχι. Αυτο γινεται επειδη στον ορισμο χρειάζεται να δεσμεύσεις καποιο formal parameter σε ενα συγκεκριμένο όνομα? Στις δηλώσεις αυτο ειναι optional.

 

2. O ορισμός μιας συνάρτησης δεσμεύει μνήμη τελικά?

 

3. Δεν μπορω οταν θέλω να χρησιμοποιήσω ενα compound literal να το βάλω μαζι με VLA's? σε εναν κωδικα που έγραψα χθες απο ενα σημειο και μετα (6-7 στοιχεια) μου κρασαριζε γιατι ????

 

> #include <stdio.h>
void table(int [] , int n );

int main( void )
{
int n;

printf(" Give n ");   // how many elements
scanf("%d" , &n);

table( (int [] ) { 0 } , n );

return 0;

}
void table(int a[] , int n)
{
int i;

for(i=0; i<n; i++)
{
scanf("%d" , &a[i]);
printf("%d" , a[i]);
}
return;

} 

 

4. Για την σελιδα 197 του King νομιζω δεν χρειάζεται να περνάς το μήκος του πίνακα μεσα στην συνάρτηση... δεν ειναι προαιρετικό?

 

> 
#include <stdio.h>
#define len 10
void table(int []);

int main( void )
{
int a[len];

table(a);

return 0;

}
void table(int a[])
{
int i;

for(i=0; i<len; i++)
{
scanf("%d" , &a[i]);
printf("%d" , a[i]);
}
return;

}

 

εγω το κανω και έτσι και μια χαρα μου παιζουν πάντως.

 

5. Χρειάζομαι ένα παραδειγματάκι για αυτο που λεει στην σελιδα 199

 

However no additional error-checking is performed ; it is still possible for any array argument to be too long or too short

 

Πως μπορει να ειναι too long το n σε εναν VLA που θα περάσω σαν argument στην συναρτηση μου? αφου το ελέγχω :/

 

Παντως εδώ ->

 

> #include <stdio.h>
void table( int , int [] );

int main( void )
{

int n
, a[n];

printf(" Give n ");
scanf("%d" , &n);

table( n , a );

return 0;
}

void table( int n , int a[n])
{
int i;

for(i=0; i<n; i++)
{
scanf("%d" , &a[i]);
printf(" %d " , a[i]);
}

return;
}

 

μου πέταξε stack smashing detected για buffer overflow :P

 

6. Στην 199 στον King λεει πως αν βάλεις πρωτο το int a[n] στον ορισμο σαν παραμετρο ειναι λάθος επειδη ο μεταγλωτιστης δεν έχει δει ακομη το n. Λογικα αυτο συμβαινει επειδη το n στην main ειναι διαφορετικό απο το n μεσα στην κεφαλίδα της συνάρτησης κατα τον ορισμό της αρα πρεπει να το ξαναδηλώσεις μεσα στο argument list.

 

Αυτα προς το παρον... ζαλαδίτσα :P οποιος έχει υπομονή τον ευχαριστω εκ των προτερων. ;)

Δημοσ.

VLA & compound literals δεν είναι συμβατά. Προσωπικώς τα αποφεύγω τα compound-literals, διότι περισσότερο μπερδεύουν παρά εξυπηρετούν (με κάποιες εξαιρέσεις).

Δες εδώ πλήρη ανάλυση: http://www.drdobbs.com/184401404

 

Για τα πρότυπα και τους ορισμούς, αν δεν βάλεις ονόματα στα ορίσματα όταν ορίζεις συναρτήσεις μετά πως θα τα χρησιμοποιήσεις μέσα στην συνάρτηση;

 

Τον King δεν ευκαιρώ να τον δω τώρα (πάντως για το 4, όντως δεν είναι υποχρεωτικό να περνάς το μέγιστο μήκος ως όρισμα... είναι όμως πιο δομημένο, είναι type-safe και άρα είναι λιγότερο error-prone).

Δημοσ. (επεξεργασμένο)

VLA & compound literals δεν είναι συμβατά. Προσωπικώς τα αποφεύγω τα compound-literals, διότι περισσότερο μπερδεύουν παρά εξυπηρετούν (με κάποιες εξαιρέσεις).

Δες εδώ πλήρη ανάλυση: http://www.drdobbs.com/184401404

 

Για τα πρότυπα και τους ορισμούς, αν δεν βάλεις ονόματα στα ορίσματα όταν ορίζεις συναρτήσεις μετά πως θα τα χρησιμοποιήσεις μέσα στην συνάρτηση;

 

Τον King δεν ευκαιρώ να τον δω τώρα (πάντως για το 4, όντως δεν είναι υποχρεωτικό να περνάς το μέγιστο μήκος ως όρισμα... είναι όμως πιο δομημένο, είναι type-safe και άρα είναι λιγότερο error-prone).

 

Οκ! Ευχαριστω.

 

Οποτε βρεις ευκαιρια με ενδιαφέρει το 5 ;)

 

edit: Το static που λεει στην σελιδα 200 παίζει για λογους ταχύτητας? ως προς την προσβαση των στοιχειων του πινακα και καλα το χεις χρησιμοποιησει ποτε ?

 

Το "prefetch" που πεταει σαν απαρέμφατο με μπερδεψε λολ. Προανακαλώ σημαινει και καλα?

Επεξ/σία από Star_Light
Δημοσ.

...

Παντως εδώ ->

 

 

> #include <stdio.h>
void table( int , int [] );

int main( void )
{

int n
, a[n];

printf(" Give n ");
scanf("%d" , &n);

table( n , a );

return 0;
}

void table( int n , int a[n])
{
int i;

for(i=0; i<n; i++)
{
scanf("%d" , &a[i]);
printf(" %d " , a[i]);
}

return;
}

 

 

μου πέταξε stack smashing detected για buffer overflow :P

...

Το n πρέπει να είναι γνωστό πριν το χρησιμοποιήσεις για να ορίσεις το VLA. Στον κώδικά σου δεν είναι.

 

 

 

ΥΓ. Πες με σπαστικό αλλά προσωπικά είναι εξαιρετικά απίθανο να απαντήσω ξανά σε αστοίχιστο κώδικα

 

 

Δημοσ.

Έχεις δίκιο.

 

Τώρα ειναι εντάξει?

 

>
#include <stdio.h>
void table( int , int [] );

//----------------------------------------------------------------------
int main( void )
{

int n;

printf(" Give n ");
scanf("%d" , &n);

int a[n];

table( n , a );

return 0;
}

//----------------------------------------------------------------------
void table( int n , int a[n])
{
int i;

for(i=0; i<n; i++)
{
scanf("%d" , &a[i]);
printf(" %d " , a[i]);
       }

} 

//----------------------------------------------------------------------

 

Τελικα τι εννοει με το οτι δεν γινεται καποιος έξτρα έλεγχος? εδω πχ δεν ειναι αρκετο που το loop κοβεται ενα στοιχειο πριν το n ? Τι μπορει να προκυψει σαν πιο long που λεει too long πχ. Δεν μπορω να σκεφτω κατι τωρα. :/

Δημοσ.

...

Τελικα τι εννοει με το οτι δεν γινεται καποιος έξτρα έλεγχος? εδω πχ δεν ειναι αρκετο που το loop κοβεται ενα στοιχειο πριν το n ? Τι μπορει να προκυψει σαν πιο long που λεει too long πχ. Δεν μπορω να σκεφτω κατι τωρα. :/

Υποθέτω εννοεί πως αν το VLA δημιουργηθεί με π.χ. n=10 και την συνάρτηση την καλέσεις με n=20 δεν θα κάνει error-checking. Δεν ξέρω κιόλας και βαριέμαι τώρα να διαβάζω το βιβλίο :P

Δημοσ.

Υποθέτω εννοεί πως αν το VLA δημιουργηθεί με π.χ. n=10 και την συνάρτηση την καλέσεις με n=20 δεν θα κάνει error-checking. Δεν ξέρω κιόλας και βαριέμαι τώρα να διαβάζω το βιβλίο :P

 

Αυτο πως μπορει να γινει στον κώδικα που έδωσα? :S

Αυτο μπορει να γινει οταν οριζεις σταθερα με το define στην αρχη

και ξεπερασεις αυτην.

 

Το βιβλίο γράφει αυτο ->

 

Variable length array parameters with a single dimension - as in all our examples so far - have limited usefulness. They make a function declaration or definition more descriptive by stating the desired length of an array argument. However , no additional error - checking is performed; it's still possible for an array argument to be too long or too short.

Δημοσ.

Το βιβλίο γράφει αυτο ->

 

Variable length array parameters with a single dimension - as in all our examples so far - have limited usefulness. They make a function declaration or definition more descriptive by stating the desired length of an array argument. However , no additional error - checking is performed; it's still possible for an array argument to be too long or too short.

Οπότε μάλλον εννοεί αυτό που έγραψα πριν.

 

Αυτο πως μπορει να γινει στον κώδικα που έδωσα? :S

Αυτο μπορει να γινει οταν οριζεις σταθερα με το define στην αρχη

και ξεπερασεις αυτην.

Στον κώδικα που έσωσες μπορεί να γίνει αν αλλάξεις την τιμή του n πριν την περάσεις ως όρισμα στην συνάρτηση table().

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

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