Προς το περιεχόμενο

Με ποιες εντολές διαχειρίζομαι το stdin, stderr καιstdout;;


nantia_rd

Προτεινόμενες αναρτήσεις

Δημοσ.

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

 

Να το αρχειάκι: http://rapidshare.com/files/111863793/data.1.html

Δημοσ.

Για να διαβάσεις από τη stdin μπορείς να χρησιμοποιήσεις τις scanf, gets, για να γράψεις στη stdout τις printf,puts, για τη stderr την perror. Επίσης μπορείς να χρησιμοποιήσεις τις συναρτήσεις με τις οποίες διαβάζεις/γράφεις σε κάποιο *FILE, αφού οι stdin, stdout και stderr είναι *FILE οι ίδιες.

Π.χ. fprintf(stdout,"Something");

Δημοσ.

Το παρακάτω πρόγραμμα διαβάζει μέσο stdin redirection σε Windows console το data.1 σε ένα δισδιάστατο πίνακα (n2DArray) και ύστερα εκτυπώνει στο stdout το περιεχόμενο του.

 

Το πρόγραμμα διαβάζει με την βοήθεια της fgets κάθε γραμμή που εισάγεται από το stdin και ύστερα με την βοήθεια της sscanf δοκιμάζει την αποθήκευση των αριθμών της στον integer πίνακα.

 

Επειδή το data.1 ακολουθεί μια συγκεκριμένη δομή όπου η πρώτη γραμμή έχει στοιχεία ενώ η δεύτερη είναι κενή (line-feed), το while-loop με την βοήθεια του nLineFeed φροντίζει να ακολουθεί αυτό τον ρυθμό (nLineFeed=!nLineFeed) διαβάζοντας ανά δυο fgets τα στοιχεία (αν nLineFeed != 0 -> γραμμή με δεδομένα, αν nLineFeed == 0 -> κενή γραμμή κτλ.)

 

Σε περίπτωση που η sscanf εντοπίσει λιγότερα από τα αναμενόμενα στοιχεία στην γραμμή (_ARRAY_SIZE_ITEMS) διακόπτει την εκτέλεση του προγράμματος (malformed stdin).

 

Σε περίπτωση που η sscanf εντοπίσει περισσότερα από τα αναμενόμενα στοιχεία στην γραμμή τότε τα αγνοεί.

 

Η ταυτόχρονη εκτύπωση του πίνακα στο stderr είναι μαρκαρισμένη ως /* fprintf(stderr, ... */ διότι τα stderr & stdout στην Windows console έχουν (by default) κοινή έξοδο (οθόνη).

 

Το πρόγραμμα έχει δοκιμασθεί με την Windows console ως project.exe <data.1 αποδίδοντας την παρακάτω έξοδο στο stdout:

 

>
12 32 36 48 59 96 87 98 92
21 82 83 54 55 26 37 38 95
13 92 35 14 25 64 74 28 95
21 29 33 24 52 64 37 28 29
15 82 36 47 85 16 27 38 59
61 52 33 34 45 69 77 86 59
81 24 35 46 75 86 97 58 59
19 32 39 47 55 61 72 83 59
11 22 73 64 45 36 27 28 39

 

Ο κώδικας είναι γραμμένος με τον CodeGear Turbo C++ Explorer και φυσικά μπορεί να περιέχει bugs ή άλλες αβλεψίες.

 

>
/*-Read stdin by Directx-----------------------------------------------------*/

#include <stdio.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif

/*---------------------------------------------------------------------------*/
#define	_ARRAY_SIZE_LINE	9
#define	_ARRAY_SIZE_ITEMS	9

#ifdef	__BORLANDC__
#pragma argsused
#endif
int main(int argc, char* argv[])
{
char szBuffer[bUFSIZ];
int	 n2DArray[_ARRAY_SIZE_LINE][_ARRAY_SIZE_ITEMS],
	 nY = 0, 
	 nX;

/*
 * Store "stdin" into szBuffer and then into n2DArray, 
 * stop if no data found or if we read more than _ARRAY_SIZE_LINE.
 */
while(fgets(szBuffer,sizeof(szBuffer),stdin) != NULL && nY<_ARRAY_SIZE_LINE)
 {			
	static int nLineFeed = 0;

	/* Exclude line-feed based on data.1 schema (Data-Lf-Data-Lf-Data-etc..) */
	if((nLineFeed=!nLineFeed)!=0)
	 {
		/* Read szBuffer integers into n2DArray */
		if(sscanf(szBuffer, "%d%d%d%d%d%d%d%d%d", &n2DArray[nY][0], 
											   &n2DArray[nY][1],
											   &n2DArray[nY][2],
											   &n2DArray[nY][3],
											   &n2DArray[nY][4],
											   &n2DArray[nY][5],
											   &n2DArray[nY][6],
											   &n2DArray[nY][7],
											   &n2DArray[nY][8])!=_ARRAY_SIZE_ITEMS)
		 {
			/* sscanf failed to read at least _ARRAY_SIZE_ITEMS -- program stops */
			fprintf(stderr, "Malformed stdin\n");
			return	-1;
		 }

		/* Move to next Array/Line */
		nY++;
	 }                                                            
 }		

/* Dump Array to stderr & stdout */
for(nY = 0; nY < _ARRAY_SIZE_LINE; nY++)
 {
	for(nX = 0; nX < _ARRAY_SIZE_ITEMS; nX++)
	 {
		fprintf(stdout, "%d ", n2DArray[nY][nX]);
		/*fprintf(stderr, "%d ", n2DArray[nY][nX]);*/
	 }
	fprintf(stdout,"\n");
	/*fprintf(stderr,"\n");*/
 }
 
return 0;
}

 

Καλή συνέχεια.

Δημοσ.

Ευχαριστώ για την βοήθεια! Ο κώδικας λειτουργεί κανονικά!

Υπάρχει ένα μπέρδεμα όμως. Μάλλον κάτι δεν κατάλαβα καλά... Το παραπάνω αρχείο έχει δημιουργηθεί σε περιβάλλον Linux και όταν το ανοίγεις σε περιβάλλον Windows το εμφανίζει διαφορετικά(σε μια ολόκληρη γραμμή όλα τα δεδομένα). Οπότε και εγώ απο τα Windows πάτησα enter για νέα γραμμή. Ένα αρχείο απο τα Linux(χωρίς την παρέμβαση μου...) είναι αυτό: http://rapidshare.com/files/111988149/data.2.html . Μάλλον θα πρέπει να αλλάξει ο κώδικας με βάση αυτό, σωστά;

 

Και κάτι άλλο. Στα windows τρέχει κανονικά με τον τρόπο που αναφέρεις. Στα Linux όμως κάτι δεν λειτουργεί σωστά, ακόμα και με το παραπάνω αρχείο. Ο τρόπος που το κάνω compile και δημιουργώ το εκτελέσιμο είναι ο εξής: gcc -o my_prog my_prog.c και στην συννέχεια το τρέχω ως εξής: my_prog <data.1 χωρίς όμως αποτέλεσμα. Κάνω άραγε κάτι λάθος;

Δημοσ.

Καταρχήν το αρχείο δεν φαίνεται σωστά σε Windows διότι τα CP/M, DOS & Windows (με την ιστορική σειρά που εμφανίστηκαν αυτά τα λειτουργικά συστήματα) διαχειρίζονται διαφορετικά την σήμανση αλλαγής γραμμής (carrier-return & line-feed) από ότι το Unix και κατʼ επέκταση το Linux.

 

Συγκεκριμένα, τα Windows καταγράφουν το “\n” στα αρχεία ως “\r\n”, αντίθετα με το Unix που αρκείται σε ένα “\n” (το \r για το Unix έμμεσα εννοείται).

 

Τώρα όσον αφορά το πρόγραμμα, η αλλαγή που χρειάζεται να κάνεις είναι η αφαίρεση του “if((nLineFeed=!nLineFeed))” διότι το αρχείο data.2 δεν περιλαμβάνει κενά μεταξύ των γράμμων.

 

Για διευκόλυνση, αναρτώ εκ νέου τον κώδικα έχοντας τοποθετήσει το εν λόγο if μεταξύ ένος #ifdef _LINE_FEED. Αν θες την παλιά λειτουργία του προγράμματος (ώστε να δουλεύει με το data.1) απλά δήλωσε ένα #define _LINE_FEED στην έναρξη του source και κάνε φυσικά re-compile.

 

>
/*-Read stdin by Directx v2--------------------------------------------------*/

#include <stdio.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif

/*---------------------------------------------------------------------------*/
#define	_ARRAY_SIZE_LINE	9
#define	_ARRAY_SIZE_ITEMS	9

#ifdef	__BORLANDC__
#pragma argsused
#endif
int main(int argc, char* argv[])
{
char szBuffer[bUFSIZ];
int	 n2DArray[_ARRAY_SIZE_LINE][_ARRAY_SIZE_ITEMS],
	 nY = 0, 
	 nX;

/*
 * Store "stdin" into szBuffer and then into n2DArray, 
 * stop if no data found or if we read more than _ARRAY_SIZE_LINE.
 */
while(fgets(szBuffer,sizeof(szBuffer),stdin) != NULL && nY<_ARRAY_SIZE_LINE)
 {			
	#ifdef _LINE_FEED
	static int nLineFeed = 0;

	/* Exclude line-feed based on data.1 schema (Data-Lf-Data-Lf-Data-etc..) */
	if((nLineFeed=!nLineFeed)!=0)
	 {
	#endif
		/* Read szBuffer integers into n2DArray */
		if(sscanf(szBuffer, "%d%d%d%d%d%d%d%d%d", &n2DArray[nY][0], 
											   &n2DArray[nY][1],
											   &n2DArray[nY][2],
											   &n2DArray[nY][3],
											   &n2DArray[nY][4],
											   &n2DArray[nY][5],
											   &n2DArray[nY][6],
											   &n2DArray[nY][7],
											   &n2DArray[nY][8])!=_ARRAY_SIZE_ITEMS)
		 {
			/* sscanf failed to read at least _ARRAY_SIZE_ITEMS -- program stops */
			fprintf(stderr, "Malformed stdin\n");
			return	-1;
		 }

		/* Move to next Array/Line */
		nY++;
	#ifdef _LINE_FEED
	 }               
	#endif
 }		

/* Dump Array to stderr & stdout */
for(nY = 0; nY < _ARRAY_SIZE_LINE; nY++)
 {
	for(nX = 0; nX < _ARRAY_SIZE_ITEMS; nX++)
	 {
		fprintf(stdout, "%d ", n2DArray[nY][nX]);
		/*fprintf(stderr, "%d ", n2DArray[nY][nX]);*/
	 }
	fprintf(stdout,"\n");
	/*fprintf(stderr,"\n");*/
 }
 
return 0;
}

 

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

Δημοσ.

Ευχαριστώ και πάλι! Τώρα δουλεύει μια χαρά!

Ενδιαφέρον τα ιστορικά στοιχεία που αναφέρεις!

 

Και μια απορία πάνω στον κώδικα(ελπίζω να μην είναι αφελείς...). Τα δύο πρώτα ifdef σε τι ακριβώς εξυπηρετούν; Επίσης η αρχική τιμή του BUFSIZ ποια είναι;

Δημοσ.

Τα δυο πρώτα #ifdef __BORLANDC__ ζητούν από τον compiler, εφ όσον είναι της εταιρίας Borland ή CodeGear, να χρησιμοποιήσει precompiled headers (βελτιώνοντας τον χρόνο του compilation) και να μην παρουσιάσει Warning ότι η μεταβλητές argc, argv και δεν χρησιμοποιούνται από τον κώδικα του main. Επειδή αυτά τα #pragma δεν είναι σίγουρο ότι υπάρχουν σε άλλους compilers (με κάποιες επιφυλάξεις σχετικά με την Microsoft Visual C++ που μπορεί να τα υποστηρίζει - ; -) προτιμώ να τα δηλώνω μέσα σε #ifdef.

 

Η τιμή του BUFSIZ, το οποίο είναι constant της C βιβλιοθήκης stdio.h, εξαρτάται από το implementation του compiler μας. Παραδοσιακά πάντως, πρόκειται για μια μεγάλη τιμή που εγγυάται ότι, αν δηλωθεί ως μέγεθος κάποιου char, μπορεί να αποθηκεύσει μια αρκετά μεγάλη συμβολοσειρά. Στην περίπτωση της CodeGear Turbo C++ το BUFSIZ αντιστοιχεί στην τιμή 512, που υπερκαλύπτει τις ανάγκες της άσκησης.

Δημοσ.
Απο περιέργεια, ποια η διαφορά του stderr με το stdout;

 

Το stderr είναι η έξοδος στην οποία γράφονται τα λάθει (errors) που μπορεί να παρουσιάσει κατά την εκτέλεση του ένα πρόγραμμα.

Το stdout είναι η έξοδος στην οποία γράφονται τα αποτελέσματα του προγράμματος και εξορισμού κατευθύνεται στην οθόνη του τερματικού - υπολογιστή μας (φυσικά μπορούμε να ανακατευθύνουμε το stdout και εμείς κάπου άλλου, πχ. σε ένα αρχείο κτλ.)

 

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

 

Αυτά στην θεωρία, όσον αφορά την πράξη, ελάχιστοι χρησιμοποιούν το stderr αρκούμενοι στο stdout –εκτός και αν έχουν κάποιον καλό λόγο να χρησιμοποιήσουν το stderr διαχωρίζοντας την έξοδο σφαλμάτων από τα αποτελέσματα του προγράμματος, εφόσον το stderr έχει κατευθυνθεί αλλού.

Δημοσ.

εγω δεν ξερω πολλα τώρα αρχισα να μαθενω λιγο λιγο

 

αλλα μηπως εχουν σχεση οι εντολες

 

putc()

putchar()

και νομίζω οτι putc (stdin) ισοδιμαμεί με putchar()

δεν ειμαι σιγουρος γιατι τωρα μαθένω

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...