In C, input/output operations are not part of the language: there are no dedicated statements, only functions added through the standard library. This separation gives flexibility, but shifts onto the programmer the responsibility of correctly specifying the format of the data.
1Lab objectives
- Understanding the concept of a stream and the five predefined logical devices
- Using character-level read/write functions
- Reading and printing character strings
- Correctly using format specifiers in
printfandscanf - Recognizing and avoiding the classic pitfalls of the
scanffunction
2Standard streams
Transfers to and from physical devices happen through logical devices called streams. There are two categories: text streams, which transfer characters organized into lines, and binary streams, which transfer bytes with no imposed structure.
| Stream | Type | Associated with | Can be redirected? |
|---|---|---|---|
stdin | text | the keyboard - standard input | yes |
stdout | text | the monitor - standard output | yes |
stderr | text | the monitor - the error output | yes |
stdprn | binary | the printer (DOS PRN device) | no |
stdaux | binary | auxiliary input/output (DOS AUX) | no |
program > result.txt)
errors still show up on the screen, instead of being hidden in the file.3Character-level operations
| Function | Role | Notes |
|---|---|---|
int getchar(void) | reads a character from stdin | waits for Enter; returns EOF at end of file |
int getch(void) | reads a character with no echo | does not wait for Enter; specific to conio.h, non-portable |
int getche(void) | reads a character with echo on screen | does not wait for Enter; non-portable |
int putchar(int c) | writes a character to stdout | returns the character written |
getchar() must be able to
signal the end of the stream through the value EOF (usually −1), which does not
fit in the unsigned char range. If the result is stored in a char,
the test c != EOF may never work.4String operations
| Function | Role | Risk |
|---|---|---|
gets(s) | reads an entire line, including spaces | dangerous - does not limit the length; removed from the standard |
fgets(s, n, stdin) | reads at most n−1 characters | safe; keeps the trailing '\n' character |
puts(s) | prints a string and adds a newline | - |
scanf("%s", s) | reads a word (stops at whitespace) | cannot read sentences with spaces |
fgets instead of gets.
To remove the leftover newline character:
s[strcspn(s, "\n")] = '\0';5Formatted input/output
The structure of a specifier
%[flag][width][.precision][modifier]type %-8.3f │││ │ └── type: f = real ││└─┴──── precision: 3 decimals │└─────── minimum width: 8 characters └──────── flag: - = left alignment
| Specifier | Data type | Example output |
|---|---|---|
%d, %i | int | -42 |
%u | unsigned int | 4294967254 |
%f | float / double | 3.141593 |
%.2f | real with 2 decimals | 3.14 |
%e | scientific notation | 3.141593e+00 |
%c | char | A |
%s | character string | text |
%x, %X | hexadecimal | ff / FF |
%o | octal | 377 |
%p | address (pointer) | 0x7ffd3a2c |
%% | a literal percent character | % |
6Specifier explorer
Choose a specifier and a value, then watch exactly what printf
prints. Try mismatched combinations - for example %c with the value 65 - to
understand why the compiler does not warn you.
7Reading pitfalls
scanf("%d", n); instead of scanf("%d", &n); passes the value of
the variable instead of its address. The program compiles, but crashes badly at run time.scanf("%d", &n);, the Enter key is left unread in stdin. An
immediately following scanf("%c", &c); will pick up that '\n',
not the intended character. Solution: scanf(" %c", &c); - the space in the
format skips over whitespace characters.printf("%d", 3.14); produces no compile error, but prints a meaningless value,
because it interprets the bits of a double as an int.scanf returns 0 and leaves
the text in the buffer, which can lead to an infinite loop. Always check the return value:
if (scanf("%d", &n) != 1) { ... }8Source code
#include <stdio.h>
int main(void)
{
int c; // int, NOT char, so it can be compared with EOF
int letters = 0, digits = 0, spaces = 0, other = 0;
printf("Enter text (Ctrl+Z / Ctrl+D to finish):\n");
while ((c = getchar()) != EOF) {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) letters++;
else if (c >= '0' && c <= '9') digits++;
else if (c == ' ' || c == '\t' || c == '\n') spaces++;
else other++;
}
printf("\nLetters: %d Digits: %d Spaces: %d Other: %d\n",
letters, digits, spaces, other);
return 0;
}
#include <stdio.h>
#include <string.h>
int main(void)
{
char name[50];
int age;
printf("Full name: ");
fgets(name, sizeof(name), stdin); // safe: limits the length
name[strcspn(name, "\n")] = '\0'; // remove the newline
printf("Age: ");
while (scanf("%d", &age) != 1) { // check that reading succeeded
printf("Invalid value. Try again: ");
while (getchar() != '\n'); // flush the buffer
}
printf("\n%-20s %3d years old\n", name, age);
return 0;
}
#include <stdio.h>
int main(void)
{
printf("%-12s %8s %10s\n", "Product", "Qty", "Price");
printf("--------------------------------\n");
printf("%-12s %8d %10.2f\n", "Resistor", 120, 0.15);
printf("%-12s %8d %10.2f\n", "Capacitor", 45, 0.80);
printf("%-12s %8d %10.2f\n", "Microcontroller", 8, 24.50);
// the same number, in different bases
int v = 255;
printf("\n%d in decimal = %o in octal = %X in hex\n", v, v, v);
// printing a literal percent sign
printf("Progress: %d%%\n", 75);
return 0;
}
9Code workshop
Output formatting is learned by experimenting. Change the numbers inside
the specifiers (%8.3f, %-12s) and watch the columns move.
scanf, in order. In a real program, the user
would type them one at a time.10Work tasks
- Write a program that reads characters until EOF and counts the letters, digits, and spaces.
- Read a full name (with spaces) using
fgetsand print it withputs. - Reproduce the leftover-Enter-in-the-buffer trap, then fix it with
" %c". - Print the number 255 in decimal, octal, and hexadecimal, in a single
printf. - Build an aligned table with three columns, using explicit widths and alignments.
- Implement robust reading of an integer, with retry on invalid data.
- Test what
printf("%d", 3.14)prints and explain the result.
11Extended application
stdio.h and ctype.h.