Τα πάντα για την C

...του ubuntu και έργων ΕΛ/ΛΑΚ (Έργα-Οδηγοί-Προτάσεις)

Συντονιστής: konnn

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό Star_Light » 09 Σεπ 2011, 01:21

Spoiler: show
Κώδικας: Επιλογή όλων

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

int main(void)
{
int *p , **paddr;
int a=2;

p=&a; //Put the address of a into a
paddr=&p; //Put the address of p into paddr

printf("%d",**paddr); //print the value

return 0;
}


Αυτη τη φορα πρεπει να το πετυχα

Και τον εμπλουτισα ακομη παραπανω (PART B) ωστε να δειχνει και τις διευθυνσεις καθεμιας μεταβλητης ξεχωριστα... δηλαδη τις αριστερες τους τιμες.... (εκει που ειναι αποθηκευμενες και οι ιδιες ασχετα αν ειναι δεικτες ή αν δεν ειναι που στην προκειμενη ειναι) επειδη κάθε μεταβλητη έχει 2 τιμες μια δεξια τιμη (περιεχομενα) και μια αριστερη (διευθυνση) οι δείκτες εχουν και αυτοι 2 τιμες με την διαφορα πως και η δεξια και η αριστερη συμπεριφέρονται ως αριστερες και οι 2 ειναι δηλαδη και οι 2 διευθυνσεις απλα η δεξια ειναι η διευθυνση στην οποια έχουμε θεσει να δειχνει η μεταβλητη δεικτη ενω η αριστερη ειναι η διευθυνση που έχει δεσμευθει απο το συστημα για να φιλοξενει τις ιδιες τις μεταβλητες δεικτων και ακριβως αυτες εκτυπωνω πιο κατω (αν τα εχω κανει σωστα) .

Spoiler: show
Κώδικας: Επιλογή όλων

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

int main(void)
{
int *p , **paddr;
int a=2;

p=&a; //H dieuthinsi tou a ston p
paddr=&p; //H dieuthinsi tou p ston paddr

printf("%d",**paddr);

// Epeidi paddr -> p -> a epetai oti oloi 8a exoun idia dieuthinsi (ekei pou deixnoun dld)
printf("\n%p",*paddr); //Ta "periexomena" edw einai h alli dieuthinsi (p) pou ton evala na deixnei
printf("\n%p", p);
printf("\n%p", &a);

// Dieuthinsi mnimis gia ton kathena ksexwrista (diki tou)

printf("\n\n%p",&paddr);
printf("\n\n%p", &p);
return 0;
}

/*
* paddr -> p -> a
* */
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 09 Σεπ 2011, 09:18

Καλημέρα,

το παρακάτω προγραμματάκι νομίζω τα συνοψίζει με σαφήνεια...
Κώδικας: Επιλογή όλων

#include <stdio.h>

int main( void )
{
int n = 10, *p = &n, **paddr = &p;

puts(" int n = 10, *p = &n, **paddr = &p;\n");
printf(" paddr = &p = %lu\n", paddr);
printf(" *paddr = p = %lu\n", *paddr);
printf("**paddr = *p = n = %d\n\n", **paddr);

return 0;
}

Έξοδος...
Κώδικας: Επιλογή όλων

int n = 10, *p = &n, **paddr = &p;

paddr = &p = 1245056
*paddr = p = 1245060
**paddr = *p = n = 10

Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 09 Σεπ 2011, 09:47

Και τώρα μερικές χρήσιμες σημειώσεις,. σχετικές με τα παραπάνω...

Καταρχήν οι διευθύνσεις μνήμης είναι πάντα unsigned. Στις αρχές ήταν unsigned int ( %u) ... πλέον είναι unsigned long int ή και unsigned long long int ( %llu ), ανάλογα την πλατφόρμα και τον compiler. Σίγουρα πάντως ΔΕΝ είναι int ( %d ).

Από την αναθεώρηση C99 και μετά, το casting από δείκτες σε int, long int και long long int (unsigned ή μη) έχει σταματήσει να θεωρείται συμβατό ανάμεσα στους compiler, μιας και ορίστηκε ως "implementation dependent" που σημαίνει πως σε ορισμένους compilers μπορεί να δίνει ακόμα και undefined αποτέλεσμα (δηλαδή τυχαίο, που δεν αντιστοιχεί στη πραγματική διεύθυνση μνήμης).

Σε ότι αφορά τώρα τη χρήση του %p για το τύπωμα διευθύνσεων μνήμης, νομίζω δεν ανήκει στα στάνταρ της γλώσσας αλλά δεν είμαι σίγουρος! Γι αυτό που είμαι σίγουρος είναι πως όποιος compiler το υποστηρίζει περιμένει να του δώσουμε δείκτη τύπου void, άρα οτιδήποτε θέλουμε να τυπώσουμε μέσω του %p πρέπει να το κάνουμε cast σε: (void *)

Δηλαδή το παραπάνω πρόγραμμα, θα γινόταν...
Κώδικας: Επιλογή όλων

#include <stdio.h>

int main( void )
{
int n = 10, *p = &n, **paddr = &p;

puts(" int n = 10, *p = &n, **paddr = &p;\n");
printf(" paddr = &p = %p\n", (void *)paddr);
printf(" *paddr = p = %p\n", (void *)*paddr);
printf("**paddr = *p = n = %d\n\n", **paddr);

return 0;
}

και με %p τα αποτελέσματα βγαίνουν πάντα σε 16αδική μορφή (ενώ με %u, %lu, %llu βγαίνουν σε 10δική μορφή).

Με την υπόθεση πως το %p δεν είναι στάνταρ, ο συμβατός τρόπος για μετατροπές δεικτών σε απρόσημες ακέραιες τιμές προϋποθέτει τη χρήση unions ή struct. Με την ευκαιρία σκέφτομαι να σας πω λίγο για unions (να κάνουμε κι ένα διάλειμμα από τα strings) και να σας δείξω πως μπορούμε να τα χρησιμοποιήσουμε για τις διευθύνσεις μνήμης.

Θα επανέλθω σε καμιά ωρίτσα όμως.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό Star_Light » 09 Σεπ 2011, 10:11

δΗλαδη παλι δεν το ειχα σωστο? :o
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό stamatiou » 09 Σεπ 2011, 10:25

Επίσης, το void είναι τύπος μεταβλητής; Εγώ νόμιζα ότι είναι μόνο για functions και σημαινει πως δεν επιστρέφει η συνάρτηση :problem:
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 09 Σεπ 2011, 12:27

@Star_Light: στον κώδικα σωστά τα είχες, εκτός από το %d... στα σχόλια είχες κάτι λάθη.
@Stamatiou: ένας τύπος δεδομένων είναι και το void (όπως οι int, float, κλπ) που τον χρησιμοποιούμε όταν θέλουμε να αναφερθούμε σε δεδομένα που μας είναι αδιάφορα.

Unions λοιπόν!

Συντακτικά είναι πανομοιότυπα με τα struct, μόνο που αντί για το keyword struct χρησιμοποιούμε το union. Η ειδοποιός διαφορά τους όμως είναι πως τα πεδία που ορίζουμε μέσα στο union αναφέρονται ΟΛΑ σε μια και μόνο εσωτερική μεταβλητή, ενώ στα struct τα πεδία του νοητικά μπορούν να εκληφθούν ως ξεχωριστές εσωτερικές μεταβλητές της δομής, κάτι σαν υπο-μεταβλητές αν το καταλαβαίνετε καλύτερα. Στα union όλα τα πεδία του είναι μια και μόνη υπο-μεταβλητή.

Το συνολικό μέγεθος μνήμης ενός struct είναι το άθροισμα των υπο-μεταβλητών του, π.χ. αν έχουμε...
Κώδικας: Επιλογή όλων

typedef struct test {
int integer;
char character;
} Test;
το συνολικό μέγεθος του struct test είναι sizeof( Test ) ή sizeof( struct test ) ... που ουσιαστικά είναι το άθροισμα της πρόσθεσης: sizeof( int ) + sizeof( char )

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

typedef union test {
int integer;
char character;
} Test;
το συνολικό μέγεθος του union test που ισούται με sizeof( Test) ή sizeof( union test) είναι ίσο με το μέγεθος του μεγαλύτερου από τα πεδία του, άρα sizeof( int ) ... οι int έχουν μέγεθος τουλάχιστον 2 bytes, ενώ οι char 1 byte.

Με άλλα λόγια σε ένα union μπορούμε να αποθηκεύσουμε μια μεταβλητή, μετατρέποντάς την αυτόματα σε οποιονδήποτε άλλο τύπο έχουμε ορίσει ως ξεχωριστό πεδίο μέσα στο union. Και όχι μόνο αυτό, αλλά όταν αναθέτουμε τιμή σε μια μεταβλητή τύπου union, η τιμή αυτή μπορεί να δοθεί σε οποιονδήποτε από τους τύπους που έχουμε ορίσει ως πεδία μέσα στο union.

Το απλούστερο παράδειγμα που μου έρχεται για αρχή είναι ένα union που θα μετατρέπει μια μεταβλητή από int σε char και αντίστροφα. Δείτε τον παρακάτω κώδικα που δείχνει ακριβώς αυτό, και πείτε μου αν είμαστε ΟΚ, για να συνεχίσουμε.

Κώδικας: Επιλογή όλων

#include <stdio.h>

typedef union converted {
int integer;
char character;
} Converted;

// ------------------------------------------------------------
void print_union( Converted uni )
{
printf("as integer : %d\n", uni.integer );
printf("as character: %c\n\n", uni.character );

return;
}
// ------------------------------------------------------------
int main( void )
{
Converted uni = { .integer = 65 }; // αρχικοποίηση δομής σύμφωνα με την αναθεώρηση C99 (πριν δεν μπορούσαμε να αρχικοποιούμε δομές)
// η τελεία, το όνομα του πεδίου και το = είναι προαιρετικά, θα μπορούσε να γραφτεί κι έτσι: Converted uni = { 65 };

print_union( uni );

uni.character = 'Z';
print_union( uni );

uni.integer = 66;
print_union( uni );

return 0;
}

* για να μη γεμίζω τον κώδικα με printf κάθε φορά που αναθέτω διαφορετική τιμή στη μεταβλητή τύπου union, το έκανα ξεχωριστή συνάρτηση το τύπωμά της.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό stamatiou » 09 Σεπ 2011, 12:44

Δλδ ουσιαστικά σε αυτόν τον κώδικα αυτό που μας εξυπηρετούσε είναι ότι με μια δήλωση είχαμε 2 μεταβλητές;
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 09 Σεπ 2011, 12:48

Όχι, μια μεταβλητή έχουμε! Το union βασικά είναι μια και μόνη μεταβλητή, εκφρασμένη όμως σε πολλούς τύπους :) Το συγκεκριμένο παράδειγμα παραπάνω είναι ανούσιο γιατί μετατροπές μεταξύ int και char υποστηρίζονται εγγενώς από τη γλώσσα, οπότε δεν χρειάζεται να φτιάξουμε union για αυτό το πράγμα. Αλλά το έβαλα έτσι για να γίνει κατανοητό.

Ετοιμάζω τώρα ένα πιο προχωρημένο παράδειγμα χρήσης union :)
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό Star_Light » 09 Σεπ 2011, 12:49

μιγφ1 και πως θα εκτυπωνα πχ την **paddr αν το %d μεσα στην printf ειναι λαθος????

Π.Σ Μαζι με το προχωρημενο παραδειγμα σου για unions που θα βαλεις σε λιγο εγω θα ειμαι αυριο ετοιμος (διαβασμενος) , το λεω απο τωρα....να μην σας καθυστερησω αν θελετε να προχωρησετε
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 09 Σεπ 2011, 12:53

Star_Light έγραψε:μιγφ1 και πως θα εκτυπωνα πχ την **paddr αν το %d μεσα στην printf ειναι λαθος????

Εκεί είναι σωστό το %d, στο *paddr όμως θέλει %lu (και στο paddr επίσης, αν μας το ζητούσε η εκφώνηση).

έγραψε:Π.Σ Μαζι με το προχωρημενο παραδειγμα σου για unions που θα βαλεις σε λιγο εγω θα ειμαι αυριο ετοιμος (διαβασμενος) , το λεω απο τωρα....να μην σας καθυστερησω αν θελετε να προχωρησετε

ΟΚ (το παράδειγμα που ετοιμάζω είναι σπάσιμο ενός byte σε bits ;) )
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

ΠροηγούμενηΕπόμενο

Επιστροφή στο Ανάπτυξη Λογισμικού / Αλγόριθμοι