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

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

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

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

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

migf1 έγραψε:Για να το διορθώσεις, θα πρέπει να περάσεις τον file by-reference στην open_file, δηλαδή &fp

Μήπως εννοείς &file;

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

#define MYFILE "/home/ilias/lol.txt"

bool open_file(FILE *fp, char filename[])
{
return ((fp = fopen(filename, "r")) == NULL) ? false : true;
}

int main(void)
{
FILE *file = NULL;

if (! open_file(&file, MYFILE)) {
printf("%s can't be opened\n", MYFILE);
exit(EXIT_FAILURE);
}

fclose(file);
exit(EXIT_SUCCESS);
}

Έτσι περνάω τον file by-reference στην open_file() δηλαδή περνάω την διεύθυνση μνήμης ενός pointer.
Άρα η open_file() περιμένει pointer; Ή pointer σε pointer;
Μπερδεύτηκα...

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

#define MYFILE "/home/ilias/lol.txt"

bool open_file(FILE **fp, char filename[])
{
return ((*fp = fopen(filename, "r")) == NULL) ? false : true;
}


int main(void)
{
FILE *file = NULL;

if (! open_file(&file, MYFILE)) {
printf("%s can't be opened\n", MYFILE);
exit(EXIT_FAILURE);
}

fclose(file);

exit(EXIT_SUCCESS);
}

Edit2: Ναι, δουλεύει. :)
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

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

Yeap :)

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

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

Δημοσίευσηαπό Ilias95 » 01 Απρ 2012, 21:41

migf1 έγραψε:Να σου πω μια άσκηση που σκέφτηκα που μπορείς να την κάνεις και τώρα, άμα διαβάσεις απευθείας για τα αρχεία;
Έναν κλώνο του unix/linux tool wc

Voila!

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // strtok(), strcmp()
#include <stdlib.h> // fopen(), exit(), EXIT_SUCCESS, EXIT_FAILURE
#include <stdbool.h> // bool, true, false

#define MAX_INPUT (10000+1)

/**********************************************************************
* open_file: Opens a file. *
* Returns true if file opens properly, else false. *
**********************************************************************/
bool open_file(FILE **fp, char filename[])
{
return ((*fp = fopen(filename, "r")) != NULL) ? true : false;
}

/**********************************************************************
* get_data: Counts the number of characters, lines, max line length *
* and words in a file. It uses strtok() to tokenize input *
* and get the number of words. *
**********************************************************************/
void get_data(FILE *fp, int *chars, int *lines, int *max_line_len, int *words)
{
char text[MAX_INPUT] = {'\0'}, *p, line_len = 0;

for (p = text; (*p = getc(fp)) != EOF; p++) {
line_len++;

if (*p == '\n') {
(*lines)++;

if (line_len - 1 > *max_line_len)
*max_line_len = line_len - 1;
line_len = 0;
}
}

*p = '\0'; // cover EOF char
if (line_len > *max_line_len) // in case that file ends without a '\n'
*max_line_len = line_len;

*chars = p - &text[0];

char *x = strtok(text, " \n"); // tokenize text
while (x != NULL) {
(*words)++;
x = strtok(NULL, " \n");
}
}

void help(void)
{
puts("usage: mywc [FILE] [OPTION]...\n"
"Print newline, word, and byte counts for a file.\n\n"
"-c, --bytes print the byte counts\n"
"-m, --chars print the character counts\n"
"-l, --lines print the newline counts\n"
"-L, --max-line-length print the length of the longest line\n"
"-w, --words print the word counts\n"
"--help print help and exit\n");
}


int main(int argc, char *argv[])
{
FILE *file = NULL;
int chars = 0, lines = 0, max_line_len = 0, words = 0;

if (argc == 1 || ! strcmp(argv[1], "--help")) {
help();
exit(EXIT_SUCCESS);
}

if (! open_file(&file, argv[1])) {
printf("%s can't be opened\n", argv[1]);
exit(EXIT_FAILURE);
}

get_data(file, &chars, &lines, &max_line_len, &words);

if (argc == 2) {
printf("byte counts: %d\n", chars * sizeof(char));
printf("characters counts: %d\n", chars);
printf("newline counts: %d\n", lines);
printf("length of the longest line: %d\n", max_line_len);
printf("word counts: %d\n", words);
goto exit_;
}

for (char **p = &argv[2]; *p != NULL; p++) {
if (! strcmp(*p, "-c") || ! strcmp(*p, "--bytes"))
printf("byte counts: %d\n", chars * sizeof(char));
else if (! strcmp(*p, "-m") || ! strcmp(*p, "--chars "))
printf("characters counts: %d\n", chars);
else if (! strcmp(*p, "-l") || ! strcmp(*p, "--lines"))
printf("newline counts: %d\n", lines);
else if (! strcmp(*p, "-L") || ! strcmp(*p, "--max-line-length"))
printf("length of the longest line: %d\n", max_line_len);
else if (! strcmp(*p, "-w") || ! strcmp(*p, "--words"))
printf("word counts: %d\n", words);
else if (! strcmp(*p, "--help")) {
help();
break;
}
else
printf("\"%s\" is not a valid option\n", *p);
}

exit_:
fclose(file);
exit(EXIT_SUCCESS);
}


Είναι παραλλαγή όμως, δεν δουλεύει ακριβώς όπως το wc. Επίσης δουλεύει μόνο με text files που περιέχουν μέχρι 10.000 χαρακτήρες.
Το ονόμασα mywc. :P

Η εικόνα βοήθειας:
Κώδικας: Επιλογή όλων
ilias@ilias-pc:~$ ./mywc --help
usage: mywc [FILE] [OPTION]...
Print newline, word, and byte counts for a file.

-c, --bytes print the byte counts
-m, --chars print the character counts
-l, --lines print the newline counts
-L, --max-line-length print the length of the longest line
-w, --words print the word counts
--help print help and exit

ilias@ilias-pc:~$


Και σε δράση ( :P ) :
Spoiler: show
Κώδικας: Επιλογή όλων
ilias@ilias-pc:~$ ./mywc file.txt
byte counts: 52
characters counts: 52
newline counts: 3
length of the longest line: 25
word counts: 10
ilias@ilias-pc:~$ ./mywc dfasfadsafd
dfasfadsafd can't be opened
ilias@ilias-pc:~$ ./mywc file.txt -w -c
word counts: 10
byte counts: 52
ilias@ilias-pc:~$ ./mywc file.txt --words -fds -L
word counts: 10
"-fds" is not a valid option
length of the longest line: 25
ilias@ilias-pc:~$ ./mywc file.txt h
"h" is not a valid option
ilias@ilias-pc:~$
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

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

Ωραίος!

Για να μην εξαρτάσαι από το μέγεθος του αρχείου, μπορείς να επεξεργάζεσαι in-place τους χαρακτήρες, απευθείας όπως τους διαβάζεις από το αρχείο (χωρίς δηλαδή να χρησιμοποιείς το buffer text). Γίνεται όμως λίγο πιο δύσκολος έτσι ο αλγόριθμος του tokenization (αν κι έχουμε κάνει ήδη αρκετά τέτοια παραδείγματα στο νήμα, με τη μόνη διαφορά πως τα κάναμε στην stdin αντί για αρχείο).

Αργότερα που θα διαβάσεις για δυναμική διαχείριση, θα μπορείς να χρησιμοποιείς κάτι σαν το παρακάτω για να βρεις το μέγεθος του αρχείου, και κατόπιν να δεσμεύεις δυναμικά το μέγεθος του text (αλλά η in-place επεξεργασία δεν είναι καθόλου άσχημη ιδέα... το μόνο της μειονέκτημα είναι πως αφήνει ανοιχτό το αρχείο καθόλη τη διάρκεια του προγράμματος, κάτι που btw το κάνεις κι εσύ στη δική σου λύση)...

Μορφοποιημένος Κώδικας: Επιλογή όλων
/*********************************************************//**
* @brief Return the size of a file in bytes, or 0 on error
* (cannot be more than LONG_MAX).
*************************************************************
*/
uintmax_t f_size( const char *fname )
{
long int size;
FILE *fp;

if ( NULL == (fp = fopen(fname, "rb")) ) /* binary mode */
return 0;

if ( 0 != fseek(fp, 0, SEEK_END) ) {
fclose(fp);
return 0;
}

size = ftell(fp);
fclose(fp);

return (size < 0) ? 0 : (uintmax_t)size;
}

Την παραπάνω ρουτίνα την έχω φτιάξει και τη χρησιμοποιώ και στο HexView, αν κι έχει τους περιορισμούς της.

ΥΓ. Εγώ δυστυχώς δεν κατάφερα να ασχοληθώ όσο έπρεπε αυτό το Σ/Κ με το HexView, οπότε αναβάλλεται για 1-2 μέρες το ποσστάρισμά του.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

Δημοσίευσηαπό stamatiou » 02 Απρ 2012, 12:57

Γεια σας και πάλι!
Το τελευταίο καιρό, είμαι στο Π.Δ.Π. (pdp.gr) και έχω περάσει τη Β' Φάση, όμως για κάποιο λόγο το πρόγραμμα που έχω φτιάξει δεν βγάζει έξοδο για 2 αρχεία εισόδου.
Εκφώνηση: http://www.pdp.gr/files/24b/PDP_24_B_GYM_final.pdf
Κώδικας: http://ideone.com/FrmLF
Αρχεία εισόδου: http://www.mediafire.com/?s4hkma5nlg5s6zc

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

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

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

migf1 έγραψε:Για να μην εξαρτάσαι από το μέγεθος του αρχείου, μπορείς να επεξεργάζεσαι in-place τους χαρακτήρες, απευθείας όπως τους διαβάζεις από το αρχείο (χωρίς δηλαδή να χρησιμοποιείς το buffer text). Γίνεται όμως λίγο πιο δύσκολος έτσι ο αλγόριθμος του tokenization (αν κι έχουμε κάνει ήδη αρκετά τέτοια παραδείγματα στο νήμα, με τη μόνη διαφορά πως τα κάναμε στην stdin αντί για αρχείο).

Σε ποια παραδείγματα αναφέρεσαι;
Το buffer text (αλήθεια το buffer πως ακριβώς μεταφράζεται και τι ακριβώς σημαίνει/δηλώνει;) το χρησιμοποιώ γιατί η strtok() περιμένει string.
Μπορείς να δώσεις ένα παράδειγμα για το πως θα γίνει το tokenization αλλιώς;
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό simosx » 02 Απρ 2012, 15:41

stamatiou έγραψε:Γεια σας και πάλι!
Το τελευταίο καιρό, είμαι στο Π.Δ.Π. (pdp.gr) και έχω περάσει τη Β' Φάση, όμως για κάποιο λόγο το πρόγραμμα που έχω φτιάξει δεν βγάζει έξοδο για 2 αρχεία εισόδου.
Εκφώνηση: http://www.pdp.gr/files/24b/PDP_24_B_GYM_final.pdf
Κώδικας: http://ideone.com/FrmLF
Αρχεία εισόδου: http://www.mediafire.com/?s4hkma5nlg5s6zc

Επίσης αν υπάρχει τρόπος να βελτιώσω την ταχύτητα πείτε μου :D


Είναι καλό να αναφέρεις το σκεπτικό σου για το πως προσπαθείς να επιλύσεις το πρόβλημα.

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

10
-101 -4 -1 6 95 1000 1001 1002 2000 9999


Και πάνω σε αυτό μπορούμε να σχολιάσουμε.
προσωπικό ιστολόγιο ϗ πλανήτης 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

Δημοσίευσηαπό stamatiou » 02 Απρ 2012, 16:03

Καταρχάς, βλέπω ότι αν αθροίσουμε το -101 με όλα τα υπόλοιπα θα βγεί ένας πίνακας αθροισμάτων:
(εδώ γράφω την απόλυτη τιμή του αθροίσματος)
Spoiler: show
105
102
95
6
900
901
1899
9898

Παρατηρώ ότι ενώ στην αρχή η διάταξη είναι φθίνουσα ενώ στο 6 και αλλάζει σε αύξουσα. Όταν κάνω έναν παρόμοιο πινακα αλλά με το -4 βγαίνει:
Spoiler: show
5
2
91
996
997
998
1996
9995

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

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

Δημοσίευσηαπό simosx » 02 Απρ 2012, 16:50

stamatiou έγραψε:Καταρχάς, βλέπω ότι αν αθροίσουμε το -101 με όλα τα υπόλοιπα θα βγεί ένας πίνακας αθροισμάτων:
(εδώ γράφω την απόλυτη τιμή του αθροίσματος)
Spoiler: show
105
102
95
6
900
901
1899
9898

Παρατηρώ ότι ενώ στην αρχή η διάταξη είναι φθίνουσα ενώ στο 6 και αλλάζει σε αύξουσα. Όταν κάνω έναν παρόμοιο πινακα αλλά με το -4 βγαίνει:
Spoiler: show
5
2
91
996
997
998
1996
9995

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


Από την εκφώνηση αναφέρει ότι το N < 1.000.000, και ότι μπορείς να χρησιμοποιήσεις μέχρι 64MB RAM. Με 1 εκατομμύριο long int (8byte), δεσμεύεις 8ΜΒ RAM που είναι μέσα στα όρια αν διάβαζες όλο το αρχείο στη μνήμη.
Σαν εξάσκηση θα πρότεινα να επιλύσεις μια φορά την εργασία με αυτό το τρόπο, με χρήση πίνακα.

Για την ανάγνωση όλου του αρχείου των 1000000 αριθμών σε ένα πίνακα, παίρνει γύρω στα 170ms στον υπολογιστή μου (φτιάχνεις το εκτελέσιμο, και τρέχεις time ./myprog). Το μέγιστο στην εκτέλεση είναι 3000ms (3 δευτερόλεπτα) που είναι μέσα στα όριά σου.

Με τη χρήση του πίνακα, βρίσκεις που είναι το 0 (ή το νούμερο που είναι πιο κοντά στο μηδέν).
Και μετά, δοκιμάζεις ζευγάρια από νούμερα (μεγαλύτερα+μικρότερα του πιο κοντινού αριθμού στο 0) για να βρεις τα καλύτερα ζευγάρια.

Κάτι άλλο που προτείνω στον κώδικά σου είναι να προσθέτεις εντολές printf() συχνά ώστε να παρακολουθείς εύκολα τι παίρνει χρόνο κατά την εκτέλεση.
προσωπικό ιστολόγιο ϗ πλανήτης 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

Δημοσίευσηαπό stamatiou » 02 Απρ 2012, 17:32

simosx έγραψε:
stamatiou έγραψε:Καταρχάς, βλέπω ότι αν αθροίσουμε το -101 με όλα τα υπόλοιπα θα βγεί ένας πίνακας αθροισμάτων:
(εδώ γράφω την απόλυτη τιμή του αθροίσματος)
Spoiler: show
105
102
95
6
900
901
1899
9898

Παρατηρώ ότι ενώ στην αρχή η διάταξη είναι φθίνουσα ενώ στο 6 και αλλάζει σε αύξουσα. Όταν κάνω έναν παρόμοιο πινακα αλλά με το -4 βγαίνει:
Spoiler: show
5
2
91
996
997
998
1996
9995

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


Από την εκφώνηση αναφέρει ότι το N < 1.000.000, και ότι μπορείς να χρησιμοποιήσεις μέχρι 64MB RAM. Με 1 εκατομμύριο long int (8byte), δεσμεύεις 8ΜΒ RAM που είναι μέσα στα όρια αν διάβαζες όλο το αρχείο στη μνήμη.
Σαν εξάσκηση θα πρότεινα να επιλύσεις μια φορά την εργασία με αυτό το τρόπο, με χρήση πίνακα.

Για την ανάγνωση όλου του αρχείου των 1000000 αριθμών σε ένα πίνακα, παίρνει γύρω στα 170ms στον υπολογιστή μου (φτιάχνεις το εκτελέσιμο, και τρέχεις time ./myprog). Το μέγιστο στην εκτέλεση είναι 3000ms (3 δευτερόλεπτα) που είναι μέσα στα όριά σου.

Με τη χρήση του πίνακα, βρίσκεις που είναι το 0 (ή το νούμερο που είναι πιο κοντά στο μηδέν).
Και μετά, δοκιμάζεις ζευγάρια από νούμερα (μεγαλύτερα+μικρότερα του πιο κοντινού αριθμού στο 0) για να βρεις τα καλύτερα ζευγάρια.

Κάτι άλλο που προτείνω στον κώδικά σου είναι να προσθέτεις εντολές printf() συχνά ώστε να παρακολουθείς εύκολα τι παίρνει χρόνο κατά την εκτέλεση.

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

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

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