Εργαστήριο Τεχνολογίας Λογισμικού
+2 votes
408 views

Θέλω να δουλέψω με τα arguments που δίνονται στην main():

// Βρήκα ότι μας δίνεται το argv μια array απο strings. η αλλιως 2d array of chars.
int main(int argc, char *argv[]) 
{

    char *executable_path[] = argv[0]; // (Το πρώτο string ειναι απλα η τοποθεσία του προγράμματος)
    printf("The file_path: %s\n", executable_path);

    char *arg_1 = argv[1] // Το Νιοστό argument βρισκεται στη θεση N. 
    printf("The first argument: %s\n", arg_1);
    
    return 0;
}

Αυτό το πρόγραμμα το βρήκα στο διαδίκτυο. Έχω κάποιες απορίες (καποιες απο τις οποίες οφείλονται στην ελειπή εμπειρία μου με δείκτες):

  1. Ισχύει οτι οταν κάνουμε μια array: int arr[n] τότε η μεταβλητη arr απλα αποθηκεύει εναν pointer στο πρώτο στοιχείο της (arr[0])?

  2. Γνωρίζω οτι τα strings ειναι απλα arrays με chars και '\0' για τελευταίο στοιχείο. Ισχύει οτι ενας δεικτης char * p μπορεί να διαβαστεί ως string (εσωτερικά, πχ αν κανουμε printf("%s", p) ) οταν για κάθε χαρακτήρα κανουμε p++ και διαβάζοντας τον χαρακτήρα *p (εως ότου συναντήσουμε τον NULL \0) ?

  3. η παραμετρος char *argv[] ειναι ουσιαστικά μια array (που εννοείται απο το []) με pointers σε χαρακτήρες (εξου char *)?

  4. Πρακτικά: Γιατί δεν να αντικαταστήσουμε το char *arg_1 = argv[1] με char arg_1[] = argv[1] αφού και τα 2 χρησιμοποιούνται ως συμβολοσειρες?

  5. Πρακτικά: Γιατί δεν μπορούμε να αντικαταστήσουμε παλι το char *arg_1 = argv[1] με int arg_1 = argv[1] (απλά φυλώ τον δείκτη σε μια μεταβλητή αφου έτσια και αλλιώς δε κάνω dereference ποτε το *arg_1) ?

in progintro by (750 points)
edited by | 408 views

1 Answer

+6 votes
Best answer

1) Ναι. Οι πίνακες ουσιαστικά είναι δείκτες σε θέσεις μνήμης. Για παράδειγμα, αν τρέξεις το παρακάτω:


array[0] = 1;
*(p+1) = 2; //Next address of the pointer   
array[2] = 3;
printf("Pointer address: %d\n", p); 
printf("Array [0] = %d, Array [1] = %d and Array [2] = %d\n", 
        array[0], *(p+1), *(array + 2));

θα πάρεις


Pointer address: 1398491568
Array [0] = 1, Array 1 = 2 and Array [2] = 3

2) Δεν είμαι σίγουρος ότι καταλαβαίνω την ερώτηση. Ένα string είναι ένας πίνακας με χαρακτήρες με τελευταίο χαρακτήρα το \0. Αρα ναι μπορείς να κάνεις κάτι σαν αυτό που (φαντάζομαι ότι) ρωτάς:


char s[12] = "Hello\0";
char *ps = s;
printf("%s\n", ps+1);

και να πάρεις

 ello 

3) Η παράμετρος έιναι δείκτης σε ένα πίνακα με δείκτες σε χαρακτήρες. Ουσιαστικά μπορείς να το σκεφτείς και σαν έναν δισδιάστατο πίνακα. Η μορφή της θα είναι κάπως έτσι (με όνομα προγράμματος prog):


*argv[] ---> argv[0] argv1 | v p r


(δεν ξέρω αν το visualisation βοήθησε. :Ρ


4) Well θα μπορούσες να το κάνεις αυτό, αλλά όχι ακριβώς έτσι. Όταν αρχικοποιείς ένα πίνακα η C(++) περιμένει μια σταθερή έκφραση. Άρα το πρόγραμμα, αν γράψεις το παραπάνω θα σου πετάξει ένα error στο compile time error: invalid initializer. Αν πραγματικά ήθελες να το κάνεις με αυτό τον τρόπο θα έπρεπε να κάνεις copy το string (π.χ με strcpy). Μπορείς να δείς εδώ μια αντίστοιχη ερώτηση.


5) Δεδομένου ότι δεν μπορείς να κάνεις την παραπάνω αντικατάσταση, θα αναφερθώ απλά στο type casting, την μετατροπή τύπου από char σε int, το οποίο η C(++) σε αφήνει να κάνεις, βγάζοντας σου μόνο ένα warning, αν π.χ. κάνεις


int *arg_1 = argv[0];
 warning: initialization of ‘int *’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types]
     int *arg_1 = argv[0];

Αυτό όμως είναι πολύ κακή πρακτική (εξού και το warning), αφού κάνει τον κώδικα δύσκολο στην διατήρηση, και δύσκολο στην ανάγνωση.

Αν πραγματικά ήθελες να κάνεις μετατροπή σε άλλο τύπο θα μπορούσες να το κάνεις explicitly, αλλά νομίζω αυτό ξεφεύγει από τα όρια της ερώτησης.


Edit:
Πρόσθεσα ένα λίγο πιο κατατοπιστικό παράδειγμα στην ερώτηση 1.

by (2.2k points)
selected by
0

Συγνώμη για καποιες ασάφειες στην ερώτηση. οι αστερίσκοι μετατράπηκαν σε χωρία για λεξεις σε italic. Το έφτιαξα τωρα με backslashes.

0

Ευχαριστώ πολυ για τις απαντήσεις. Μονο στην 5 εννοουσα κατι αλλο: Να φυλλαξω τη διεύθυνση του πρώτου χαρακτήρα της συμβολοσειράς (εμμεσα την συμβολοσειρα) οχι σε εναν φυσιολογικό pointer αλλα απλως σε μια μεταβλητη (int για απλότητα). Αρα να φυλλαξω πχ τη διευθυνση argv[1] ετσι: int arg_1 = argv[1], και να θυμαμαι απλα οτι ο arg_1 περιέχει διεύθυνση στον πρώτο χαρακτήρα / συμβολοσειρά.

0

Θα μπορούσες να φτιάξεις άλλον ένα δείκτη ίδιου τύπου με τον αρχικό για να αποθηκεύσεις την διεύθυνση της συμβολοσειράς ή του χαρακτήρα. Έτσι στην περίπτωση που κάνεις οτιδήποτε με τον πρώτο δείκτη, δεν θα χάσεις την θέση τους. Να το αποθηκεύσεις σε int, θεωρητικά μπορείς, αλλά δεν θα είναι πολύ βολικό αργότερα.

301 questions

289 answers

288 comments

903 users