Sequential IO with stdin & stdout#

Opening a file#

FILE *fopen(char *path, char* mode);
int fclose(FILE *stream);

When we open a file, then we get a stream or a FILE *. We use the stream with the following functions.

Writing & reading strings#

int fputs(char *s, FILE *stream);
char *fgets(char *s, int size, FILE *stream);

// With formatting
int fprintf(FILE *stream, char *format);
int fscanf(FILE *stream, char *format);

// stdout
int puts(char *s);
  • f stands for file.

  • puts Adds a newline. If you don't want it, use printf or fputs.

  • fgets requires size and stdout explicitly.

  • the sister of puts, char *gets(char *s) used to exist, but is deprecated now due to security. It is impossible to know in advance how many characters we will read, so it can lead to buffer overflow.

🤔 Question to ponder

Why does fgets require size but fputs does not?

Opening modes#

mode

meaning

mode+

meaning

r

read

r+

read + write

w

write

w+

write + read

a

append

a+

append + read

âš¡ Live programming

Example below

#include <stdio.h>

#define LINE_MAX 80

void write_to_a_file() {
  FILE *fp = fopen("file.txt", "w");
  // open file with only write permissions

  fputs("First string", fp);
  fputs("Second string", fp);
  fputs("\nNew line", fp);

  fclose(fp);
}

void read_from_a_file() {
  FILE *fp = fopen("file.txt", "r");
  // only read permissions

  char line[LINE_MAX];
  fgets(line, LINE_MAX, fp);
  puts(line);

  fgets(line, LINE_MAX, fp);
  puts(line);
}

int main() {
  write_to_a_file();
  read_from_a_file();
}
First stringSecond string

New line

Activity 59 (Processing temperature data)

temperatures.txt contains several temperature measurements:

20
21
18
18
19
20

20

Write a single program that do the following actions. For each point, open and close the file separately.

  1. Reads five lines from temperatures.txt file and prints them to the console.

  2. Creates a new file temperatures-today.txt and writes three temperature measurements.

  3. Appends a new measurement to temperatures.txt.

  4. Creates an empty file measurements-done.txt

  5. Reads five lines from temperatures.txt and writes the temperatures which are greater than 19 to temperatures-filtered.txt. Use a for loop that reads five times.

    You can use fgets + strtol or fscanf for integer conversion.

  6. Similar to last, but read all lines using while(line = fgets(...)).

    What does fgets return if we arrive at the end of the file? Refer to the documentation.

Appendix#

Character-oriented functions#

int fputc(int c, FILE *stream);
int fgetc(FILE *stream);

// stdout & stdin
int putchar(int c);
int getchar(void);

String-oriented functions use character-oriented functions. This is useful for implementing input-output (IO) for special hardware. Let's assume you are programming a microcontroller and want to use an LCD to display data. You can implement putchar to write a character to the LCD's display memory and maybe to move the cursor afterwards, e.g.,:

int putchar(int c) {
  lcd_write(c);  
  lcd_move_cursor();
  return c;
}

Then you can use puts or printf to display whole strings.

🥡 Takeaway

String-oriented functions are built on top of the character-oriented functions.

If you provide, i.e., implement a character-oriented function like putc, you can determine what string functions do.

putc && getc#

int putc(int c, FILE *stream);
int getc(FILE *stream);

These are input-output-wise functionally equivalent to fputc and fgetc. I don't mention these functions, because these functions are in the standard for performance. They are allowed to be implemented as macros.

More info: