Skip to content

11.18 IO ASCII EOF

intro-to-computer-science-gtiit-06-2024.pdf

Example: Computing Powers of 2

/* Some powers of 2 are printed. */

#include <stdio.h>

int main(void) {
    int i = 1, power = 1;
    while (i <= 10) {
        printf("%-6d", power *= 2);
        i++;
    }
    printf("\n");
    return 0;
}

The output of the program is:

2     4     8     16    32    64    128   256   512   1024

Example: Computing Powers of 2

/* Some powers of 2 are printed. */

#include <stdio.h>

int main(void) {
    for (int i = 1, power = 2; i <= 10; i++) {
        printf("%-6d", power);
        power = power * 2;
    }
    printf("\n");
    return 0;
}

The output of the program is:

2     4     8     16    32    64    128   256   512   1024

About printf()​ Formatting

printf("%-6d", power *= 2);
  • The placeholder %-6d​ indicates that the value is to be printed as a decimal integer with a field width of 6. (including the length of number)
  • The minus sign indicates that the value is to be left-adjusted in its field.

Try without the minus sign to align values to the right: %6d​.

Complete information about formatting is available in the manpage of printf()​:

$ man 3 printf

Standard Input and Standard Output

  • Consider the following program:

  • It reads characters from the standard input (normally the keyboard) with scanf()​.

  • It writes each character twice to the standard output (normally the terminal screen) with printf()​.
  • %c​ is the placeholder to read and print a single character.

Example Program:

#include <stdio.h>

int main(void) {
    char c;
    while (scanf("%c", &c) == 1) {
        printf("%c", c);
        printf("%c", c);
    }
    return 0;
}

If we input abcd​, then the computer read in sequence 'a''b''c'd''\n''EOF'


Return Value of scanf()

  • When scanf()​ is successful, it returns the number of input items successfully matched and assigned.
  • This value can be fewer than provided for, or even zero, in the event of an early matching failure.
  • In the example:
scanf("%c", &c)
  • Details:

  • It has a single placeholder (%c​).

  • While scanf("%c", &c)​ returns 1​, the reading of input is correct.

Example Program:

#include <stdio.h>

int main(void) {
    char c;
    while (scanf("%c", &c) == 1) {
        printf("%c", c);
        printf("%c", c);
    }
    return 0;
}

Redirection of Input and Output

  • Suppose we compile the program into an executable dbl_out:
$ tcc -w dbl_out.c -o dbl_out
  • We can use redirection to allow the executable to receive input and produce output in different ways:

$ ./dbl_out​: Input from keyboard (stdin), output to screen (stdout)
$ ./dbl_out < infile​: Input from file "infile", output to screen (stdout)
$ ./dbl_out > outfile​: Input from keyboard (stdin), output to file "outfile"
$ ./dbl_out < infile > outfile​: Input from file "infile", output to file "outfile"


Why does the loop end?

  • When using this program with a standard input redirection:
$ ./dbl_out < infile
  • The input file is consumed.
  • When it is completely consumed, an End-of-File (EOF) signal is sent to the program, making scanf()​ return a special value (not 1​).

Example Code:

#include <stdio.h>

int main(void) {
    char c;
    while (scanf("%c", &c) == 1) {
        printf("%c", c);
        printf("%c", c);
    }
    return 0;
}

The End-of-File Signal

  • When the input is taken from a file, the end-of-file signal is automatically generated when the input file is completely fed to the program.
  • When a program takes its input from the keyboard, it is necessary to generate an end-of-file signal manually.
  • In Linux, Ctrl+D​ is the typical way to generate an end-of-file signal.

Control+C and End-of-File Are Not The Same

  • The following command is of special interest:
$ ./dbl_out > outfile
  • This command causes dbl_out​ to take its input from the keyboard (standard input) and to write its output in the file outfile​, provided that you issue an end-of-file signal when you are finished.
  • Important: If, instead of typing Ctrl+D​, you type Ctrl+C​ to kill the program, nothing gets written into outfile​!

getchar()​ and putchar()

  • Functions getchar()​ and putchar()​ are defined in stdio.h​.
  • Usage:

  • getchar()​ is used to read a single character from the keyboard.

  • putchar()​ is used to write a single character to the screen.
  • Common use cases:

  • Typically used to manipulate character data.

  • Sometimes more convenient to use than scanf()​ and printf()​.

getchar()​ Example

int main() {
    int input;
    input = getchar(); // Read a single character from input
    if (input == 'a' || input == 'e' || input == 'i' || input == 'o' || input == 'u') {
        printf("We have a vowel!\n");
    } else {
        printf("This is not a vowel.\n");
    }
    return 0;
}

Example with getchar()​ and putchar()

int main(void) {
    int c;
    // Continuously read characters until EOF is encountered
    while ((c = getchar()) != EOF) {
        putchar(c); // Output the character
        putchar(c); // Output the character again
    }
    return 0;
}

Example with getchar()​ and putchar()

int main(void) {
    int c;
    c = getchar(); // Read the first character
    while (c != EOF) { // Continue until EOF is encountered
        putchar(c); // Output the character
        putchar(c); // Output the character again
        c = getchar(); // Read the next character
    }
    return 0;
}

ASCII

image

The American Standard Code for Information Interchange (ASCII) is a standard that sets how to interpret integers from 0 to 127 (0x00 to 0x7F in hexadecimal) as printable characters and control codes.

image​​image


getchar()​ and Integer Constants According to ASCII

int main() {
    int input;
    input = getchar();
    if (input == 97 || input == 101 || input == 105 || input == 111 || input == 117)
        printf("We have a vowel!\n");
    else
        printf("This is not a vowel.\n");
    return 0;
}

getchar()​ and Integer Constants (in Hexadecimal)

int main() {
    int input;
    input = getchar();
    if (input == 0x61 || input == 0x65 || input == 0x69 || input == 0x6F || input == 0x75)
        printf("We have a vowel!\n");
    else
        printf("This is not a vowel.\n");
    return 0;
}

Why is c​ of type int​ and not char​?

  • EOF​ is defined in stdio.h​ as -1​.

  • The actual value of EOF​ is system-dependent.

  • Value -1​ is often used, but it is better to use EOF​ and let the file stdio.h​ define its concrete value.
  • getchar()​ evaluates to an int​ value, not char​.

  • The value used to signal the end of the file cannot be a character value (e.g., -1​).

  • Because c​ is an int​, it can hold all possible character values and the special value EOF​.
int main(void) {
    int c;
    while ((c = getchar()) != EOF) {
        putchar(c);
        putchar(c);
    }
    return 0;
}

ASCII: Observations

  • The most commonly used sequences of characters exist in ASCII as sequences:

  • Characters '0'​ to '9'​ (digits)

  • Characters 'A'​ to 'Z'​ (uppercase Latin alphabet)
  • Characters 'a'​ to 'z'​ (lowercase Latin alphabet)

image

Checking whether some character is a digit, an uppercase letter, or a lowercase letter can be done with a condition that checks for an interval.


Example: Capitalizing Letters

#include <stdio.h>

int main(void) {
    int c;
    while ((c = getchar()) != EOF) {
        if (c >= 'a' && c <= 'z') {
            putchar(c + 'A' - 'a');
        } else {
            putchar(c);
        }
    }
    return 0;
}

No Need to Learn ASCII Codes

  • It is not necessary to memorize the integer ASCII codes that correspond to characters.
  • It’s generally enough to remember that character codes are integers, and groups of related commonly used symbols are organized in sorted intervals.

Some Character Constants and Their Corresponding Integer Values:

Character Constants Corresponding Values
'a'​, 'b'​, 'c'​ … 'z' 97, 98, 99 … 122
'A'​, 'B'​, 'C'​ … 'Z' 65, 66, 67 … 90
'0'​, '1'​, '2'​ … '9' 48, 49, 50 … 57
'&'​, '*'​, '+' 38, 42, 43