ΚΕΦΑΛΑΙΟ 7 - ΟΡΙΣΜΑΤΑ ΤΗΣ ΜΑΙΝ

...ασύγχρονα μαθήματα γλώσσας C

ΚΕΦΑΛΑΙΟ 7 - ΟΡΙΣΜΑΤΑ ΤΗΣ ΜΑΙΝ

Δημοσίευσηαπό linuxs » 15 Μαρ 2011, 23:36

ΚΕΦΑΛΑΙΟ 7 - Ορίσματα της main

τι περιέχει αυτό το κεφάλαιο...
Όπως είχαμε πεί και στην εισαγωγή η main δεν είναι τίποτα άλλο απο μια συνάρτηση. Γνωρίζουμε οτι κάθε συνάρτηση παίρνει ορίσματα, έτσι και η main μπορεί να παρει ορίσματα με λίγο διαφορετικό τρόπο. Δεν θα έλεγα οτι είναι δύσκολος αλλα λίγο διαφορετικός! Καταρχήν τα ορίσματα αυτά θα τα δώσουμε απο το τερματικό απο όπου και θα εκτελέσουμε το πρόγραμμά μας. Τώρα, τα ορίσματά της είναι τα: argc, argv[].

Το argc είναι ένας ακέραιος και το argv[] ένας πίνακας. Δεν επιτρέπεται να βάλετε κάτι άλλο όπως μια μεταβλητή που έχετε στο πρόγραμμα. Ότιδήποτε θέλετε να περάσετε στο πρόγραμμα θα το περνάτε μέσω argv[]. Πως? Σκεφτείτε οτι το argv είναι πίνακας και έτσι μπορείτε σε κάθε κελί να έχετε και μια μεταβλητη-όρισμα! Ας δούμε τώρα πως μπορεί κάποιος να το κάνει.

Αντί να γράφετε στον κώδικα σας,
Κώδικας: Επιλογή όλων
main(){
...
}

θα πρέπει να βάζετε και τα ορίσματα της main ώς εξής,
Κώδικας: Επιλογή όλων
main(int argc, char *argv[]){
...
}

ή
Κώδικας: Επιλογή όλων
main(int argc, char argv[][]){
...
}

Προτιμήστε τον πρώτο τρόπο! ;)


Ας δούμε τώρα αναλυτικά τί είναι το καθένα...
Κώδικας: Επιλογή όλων
argc: Η μεταβλητή αυτή είναι ίση με τα ορίσματα που έχουμε δώσει.


Για παράδειγμα,
Κώδικας: Επιλογή όλων
argc = 5 -> a.out 32 koutia ston aera


Κώδικας: Επιλογή όλων
argc = 7 -> a.out 2 kai 3 mas kanei 5


Κώδικας: Επιλογή όλων
argc = 3 -> a.out 4 5


Κώδικας: Επιλογή όλων
argv[ ]: Δείτε στον παρακάτω πίνακα.


έστω οτι δίνουμε, a.out manolis 32 poulia , γραφικά μπορούμε να το σχηματίσουμε κάπως έτσι:
Off topic:
Κανονικά το παρακάτω θα πρέπει να εμφανιστεί σε πίνακα, αλλα τέλοςπάντων. Μόλις μάθω θα το φτιάξω! Υπομονή..

argc = 6
argv[0] = ./a.out
argv[1] = manolis
argv[2] = 32
argv[3] = pouli

σαν έναν πίνακα δηλαδή που για να προσπελάσουμε ένα κελί χρησιμοποιούμε το όνομα του πίνακα και τον αριθμό του κελιού όπως, πχ argv[2], argv[5], argv[0].


για παράδειγμα,
Κώδικας: Επιλογή όλων
/* How to use argc, argv[ ] */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
printf("argc: %d\n", argc);
printf("argv[0]: %s\n", argv[0]);
printf("argv[1]: %s\n", argv[1]);
printf("argv[2]: %s\n", argv[2]);
return 0;
}


κάντε compile και τρέξτε το παραπάνω πρόγραμμα δίνοντας μαζί με το a.out κάποια ορίσματα χωρισμένα με space όπως,

Κώδικας: Επιλογή όλων
a.out 32 koutia me 10 mpales


ΣΥΧΝΟ ΛΑΘΟΣ: Εάν χρησιμοποιείσετε σωστά τα argc, argv[ ], κάνετε compile και μετά δώσατε την εντόλη a.out ή ./a.out θα έχετε την εξής συνέπεια: Segmentation Fault! Γιατί? Γιατί, θα πρέπει να κάνετε κάτι σαν το παρακάτω:

Κώδικας: Επιλογή όλων
a.out manolis 32 poulia ston aera ή ./a.out manolis 32 poulia ston aera


θα έπρεπε δηλαδή να βάλετε και ορίσματα μετά το a.out ή ./a.out.

Έλεγχος

Δεν είναι απαραίτητος αλλα καλό είναι να τον βάζουμε στην αρχή του προγράμματος μας! Σε περίπτωση που γίνουν όλα σωστά δεν υπάρχει θέμα γιατί είναι όλα οκ! Σε περίπτωση όμως που κάνουμε κάποιο λάθος όπως να μην δώσουμε καθόλου ορίσματα τότε οκ θα πετάξει Segmentation fault αλλα είμαστε σίγουροι οτι είναι απο αυτό και όχι απο κάτι άλλο? Προφανώς οχι!!! Και ή λύση είναι σε κάποιο σημείο στην αρχή του προγράμματτος μας βάζουμε τον εξής κώδικα:

Κώδικας: Επιλογή όλων
if(argc != 2){
        printf("Error in argv!\n");
        exit(1);
}

Δεν είναι ο μόνος έλεγχος που μπορεί να γίνει!

Έτσι μπορούμε να εξετάουμε αν η είσοδος είναι διαφορετική απο δύο! Δηλαδή, αν εκτός το ./a.out που πληκτρολογήσαμε δώσαμε και άλλο ένα όρισμα. Σε περίπτωση που δώσαμε μόνο ένα όρισμα μετά του ./a.out θα συνεχίσει κανονικά ο κώδικας. Σε αντίθετη περίπτωση θα εκτυπωθεί ένα μύνημα σφάλματος. Για παράδειγμα αν θέλει κάποιος να δώσει οπωςδήποτε 4 ορίσματα θα έχει τον εξής έλεγχο:
Κώδικας: Επιλογή όλων
if(argc != 5){ /* 4 ορίσματα και ένα το ./a.out = 5 ορίσματα! */
        printf("Error in argv!\n");
        exit(1);
}


Χρήση της παραμέτρου
Κάποια στιγμή θα περάσουμε τον έλεγχο, οπότε θα έρθει η ώρα να χρησιμοποιήσουμε το όρισμα που δώσαμε! Σωστά? Ένα συχνό και πολύ δύσκολο να εντοπιστεί να δεν το γνωρίζει κάποιος είναι το εξής:
Εάν περάσετε μια παράμετρο πχ. 4 και μετά προσπαθήσετε να κάνετε x = argv[1] + 2; αυτό που θα περιμένατε είναι το 6. Δεν θα εμφανιστεί αυτό όμως!


Καταρχήν στο παραπάνω παράδειγμα, η πράξη που έκανα είναι απολύτως λογική γιατί στο argv[0](1ο κελί του πίνακα argv[]) βρίσκεται το "./a.out" και στην δεύτερη θέση το 4. Άρα ως πράξη είναι λογικη! Ο πίνακας όμως μέσα έχει strings. Τι σημαίνει αυτό? το 4 ναι μεν είναι ακέραιος αριθμός-integer αλλα στο πρόγραμμά μας έχει περαστεί ως string. Έτσι μόλις περάσουμε τον έλεγχο θα πρέπει να καταναλώσουμε άλλη μια γραμμή για να τον κάνουμε πάλι ακέραιο! Πώς? Με χρήση της συνάτησης atoi(). Η atoi έιναι μια συνάρτηση που επιστρέφει ένα ακέραιο! Όπως το 4 στο παραδειγμά μας! Χρησιμοποιείτε ως εξής:
Κώδικας: Επιλογή όλων
atoi(argv[number]); /* όπου Number θα βάλετε το νούμερο του πίνακα πχ. 1, 2, κτλ */

Στο συγκεριμένο παράδειγμα θα έπρεπε να χρησιμοποιήσουμε,
Κώδικας: Επιλογή όλων
int value;
value=atoi(argv[1]);


Έτσι έχουμε ως αποτέλεσμα η μεταβλητή value να περιέχει το όρισμα που δώσαμε που ήταν το 4!

-ΚΑΛΗ ΣΥΝΕΧΕΙΑ!!!- ΓΙΑ ΑΠΟΡΙΕΣ-ΕΡΩΤΗΣΕΙΣ-ΔΙΟΡΘΩΣΕΙΣ ΜΗΝ ΔΙΣΤΑΣΕΤΕ ΝΑ ΚΑΝΕΤΕ POST
Τελευταία επεξεργασία από linuxs και 14 Ιουν 2011, 16:57, έχει επεξεργασθεί 8 φορά/ες συνολικά
Αν το πρόβλημά μας επιλυθεί. Επιλέγουμε το θέμα που βοήθησε στην επίλυση και πατάμε το κουμπάκι Εικόνα.
Γνώσεις ⇛ Linux: Μέτριο┃Προγραμματισμός: C┃Αγγλικά: Καλά
Λειτουργικό ⇛ Linux Ubuntu 10.4 LTS
Προδιαγραφές ⇛ Intel Pentium @T4500 2.3GHz│ 512GB VRAM│ 500 HDD│ ATI RADEON HD545v 512 MB │ Screen: 15.6''
Άβαταρ μέλους
linuxs
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 1060
Εγγραφή: 02 Ιούλ 2010, 13:19
Τοποθεσία: GR
IRC: linuxs
Εκτύπωση

Re: Ανάλυση των παραμέτρων της main (C)

Δημοσίευσηαπό Tasos09 » 18 Μαρ 2011, 01:26

Καλό θα ήταν να αναφέρεις ότι είναι καλή προγραμματιστική συνήθεια ο έλεγχος του πλήθος των ορισμάτων, ώστε να αποφεύγονται ανεπιθύμητες καταστάσεις όπως το να σκάει το πρόγραμμα. Επίσης ότι τα στοιχεία είναι strings, οπότε για να χειριστούμε μία είσοδο ως ακέραιο θα πρέπει να γίνει χρήση της συνάρτησης atoi.

Off topic:
ΥΓ: Συμφοιτητής σου 8-)
Tasos09
babeTUX
babeTUX
 
Δημοσιεύσεις: 8
Εγγραφή: 22 Δεκ 2009, 16:32
Εκτύπωση

Re: Ανάλυση των παραμέτρων της main (C)

Δημοσίευσηαπό linuxs » 18 Μαρ 2011, 01:31

Tasos09 έγραψε:Καλό θα ήταν να αναφέρεις ότι είναι καλή προγραμματιστική συνήθεια ο έλεγχος του πλήθος των ορισμάτων, ώστε να αποφεύγονται ανεπιθύμητες καταστάσεις όπως το να σκάει το πρόγραμμα. Επίσης ότι τα στοιχεία είναι strings, οπότε για να χειριστούμε μία είσοδο ως ακέραιο θα πρέπει να γίνει χρήση της συνάρτησης atoi.

Off topic:
ΥΓ: Συμφοιτητής σου 8-)


Καλησπέρα! Είναι υπο-επεξεργασία το θέμα...όπως και τα υπόλοιπα! :P Αργά η γρήγορα όμως θα προσθέσω κι άλλα και σίγουρα αυτό που επισήμανες. :)
Αν το πρόβλημά μας επιλυθεί. Επιλέγουμε το θέμα που βοήθησε στην επίλυση και πατάμε το κουμπάκι Εικόνα.
Γνώσεις ⇛ Linux: Μέτριο┃Προγραμματισμός: C┃Αγγλικά: Καλά
Λειτουργικό ⇛ Linux Ubuntu 10.4 LTS
Προδιαγραφές ⇛ Intel Pentium @T4500 2.3GHz│ 512GB VRAM│ 500 HDD│ ATI RADEON HD545v 512 MB │ Screen: 15.6''
Άβαταρ μέλους
linuxs
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 1060
Εγγραφή: 02 Ιούλ 2010, 13:19
Τοποθεσία: GR
IRC: linuxs
Εκτύπωση

Re: ΚΕΦΑΛΑΙΟ 7 - ΟΡΙΣΜΑΤΑ ΤΗΣ ΜΑΙΝ

Δημοσίευσηαπό g1wrg0s » 25 Ιουν 2012, 10:32

H εντολη που γραφεις argv[1] +2 δεν θα επιστρεψει διευθυνση; και πιο συγκεκριμενα την διευθυνση του τριτου δεικτη του πινακα argv; Οχι το 4 ως αλφαριθμιτικο οπως αναφερεις ετσι δεν ειναι;
Spoiler: show
1 Γνώσεις Linux: Πρώτα βήματα ┃ Προγραμματισμού: Πρώτα βήματα ┃ Αγγλικών: Πρώτα βήματα
2 Ubuntu 12.10 quantal 3.10.20-031020-generic 32bit (el_GR.UTF-8, Unity ubuntu), Windows 8
3 Intel Core i5-3230M CPU @ 2.60GHz ‖ RAM 7923 MiB ‖ Acer VA50_HC_CR - Acer Aspire V3-571G
4 Intel 3rd Gen Core processor Graphics Controller [8086:0166] {i915} ⋮ nVidia Device [10de:0fe1] {}
5 eth0: Broadcom NetLink BCM57785 Gigabit Ethernet PCIe [14e4:16b5] (rev 10) ⋮ wlan0: Atheros Inc. AR9462 Wireless Network Adapter [168c:0034] (rev 01)
g1wrg0s
punkTUX
punkTUX
 
Δημοσιεύσεις: 196
Εγγραφή: 26 Μάιος 2012, 10:29
Εκτύπωση

Re: ΚΕΦΑΛΑΙΟ 7 - ΟΡΙΣΜΑΤΑ ΤΗΣ ΜΑΙΝ

Δημοσίευσηαπό migf1 » 25 Ιουν 2012, 19:42

g1wrg0s έγραψε:H εντολη που γραφεις argv[1] +2 δεν θα επιστρεψει διευθυνση; και πιο συγκεκριμενα την διευθυνση του τριτου δεικτη του πινακα argv; Οχι το 4 ως αλφαριθμιτικο οπως αναφερεις ετσι δεν ειναι;

Σωστά το αναφέρει ο οδηγός.

Για να μας επιστρέψει την διεύθυνση του 3ου string στον πίνακα *argv[] θα έπρεπε να γράφαμε...

Μορφοποιημένος Κώδικας: Επιλογή όλων
argv+2

Έστω ότι...

Μορφοποιημένος Κώδικας: Επιλογή όλων
char *strarr[] = { "1", "10", "100", "1000" }

τότε ισχύει (τα == στην αριστερή μεριά είναι συντμήσεις της 0 == strcmp(), δεξιά ισχύουν ατόφια) ...

*strarr == strarr[0] == "1" και strarr == &strarr[0]
*(strarr+1) == strarr[1] == "10" και (strarr+1) == &strarr[1]
*(strarr+2) == strarr[2] == "100" και (strarr+2) == &strarr[2]
*(strarr+3) == strarr[3] == "1000" και (strarr+3) == &strarr[3]

Ανεξάρτητα με αυτά, να συμπληρώσω πως ο *argv[] είναι πάντα NULL terminated, οπότε το παρακάτω δεν κρασάρει ποτέ...

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
while ( *argv )
puts( *argv++ );
exit( 0 );
}


Τέλος να συμπληρώσω και την ύπαρξη 3ου ορίσματος της main(), του char **envp, το οποίο δεν είναι στάνταρ C αλλά υποστηρίζεται από το runtime των περισσοτέρων δημοφιλών πλατφορμών (windows, posix > 1.x, mac-osx).

Όπως και το char **argv, έτσι κι αυτό είναι ένας NULL terminated πίνακας από strings, που περιέχει τις μεταβλητές περιβάλλοντος.

Δοκιμάστε π.χ. τον παρακάτω κώδικα...

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[], char *envp[] )
{
while ( *envp )
puts( *envp++ );
exit( 0 );
}
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: ΚΕΦΑΛΑΙΟ 7 - ΟΡΙΣΜΑΤΑ ΤΗΣ ΜΑΙΝ

Δημοσίευσηαπό g1wrg0s » 26 Ιουν 2012, 01:00

Ευχαριστω. Με τα δικα σου ποστ και με την αναδρομη σε ενα βιβλιο τα ξεκαθαρισα.
Οσο τα αφησεις , σε αφηνουν!
Spoiler: show
1 Γνώσεις Linux: Πρώτα βήματα ┃ Προγραμματισμού: Πρώτα βήματα ┃ Αγγλικών: Πρώτα βήματα
2 Ubuntu 12.10 quantal 3.10.20-031020-generic 32bit (el_GR.UTF-8, Unity ubuntu), Windows 8
3 Intel Core i5-3230M CPU @ 2.60GHz ‖ RAM 7923 MiB ‖ Acer VA50_HC_CR - Acer Aspire V3-571G
4 Intel 3rd Gen Core processor Graphics Controller [8086:0166] {i915} ⋮ nVidia Device [10de:0fe1] {}
5 eth0: Broadcom NetLink BCM57785 Gigabit Ethernet PCIe [14e4:16b5] (rev 10) ⋮ wlan0: Atheros Inc. AR9462 Wireless Network Adapter [168c:0034] (rev 01)
g1wrg0s
punkTUX
punkTUX
 
Δημοσιεύσεις: 196
Εγγραφή: 26 Μάιος 2012, 10:29
Εκτύπωση


Επιστροφή στο Μαθήματα C

cron