[Courses] Fwd: Re: C Programming For Absolute Beginners, Lesson 2: Fun With Printf, Scanf, Puts, and Variables

Carla Schroder carla at bratgrrl.com
Wed Feb 22 00:10:14 UTC 2012


Here is some interesting stuff from Jim on stdin, stdout, stderr, fgets, and 
fputs. Have fun!

Carla




    Here are some links about std in, out, err: 

General 
http://en.wikipedia.org/wiki/Standard_streams 

Mainly shell use 
http://people.ischool.berkeley.edu/~kevin/unix-tutorial/section10.html 
http://www.codecoffee.com/tipsforlinux/articles2/042.html 

Shell and C 
http://www.cs.bu.edu/teaching/c/file-io/intro/ 

C-specific 
http://en.wikipedia.org/wiki/C_file_input/output 
http://icecube.wisc.edu/~dglo/c_class/stdio.html 
http://www.cprogramming.com/tutorial/cfileio.html 
http://www.mrx.net/c/program.html 
------------------------

    I want to give it a try. The following augments the last four 
links above. 


// readtxt.c    20120221    jim at well.com    james stockford 
// demonstrates how to read text from a file 

#include <stdio.h> 

int main() 
{ 
    FILE *myfile; 
    char mybuffer[81]; 

    myfile = fopen("/home/jim/.bashrc","r"); 

    fgets(mybuffer, 81, myfile); 

    puts(mybuffer); 
    fputs(mybuffer, stdout); 
    fputs(mybuffer, stderr); 

    fclose(myfile); 
}


    I recall the saying "everything in unix is a file". Not very
helpful, I tho't when I first heard it. 

    A file is defined as a stream of bytes. 
    There are two categories: 
* files with bytes that are only ASCII (values from 0 to 127), meant 
to be interpreted as text, and 
* files with bytes that are fully binary (values from 0 to 255), used 
for everything but text, for example, a pixel might be described as 
three or four bytes, and a file might contain information about a lot 
of pixels. 
    Beginning examples stick to ASCII text files, and C has functions 
designed to work with just text files as well as functions designed 
to work with fully binary files. 

#include <stdio.h>  // the stdio.h file for basic file handling 

    To open a file is to ask the kernel to do the work and return 
a number that represents the file. 
FILE *myfile;  // FILE * says myfile can store a number for a file 
          // the * means myfile stores an address, ignore for now 

    I have to have a place in memory where my program can store a 
line of text from the file. The following tells the gcc to create 
an array of 81 bytes in memory with the name mybuffer. 
char mybuffer[81]; 

myfile = fopen("/home/jim/.bashrc", "r");  // fopen asks the kernel 
          // to open the .bashrc file in my home directory in read- 
          // only mode 
          // myfile stores the number that the kernel returns 

    I use the fgets function to read a line of text from the file. 
fgets(mybuffer, 81, myfile); // the fgets function is designed to 
         // interpret its three arguments as 
         // the address of a storage area in memory 
         // the maximum number of characters to read 
         // the number of an open text file

    The fgets function asks the kernel to give it bytes from the file 
until one of the bytes is a newline character or the total number of 
bytes is 81. 
    The name fgets has three distinctive parts: 
"f" means "file" 
"get" means read some bytes 
"s" means this function is designed to work with text strings 

    I want to prove to myself that my program really did read a line 
of text from the /home/jim/.bashrc file. Here are three ways to do 
that; all three print a line of text to the terminal. 
puts(mybuffer); 
fputs(mybuffer, stdout); 
fputs(mybuffer, stderr); 

    The name puts has two parts, the name fputs has three parts. 
The difference in the names is the "f" and the difference in the 
arguments is stdout or stderr. 
    The puts (put string) function has got the stdout information 
built in. It can only write to the standard output. 
    The fputs function does not have any file information built in 
and requires the number of some open text file; I chose to use 
stdout in one call and stderr in the subsequent call. The stdio.h 
file declares stdout and stderr to be FILE type, and the magic is 
that there's no need to ask the kernel for a number (no fopen call). 
    There are three names for standard output "files". 
stdin   (standard input) has a value of 0 
stdout  (standard output) has a value of 1 
stderr  (standard error) has a value of 2 
    Here's where "everything is a file" comes in handy. 
* The keyboard is a file, a stream of bytes (the stuff I type) 
with a guaranteed file number of 0. It's a read-only file. 
* The display (the terminal window) is a file with a guaranteed 
file number of 1 that is write-only; programs send streams of 
bytes to the terminal window. 
* The display (the terminal window) also has a guaranteed file 
number of 2. It's a write-only file to which programs send  
streams of bytes. 
    Using stderr instead of stdout seems to work the same, both 
send the line of text to the display. But stdout and stderr are 
different files. I use redirection in the shell to verify. 

     Using normal redirection, the output of my program stores 
the puts and stdout output to ofile and displays only the stderr 
output. 
$ a.out > ofile 
# ~/.bashrc: executed by bash(1) for non-login shells.
$ ls 
ofile 

    Redirecting standard error, the output of my program stores 
the stderr output to efile and displays the puts and stdout 
output. 
$ a.out 2> efile 
# ~/.bashrc: executed by bash(1) for non-login shells.

# ~/.bashrc: executed by bash(1) for non-login shells.
$ ls 
efile  ofile  

    I've asked the kernel to open the /home/jim/.bashrc file and 
the kernel keeps that file open until I ask it to close it. 
fclose(myfile); 

    These standard input, output, and error techniquest don't work 
with GUI programs. 
-----------------------

    About the * character. It's sometimes called "splat" and can 
either represent the multiplication operator or the dereference 
(aka "indirection") operator. 

int x = 5 * 6;  // multiplication, spat is between to operands 

FILE *myfile    // dereference, splat is to the left of one operand 
    Here splat means that myfile stores the address of a value that 
is the address of a FILE type. 

char *mystring  
    Here splat means that mystring stores the address of a value 
that is the address of a single character. 

    Above, myfile is a pointer to a FILE type and mystring is a 
pointer to a character. Note that the term "pointer" means an 
identifier that stores an address. 




On Tue, 2012-02-21 at 11:26 -0800, Carla Schroder wrote: 
> On Tuesday, February 21, 2012 12:29:35 PM Kathryn Hogg wrote:
> > On 2012-02-21 12:26, Christopher Howard wrote:
> > > Some discussion should probably be made of buffering issues that can
> > > occur while mixing reading and writing on the command-line. I.e., the
> > > program might start waiting for the user input before it actually
> > > prints
> > > out the line telling the user what to enter. It's been a long time
> > > since
> > > I have had to deal with this (normally user input is provided through
> > > the program arguments). However, I think it involves flushing
> > > stdin/stdout buffers with fflush().
> > 
> > Reading from stdin (which is what scanf is doing) will cause stdout to
> > be flushed.
> 
> Excellent, this is exactly the sort of clear, pertinent explanation that I 
> like, and try to write myself.  (This was rather a half-baked lesson so it 
> needs  help.)
> 
> Anyone who does not have a good understanding of stdin and stdout should 
look 
> them up because they are fundamental to all computing.
> 
> And remember, there are no stupid questions-- don't be shy!
> 
> Carla
> 


-----------------------------------------
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Carla Schroder
ace Linux nerd
author of Linux Cookbook,
Linux Networking Cookbook,
Book of Audacity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



More information about the Courses mailing list