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

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

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

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

Δημοσίευσηαπό Ilias95 » 21 Μαρ 2012, 22:02

Μάλιστα, τώρα κατάλαβα.
Δεν έχει να κάνει με το σύστημα, αλλά με την C που διαχειρίζεται τις διαθέσιμες περιοχές μνήμης όπως αυτή (δηλ. ο χρήστης) θέλει.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 21 Μαρ 2012, 22:03

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

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

Δημοσίευσηαπό Ilias95 » 21 Μαρ 2012, 22:30

Και μια ακόμα απορία.

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

void capitalize(char *s)
{
for (; *s; s++)
*s = toupper(*s);
}

void func(char *s)
{
capitalize(s);
puts(s);
}

int main(void)
{
func("string");
return 0;
}

Η capitalize() αντικαθιστά κάθε μικρό γράμμα ενός string με το αντίστοιχο κεφαλαίο.
Έτσι όπως είναι ο παραπάνω κώδικας δίνει seg fault.
Το σφάλμα είναι στο σημείο όπου καλώ την capitalize και μαντεύω ότι για κάποιο λόγο το argument που περνάω δεν είναι σωστό.

Αν αντικαταστήσω όμως την func() με:
Μορφοποιημένος Κώδικας: Επιλογή όλων
void func(char *s) 
{
char x[10];
strcpy(x, s);
capitalize(x);
puts(x);
}

Θα εκτελεστεί κανονικά ο κώδικας.

Ποιο ακριβώς είναι το λάθος όμως στην πρώτη περίπτωση; Pointer περιμένει η capitalize(), pointer περνάω (ή όχι;).
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 21 Μαρ 2012, 22:58

Είναι και πάλι τι ίδιο πρόβλημα με προηγουμένως. Το "string" που περνάς απευθείας στην func() στην 1η περίπτωση, είναι read-only (string literal)... οπότε με το που πάει η συνάρτηση capitalize() να μετατρέψει σε κεφαλαίο τον πρώτο πεζό χαρακτήρα του, σκάει seg-fault

Αντίθετα, στη 2η περίπτωση, περνάς στην func() ένα mutable (read/write) string, μιας και πρόκειται για μεταβλητή που την έχεις δηλώσει ως πίνακα από χαρακτήρες.

Το πιο κοντινό παράδειγμα που μπορώ να σκεφτώ για το σφάλμα που κάνεις στην 1η περίπτωση, είναι κάτι σαν το παρακάτω.

Μορφοποιημένος Κώδικας: Επιλογή όλων
int plus10( int *n )
{
return *n + 10;
}

int main( void )
{
printf( "%d\n", plus10( &2 ) ); // ΣΦΑΛΜΑ... το 2 είναι απλώς μια σταθερά, δεν έχει διαχειρίσιμη διεύθυνση
}


Ενώ στη 2η περίπτωση το κάνεις σωστά...

Μορφοποιημένος Κώδικας: Επιλογή όλων
int main( void )
{
int n;

n = 2;
printf( "%d\n", plus10( &n ) ); // Σωστό!
...
}


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

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

Δημοσίευσηαπό simosx » 21 Μαρ 2012, 23:00

Το πρόγραμμά σου μπορεί να απλοποιηθεί ως
Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void func(char* s)
{
s[0] = 'a';
}

int main(void)
{
func("string");

return 0;
}


Προσπαθείς να γράψεις σε string literal, και στην περίπτωση αυτή αποτελεί μνήμη μόνο για ανάγνωση.
Σε παλαιότερους μεταγλωττιστές υπήρχε η ελευθερία να γράφεις σε τέτοιες περιοχές μνήμης, όχι όμως τώρα.
Δες περισσότερα στο
http://c-faq.com/decl/strlitinit.html
προσωπικό ιστολόγιο ϗ πλανήτης Ubuntu-gr
Συμβάλετε και εσείς στο ελληνικό βιβλίο Ubuntu!
1 Γνώσεις Linux: Πολύ καλό ┃ Προγραμματισμού: Πολύ καλό ┃ Αγγλικών: Πολύ καλό
2 Ubuntu 13.10 saucy 3.11.0-031100rc1-generic 64bit (el_GR.UTF-8, Unity ubuntu)
3 AMD E-450 APU with Radeon HD Graphics ‖ RAM 3555 MiB ‖ Sony Corporation VAIO
4 AMD nee ATI Wrestler [Radeon HD 6320] [1002:9806] {fglrx_pci}
5 eth0: Atheros Inc. AR8151 v2.0 Gigabit Ethernet [1969:1083] (rev c0) ⋮ wlan0: Atheros Inc. AR9285 [168c:002b] (rev 01)
Φτιάξτε και εσείς τη δική σας υπογραφή (παραπάνω κείμενο) αυτόματα με κλικ εδώ!
simosx
Επίτιμο μέλος
Επίτιμο μέλος
 
Δημοσιεύσεις: 10334
Εγγραφή: 11 Μάιος 2008, 18:52
Launchpad: simosx
IRC: simosx
Εκτύπωση

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

Δημοσίευσηαπό Ilias95 » 21 Μαρ 2012, 23:12

Σωστά, ακριβώς το ίδιο λάθος. :eh:
Ευχαριστώ για τις απαντήσεις.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό Star_Light » 22 Μαρ 2012, 14:36

Σπερααααα!

Τι κανει το team? :D

Eγω τελειώνω 6ο κεφάλαιο... και μετα θα μπω 7ο.
Παλι καλα που το παω σιγα - σιγα ειχα κατι τρελα κενα στα loops :/

Σελ.112 ειμαι. Αλλα σημερα θα ασχοληθω με κατι διορθωσεις που μου βαλανε στην πτυχιακη
γιατι θελω να κανω παρουσιαση πριν μπω φανταρος... τελη Απριλιου δηλαδη.
Γνώσεις ⇛ 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

Δημοσίευσηαπό Star_Light » 22 Μαρ 2012, 14:47

Σε καποια φαση σε ενα

Κώδικας: Επιλογή όλων
for(1. i=0; 2. i<n; 3. i++)


νομιζα οτι σε καθε loop ξεκινά απο το 1. και εκχωρει καθε φορα δεν ημουν και απολυτος βεβαια :p ... εν τελει αυτο ειναι λαθος
απο το 2 ξεκινα... αποτιμα την συνθηκη εκτελει τις πραξεις και μετα αυξανει το i κατα 1
για αυτο δεν εχει και σημασια αν μπει ++i ή i++ .

H έκφραση i=0; ειναι εκτος loop.

To ισοδυναμο while

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


int 1. i=0;

while(2. i < n)
{
....
3. i++; ή ++i;
}
Γνώσεις ⇛ 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

Δημοσίευσηαπό Ilias95 » 23 Μαρ 2012, 00:57

Κάποια καλύτερη λύση για το 10ο programming project της σελίδας 312;

Η παρακάτω είναι κακή, στραβή και άσχημη αλλά τουλάχιστον δουλεύει:
Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // strcat()

void reverse_name(char *name)
{
char *p = name, first_letter[1+1];

while (*p == ' ') p++; // skip spaces and go to first letter
first_letter[0] = *p;

while (*p != ' ') p++; // go to next space
while (*p == ' ') p++; // skip spaces and go to surname

for (; *p != ' ' && *p; p++, name++)
*name = *p;
*name = '\0';

strcat(name, ", ");
strcat(name, first_letter);
strcat(name, ".");
}

int main(void)
{
char name[80+1] = {'\0'};

gets(name);
reverse_name(name);
puts(name);

return 0;
}
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 23 Μαρ 2012, 04:56

Μια χαρά λύση τη βλέπω εγώ, αλλά σε real-life εφαρμογή χρειάζονται περισσότεροι έλεγχοι.

Θα μπορούσες επίσης να αποφύγεις τη χρήση συναρτήσεων στο τέλος (που είναι αργές) και να δουλέψεις απευθείας στην τρέχουσα θέση του name.

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

/* ------------------------------------------------------- */
void reverse_name( char *name )
{
char ch, *cp = NULL;

if ( !name )
return;

/* find & save the 1st letter of first name */
for (cp=name; *cp && isspace(*cp); cp++) /* skip any blanks */
; /* void */
if ( !*cp ) /* name was empty or all blanks */
return; /* ... early exit */

ch = *cp; /* save 1st letter */

/* find start of last name */
for (; *cp && !isspace(*cp); cp++ ) /* skip first name */
; /* void */
for (; *cp && isspace(*cp); cp++ ) /* skip any blanks */
; /* void */
if ( !*cp ) /* there was no non-blank last name */
return; /* ... early exit */

/* copy last name to start of name */
while ( *cp && !isspace(*cp) )
*name++ = *cp++;

/* append the mummble-jumble asked by the exercise */
*name++ = ',';
*name++ = ' ';
*name++ = ch;
*name++ = '.';
*name = '\0';
}
/* ------------------------------------------------------- */
int main( void )
{
char name[] = " Harry Karayannis ";

reverse_name( name );
printf( "%s\n", name );

system("pause"); /* windows only */
exit( EXIT_SUCCESS );
}

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

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

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