Quick Navigation Bar functions, preprocessor :: input/output and file i/o :: pointers [ toc | forums ] |
Note: If the document URL does not begin with https://randu.org/tutorials/c/ then you are viewing a copy. Please direct your browser to the correct location for the most recent version. |
With most of the basics of C under our belts, lets focus now on grabbing Input and directing Output. This is essential for many programs that might require command line parameters, or standard input.
int printf(const char *format, ...);printf takes in a formatting string and the actual variables to print. An example of printf is:
int x = 5; char str[] = "abc"; char c = 'z'; float pi = 3.14; printf("\t%d %s %f %s %c\n", x, str, pi, "WOW", c);The output of the above would be:
5 abc 3.140000 WOW zLet's see what's happening. The
\t
line signifies an
escape sequence, specifically, a tab. Then the %d
specifies a conversion specification as given by the variable x.
The %s
matches with the string and the %f
matches with the float. The default precision for %f
is 6 places after the decimal point. %f
works for both
floats and doubles. For long doubles, use %Lf
.
The %s
matches with the "WOW", and the %c
tells printf to output the char c. The \n
signifies a
newline.printf("%10.4d", x);Would print this:
0005The
.
allows for precision. This can be applied to
floats as well. The number 10
puts 0005 over 10 spaces
so that the number 5 is on the tenth spacing. You can also add
+
and -
right after %
to
make the number explicitly output as +0005. Note that this does not
actually change the value of x. In other words, using
%-10.4d
will not output -0005.%e
is useful for outputting floats using
scientific notation. %le
for doubles and %Le
for long doubles.int scanf( const char *format, ...);Looks similar to printf, but doesn't completely behave like printf does. Take for example:
scanf("%d", x);You'd expect scanf to read in an int into x. But scanf requires that you specify the address to where the int should be stored. Thus you specify the address-of operator (more on this when we get to pointers). Therefore,
scanf("%d", &x);will put an int into x correctly.
int x, args; for ( ; ; ) { printf("Enter an integer bub: "); if (( args = scanf("%d", &x)) == 0) { printf("Error: not an integer\n"); continue; } else { if (args == 1) printf("Read in %d\n", x); else break; } }The code above will fail. Why? It's because scanf isn't discarding bad input. So instead of using just
continue;
, we have
to add a line before it to digest input. We can use a function
called digestline()
.
void digestline(void) { scanf("%*[^\n]"); /* Skip to the End of the Line */ scanf("%*1[\n]"); /* Skip One Newline */ }This function is taken from Weiss pg. 341. Using assignment suppression, we can use
*
to suppress anything contained in
the set [^\n]
. This skips all characters until the
newline. The next scanf allows one newline character read. Thus
we can digest bad input!scanf/fscanf
is
fgets
. The prototype is:
char *fgets(char *s, int size, FILE *stream);
fgets
reads in size - 1
characters from
the stream
and stores it into *s
pointer. The string is automatically null-terminated.fgets
stops reading in characters if it reaches
an EOF or newline.sscanf
,
see below.sscanf
library
call is handy. It's prototype:
int sscanf(const char *str, const char *format, ...);
sscanf
works much like fscanf
except it takes a character pointer instead of a file pointer.fgets/sscanf
instead
of scanf/fscanf
you can avoid the "digestion"
problem (or bug, depending on who you talk to :)int fprintf(FILE *stream, const char *format, ...);fprintf takes in a special pointer called a file pointer, signified by FILE *. It then accepts a formatting string and arguments. The only difference between fprintf and printf is that fprintf can redirect output to a particular stream. These streams can be
stdout
, stderr
, or a file pointer.
More on file pointers when we get to fopen
.fprintf(stderr, "ERROR: Cannot malloc enough memory.\n");This outputs the error message to standard error.
int fscanf( FILE *stream, const char *format, ...);
int fflush(FILE *stream);Not very difficult to use, specify the stream to fflush.
FILE *fopen (const char *path, const char *mode);fopen returns a file pointer and takes in the path to the file as well as the mode to open the file with. Take for example:
FILE *Fp; Fp = fopen("/home/johndoe/input.dat", "r");This will open the file in /home/johndoe/input.dat for reading. Now you can use fscanf commands with Fp. For example:
fscanf(Fp, "%d", &x);This would read in an integer from the input.dat file. If we opened input.dat with the mode "w", then we could write to it using fprintf:
fprintf(Fp, "%s\n", "File Streams are cool!");
int fclose( FILE *stream );You would just give fclose the stream to close the stream. Remember to do this for all file streams, especially when writing to files!
#define ERR_MSG( fn ) { (void)fflush(stderr); \ (void)fprintf(stderr, __FILE__ ":%d:" #fn ": %s\n", \ __LINE__, strerror(errno)); } #define METAPRINTF( fn, args, exp ) if( fn args exp ) ERR_MSG( fn )This will create an ERR_MSG macro to handle error messages. The METAPRINTF is the meta-wrapper for our printf type functions. So let's define our printf type macros:
#define PRINTF(args) METAPRINTF(printf, args, < 0) #define FPRINTF(args) METAPRINTF(fprintf, args, < 0) #define SCANF(args) METAPRINTF(scanf, args, < 0) #define FSCANF(args) METAPRINTF(fscanf, args, < 0) #define FFLUSH(args) METAPRINTF(fflush, args, < 0)Now we have our wrapper functions. Because args is sent to METAPRINTF, we need two sets of parentheses when we use the PRINTF macro. Examples on using the wrapper function:
PRINTF(("This is so cool!")); FPRINTF((stderr, "Error bub!"));Now you can this code into a common header file and be able to use these convenient macros and still be able to check for return values! (Make sure you have included the string.h library)
fputs, getchar, putchar, ungetc
. Refer to
the man pages on these functions or in the Weiss text.ls -l
command before.
ls -l *.c
would display all c files with extended
information. These parameters and arguments can be handled by your
c program through getopt(3).
int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg; extern int optind, opterr, optopt;In order for us to utilize argc and argv, we must allow these as parameters on our main() function:
int main(int argc, char **argv)Now that we have everything set up, lets get this show on the road. Here's an example of using getopt:
int ich; while ((ich = getopt (argc, argv, "ab:c")) != EOF) { switch (ich) { case 'a': /* Flags/Code when -a is specified */ break; case 'b': /* Flags/Code when -b is specified */ /* The argument passed in with b is specified */ /* by optarg */ break; case 'c': /* Flags/Code when -c is specified */ break; default: /* Code when there are no parameters */ break; } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); }This code might be a bit confusing if taken in all at once.
optarg
will contain the string "gradient".if (optind < argc) {
checks for aguments passed in without an accompanying
parameter. optind
is the current index in the
list of arguments passed in in the argv-list. argc
is the total number of arguments passed in../junk -b gradient yeehaw
the variables would look like:
Variable Contains ------------------ ---------- argc 4 argv[0] "./junk" argv[1] "-b" argv[2] "gradient" argv[3] "yeehaw" optarg at case 'b' "gradient" optind after while 3 getopt loop
Notice: Please do not replicate or copy these pages and
host them elsewhere. This is to ensure that the latest version can always
be found here.
Disclaimer: The document author has published these pages
with the hope that it may be useful to others. However, the document
author does not guarantee that all information contained on these
webpages are correct or accurate. There is no warranty, expressed or
implied, of merchantability or fitness for any purpose. The author does
not assume any liability or responsibility for the use of the information
contained on these webpages.
If you see an error, please send an email to the address below indicating
the error. Your feedback is greatly appreciated and will help to
continually improve these pages.