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

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

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

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

Δημοσίευσηαπό konnn » 10 Απρ 2012, 17:14

1.Μήπως σταματά σε σημείο που το p δε δείχνει κάπου;

2.Αυτό είχα κάνει όσο δε λειτουργούσε η sizeof αλλά και εκείνο δεν μου δούλεψε οπότε είπα να φτιάξω τη δική μου συνάρτηση,μάταια.Τώρα όμως οκ.
Ευχαριστώ πολύ.
ΥΓ: Όταν το τελειώσω θα το αναρτήσω.
Τελευταία επεξεργασία από konnn και 11 Απρ 2012, 09:57, έχει επεξεργασθεί 1 φορά/ες συνολικά
1 Linux: Μέτριος ┃ Προγραμματισμός: Μέτριος ┃ Αγγλικά: Προχωρημένος
2 Desktop : Ubuntu 16.04 64bit
a Intel Core i3 CPU 530 2.93GHz ‖ RAM 3824 MiB ‖ Intel DH55HC -
b nVidia Device [10de:1040] (rev a1)
c eth0: Intel 82578DC Gigabit Network Connection
3 Notebook : Ubuntu 16.04 64 bit
a Intel Core i3-2365M CPU @ 1.40GHz ‖ RAM 3854 MiB ‖ LENOVO 20197
b Intel 2nd Generation Core Processor Family Integrated Graphics Controller
c 5 wlan0: Intel Centrino Wireless-N 2230 ⋮ eth0: Realtek RTL8101E/RTL8102E

Αυτόματη υπογραφή.
Άβαταρ μέλους
konnn
Συντονιστής
Συντονιστής
 
Δημοσιεύσεις: 3568
Εγγραφή: 12 Ιούλ 2010, 17:54
Τοποθεσία: Καλαμάτα
Launchpad: konnn
Εκτύπωση

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

Δημοσίευσηαπό Ilias95 » 11 Απρ 2012, 00:31

Γεια χαρά,

Τελείωσα το κεφάλαιο 17 και έχω κάποιες απορίες.
Τις παραθέτω.


1. Το παρακάτω είναι το prototype της malloc:
Κώδικας: Επιλογή όλων
void *malloc(size_t size);

Τι ακριβώς καταλαβαίνουμε από αυτό για τον τύπο που επιστρέφει η malloc;
Είναι ένας pointer σε τι; Είναι μήπως ένας pointer που μπορεί να δείχνει σε οποιονδήποτε τύπο;

2. Είναι η παρακάτω σωστή λύση για την 1η άσκηση της σελίδας 453;
Μορφοποιημένος Κώδικας: Επιλογή όλων
void *my_malloc(size_t size) 
{
void *s = malloc(size);
if (!s) {
puts("error: out of memory");
exit(EXIT_FAILURE);
}
return s;
}

Σε real-life εφαρμογές συνηθίζεται να γίνεται χρήση παρόμοιων συναρτήσεων;

3. Το παρακάτω sample μου δίνει έξοδο 14:
Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int *a;

a = malloc(3 * sizeof(int));
a[0] = 4;
a[1] = 3;
a[7] = 14;
printf("%d\n", a[7]);

return 0;
}

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

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

Δημοσίευσηαπό migf1 » 11 Απρ 2012, 16:38

Ilias95 έγραψε:Γεια χαρά,

Καλησπέρα,

έγραψε:Τελείωσα το κεφάλαιο 17 και έχω κάποιες απορίες.
Τις παραθέτω.


1. Το παρακάτω είναι το prototype της malloc:
Κώδικας: Επιλογή όλων
void *malloc(size_t size);

Τι ακριβώς καταλαβαίνουμε από αυτό για τον τύπο που επιστρέφει η malloc;
Είναι ένας pointer σε τι; Είναι μήπως ένας pointer που μπορεί να δείχνει σε οποιονδήποτε τύπο;

Ακριβώς! Είναι ο στάνταρ τρόπος για generic/abstract programming στη C. Ουσιαστικά δηλώνεις abstractly τα data σου ως δείκτες σου void, και όταν φτιάχνεις συναρτήσεις που θα τα χρησιμοποιήσουν, τα κάνεις cast στον κανονικό τους τύπο.

έγραψε:2. Είναι η παρακάτω σωστή λύση για την 1η άσκηση της σελίδας 453;
Μορφοποιημένος Κώδικας: Επιλογή όλων
void *my_malloc(size_t size) 
{
void *s = malloc(size);
if (!s) {
puts("error: out of memory");
exit(EXIT_FAILURE);
}
return s;
}

Σε real-life εφαρμογές συνηθίζεται να γίνεται χρήση παρόμοιων συναρτήσεων;

Συνήθως δεν διακόπτουμε το πρόγραμμα άμεσα μέσα στις συναρτήσεις. Συνήθως τις βάζουμε να επιστρέφουν κάποια τιμή αποτυχίας και διαχειριζόμαστε όλα τα πιθανά σφάλματα σε πιο υψηλό επίπεδο, όπου έχουμε πιο εποπτικό έλεγχο στο πρόγραμμα και μπορούμε π.χ. να κάνουμε cleanup πριν τερματίσουμε.

Για παράδειγμα, αν είχες 2 τέτοιες συναρτήσεις που έκαναν malloc 2 διαφορετικά πράγματα (π.χ. η μια έναν πίνακα από int και η άλλη έναν πίνακα από float) τότε αν τις υλοποιήσεις και τις 2 όπως παραπάνω, και αποτύχει μόνο η 2η, τότε τερματίζεις το πρόγραμμα χωρίς να κάνεις cleanup τη μνήμη που έχει δεσμεύσει η 1η (potential memory leak).

έγραψε:
3. Το παρακάτω sample μου δίνει έξοδο 14:
Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int *a;

a = malloc(3 * sizeof(int));
a[0] = 4;
a[1] = 3;
a[7] = 14;
printf("%d\n", a[7]);

return 0;
}

Πως γίνεται να δουλεύει σωστά; Αφού υποτίθεται ότι η a έχει δεσμευμένο χώρο για 3 στοιχεία.
Δουλεύει κατά τύχη ή συμβαίνει κάτι άλλο;

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

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

Δημοσίευσηαπό Ilias95 » 11 Απρ 2012, 17:50

Κατάλαβα, ευχαριστώ για τις απαντήσεις.

Μία ακόμα απορία.
Αν ο προγραμματιστής δεν φροντίσει να απελευθερώσει την μνήμη που δέσμευσε δυναμικά μέσα απ' το πρόγραμμα πριν αυτό τερματίσει ποιες μπορεί να είναι οι συνέπειες;

Επίσης κάτι άλλο σχετικά με την άσκηση που υπάρχει στο τέλος των σημειώσεων εδώ: http://x-karagiannis.gr/prog/libs/conte ... lists6.php
Είναι εντάξει να θεωρήσουμε ότι οι λέξεις θα έχουν ένα standar max μήκος ή μπορούν να έχουν οποιοδήποτε μήκος και το πρόγραμμα πρέπει να δουλεύει σωστά ακόμα και εάν ο χρήστης δώσει μία λέξη 200 χαρακτήρων;
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 11 Απρ 2012, 18:01

Ilias95 έγραψε:Κατάλαβα, ευχαριστώ για τις απαντήσεις.

Μία ακόμα απορία.
Αν ο προγραμματιστής δεν φροντίσει να απελευθερώσει την μνήμη που δέσμευσε δυναμικά μέσα απ' το πρόγραμμα πριν αυτό τερματίσει ποιες μπορεί να είναι οι συνέπειες;

Στα δημοφιλή, σύγχρονα λειτουργικά συστήματα δεν υπάρχει πρόβλημα, γιατί αποδεσμεύουν αυτόματα τη μνήμη που έχει δεσμεύσει το πρόγραμμα. Επίσης, η C99 επιβάλλει την αποδέσμευση ακόμα κι αν δεν υπάρχει free() (όπως και το κλείσιμο τυχόν αρχείων, χωρίς να υπάρχει fclose(), και μερικά ακόμα)... αλλά δεν υλοποιούν όλοι οι compilers όλα τα στάνταρ (πρέπει για τον καθένα τους να δει κανείς στην τεκμηρίωσή τους ποια στάνταρ υλοποιούν).

Σε πιο εξειδικευμένες πλατφόρμες (π.χ. στα ενσωματωμένα συστήματα) ενδέχεται να μην απελευθερώνεται αυτόματα η μνήμη. Δηλαδή σε γενικές γραμμές δεν μπορούμε να είμαστε σίγουροι (εκτός αν προγραμματίζουμε για συγκεκριμένη πλατφόρμα, για την οποία ξέρουμε την συμπεριφορά της).

Επίσης σε γενικές γραμμές, θεωρείται bad-practice να μην απελευθερώνεις τη μνήμη που έχεις δεσμεύσει, γιατί εγκυμονεί κινδύνους. Πες για παράδειγμα πως το κύριο πρόγραμμά σου καλεί child processes που δεσμεύουν μνήμη δυναμικά και δεν τη κάνουν free() όταν επιστρέφουν. Πολύ σύντομα θα μείνει χωρίς μνήμη το κύριο πρόγραμμα. Κάτι παρόμοιο μπορεί να συμβεί και σε κώδικες βιβλιοθηκών που δεν κάνουν free().

έγραψε:Επίσης κάτι άλλο σχετικά με την άσκηση που υπάρχει στο τέλος των σημειώσεων εδώ: http://x-karagiannis.gr/prog/libs/conte ... lists6.php
Είναι εντάξει να θεωρήσουμε ότι οι λέξεις θα έχουν ένα standar max μήκος ή μπορούν να έχουν οποιοδήποτε μήκος και το πρόγραμμα πρέπει να δουλεύει σωστά ακόμα και εάν ο χρήστης δώσει μία λέξη 200 χαρακτήρων;

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

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

Δημοσίευσηαπό Ilias95 » 11 Απρ 2012, 20:37

migf1 έγραψε:Κάνε το αρχικά όπως λες.

Ορίστε μια λύση:

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>   // printf(), puts(), scanf(), putchar()
#include <stdlib.h> // malloc(), free(), exit(), EXIT_SUCCESS, EXIT_FAILURE
#include <string.h> // strcmp(), strcpy()
#include <ctype.h> // tolower()

#define LEN_WORD (30+1)
#define LEN_ALPHABET 26

typedef struct node {
char word[LEN_WORD];
struct node *next;
} Node;

typedef struct {
Node *head;
int len;
} List;


Node *add_to_list(Node *n, char *s)
{
Node *new_node = malloc(sizeof(Node));

if (new_node == NULL)
return NULL;

strcpy(new_node->word, s);
new_node->next = n;
return new_node;
}

void list_print(Node *n)
{
for (; n != NULL; n = n->next)
printf("%s ", n->word);
putchar('\n');
}

void list_destroy(Node *n)
{
if (n == NULL)
return;

Node *dummy = NULL;
for (; n != NULL; n = dummy) {
dummy = n->next;
free(n);
}
}

void lowerize(int n, char s[n])
{
for (int i = 0; i < n; i++) {
s[i] = tolower(s[i]);
if (!s[i])
return;
}
}


int main(void)
{
char word[LEN_WORD];
List alphabet[LEN_ALPHABET];

for (int i = 0; i < LEN_ALPHABET; i++) {
alphabet[i].head = NULL;
alphabet[i].len = 0;
}

for (;;) {
scanf("%s", word);
lowerize(LEN_WORD, word);

int c = word[0] - 'a';

if (c < 0)
c = 0;
else if (c > LEN_ALPHABET)
c = LEN_ALPHABET;

alphabet[c].head = add_to_list(alphabet[c].head, word);
if (alphabet[c].head == NULL)
goto exit_failure;
alphabet[c].len++;

if (!strcmp(word, "stop"))
break;
}

int num_words = 0;
putchar('\n');

for (int i = 0; i < LEN_ALPHABET; i++) {
if (alphabet[i].len) {
printf("%c (%d words): ", i + 'a', alphabet[i].len);
list_print(alphabet[i].head);
num_words += alphabet[i].len;
list_destroy(alphabet[i].head);
}
}
printf("\nyou have typed %d words in total (including \"stop\")\n", num_words);
exit(EXIT_SUCCESS);

exit_failure:
for (int i = 0; i < LEN_ALPHABET; i++)
list_destroy(alphabet[i].head);
exit(EXIT_FAILURE);
}
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 11 Απρ 2012, 23:43

Αν το έχεις τεστάρει με ζόρικα test-cases και δουλεύει απροβλημάτιστα, ωραίος Ηλίας (δεν είμαι σε θέση να το κοιτάξω τώρα).

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

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

Δημοσίευσηαπό Ilias95 » 12 Απρ 2012, 00:08

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

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

Δημοσίευσηαπό migf1 » 12 Απρ 2012, 00:21

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

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

Δημοσίευσηαπό Ilias95 » 12 Απρ 2012, 00:38

migf1 έγραψε: κενή γραμμή αντί για λέξη

Συνεχίζει κανονικά και δεν μετράει το κενό σαν λέξη.
migf1 έγραψε: λέξεις σε ελληνικά

Μπαίνουν στην λίστα του αγγλικού 'a' αφού " ελληνικός χαρακτήρας - 'a' " είναι μικρότερο του 0.
migf1 έγραψε:λέξεις μεγαλύτερου μήκους από ότι περιμένε

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

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

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

cron