© Mikael Olsson 2019
Mikael OlssonModern C Quick Syntax Referencehttps://doi.org/10.1007/978-1-4842-4288-9_20

20. Input Handling

Mikael Olsson1 
(1)
Hammarland, Länsi-Suomi, Finland
 
When a C program is executed, it can accept arguments that are passed to it from the command line. These command-line arguments are useful for controlling the behavior of the program from outside the code. The arguments are passed to the main function, which is then set to accept two parameters as shown here.
int main(int argc, char* argv[]) {}
The integer argc is the number of arguments passed, and argv is a pointer array to the supplied command-line arguments. The first argument argv[0] is the name of the program, so the argument count in argc begins with 1 when no arguments are passed. If the program name is not available on the host environment, the first element will be an empty string instead. A simple program that prints all arguments is given here.
#include <stdio.h>
int main(int argc, char* argv[]) {
  int i;
  for(i=0; i<argc; i++) {
    printf("Argument %d is: %s\n", i, argv[i]);
  }
}
When a program is executed from a terminal window, the string arguments are listed after the file name, separated by spaces. If the argument itself contains a space it can be delimited by double quotes. In the following example, the previous program is compiled and executed with two arguments.
gcc myapp.c -o myapp.exe
./myapp.exe test "Hello World"
Argument 0 is myapp.exe
Argument 1 is test
Argument 2 is Hello World

Keyboard Input

Input from the command line can also be passed to a program while it is running, using for instance the scanf function. The first argument to this function is a formatting string that uses the same placeholders as printf, such as %d for accepting an int type. The second argument is the address to a variable that will hold the value of the expected input type.
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h> /* scanf */
int main(void)
{
  int a, b, c;
  printf("Enter first number: ");
  scanf("%d", &a);
  printf("Enter second number: ");
  scanf("%d", &b);
  c = a + b;
  printf("%d + %d = %d\n", a,b,c);
}
Visual Studio considers scanf to be unsafe, so to use it with that compiler, you need the define directive seen at the start of this code. Given the proper input (followed by pressing Return), the function performs as expected.
gcc myapp.c -o myapp.exe
./myapp.exe
Enter first number: 2
Enter second number: 3
2 + 3 = 5
The scanf function does not perform bounds checking, so it is susceptible to buffer overflows when reading more than one character at a time. A more robust function for handling user input is fgets, which reads a string of text until the newline character appears. This function takes three arguments: the buffer, the maximum length of characters to read (including the null character), and the stream from which to read. The stream in this case is the standard input stream, designated by stdin .
#include <stdio.h> /* fgets */
int main(void)
{
  char name[10];
  printf("Enter your name: ");
  fgets(name, 10, stdin);
  printf("Hi %s", name);
}
Keep in mind that the newline character that marks the end of the input will be included in the string. If the string provided is too long, only the first nine characters plus the NULL character will be stored in this char array.
gcc myapp.c -o myapp.exe
./myapp.exe
Enter your name: Tom
Hi Tom

File Input and Output

Writing a file to the hard drive allows a program to store data that persists even after the program has shut down. A file can be opened for reading or writing using the fopen function. This function returns a pointer to a file handler and it takes two arguments: the file to open (including the path if needed) and the access mode for the file. Specifying the access mode as "w+" will create an empty file and return a handler that allows both reading and writing. Once it’s opened, a variant of printf called fprintf can be used to write content to the file. Note that the file handler is passed as the first argument to this function. After completing this task the file handler should be closed to free up resources by passing it to the fclose function.
#define _CRT_SECURE_NO_DEPRECATE /* for Visual Studio */
#include <stdio.h> /* fopen, fprintf, fclose */
int main(void)
{
  /* Create and open a file for reading/writing */
  FILE *fp = fopen ("file.txt", "w+");
  /* Write text to the file */
  fprintf(fp, "%s\n%s", "Hello", "World");
  /* Close the file */
  fclose(fp);
}
A text file has now been created in the same folder as the program. We will now read its content with another program. First the file is opened for reading by passing the r argument to fopen. Using the fgets function, the file is read one line at a time in a loop until the end of the file is reached, indicated by NULL being returned. Once all content has been read, the file is closed.
#define _CRT_SECURE_NO_DEPRECATE /* for Visual Studio */
#include <stdio.h> /* fopen, fgets, fclose */
int main(void)
{
  char buf[100];
  FILE *fp = fopen("file.txt", "r");
  while(fgets(buf,100,fp)!=NULL) {
    printf("Line contains: %s\n", i, buf);
  }
  fclose(fp);
}

Error Handling

The return value of file-handling functions should be checked to make sure each operation is successful. For instance, in this case if the file to be read is missing, then fopen will fail. In addition to returning NULL, the function will set the errno integer. This variable is used by many standard C library functions to indicate what kind of error has occurred. The variable is provided by the errno.h header file and is zero at program startup, indicating no error. Prior to calling a library function, the variable should be reset to zero since library functions will never do this in the absence of errors.
#define _CRT_SECURE_NO_DEPRECATE /* for Visual Studio */
#include <stdio.h> /* fopen, fclose */
#include <errno.h> /* errno */
int main(void)
{
  errno = 0;
  FILE *fp = fopen("missing.txt", "r");
  if(fp == NULL) {
    perror("File read failed");
    return 1; /* failed */
  }
  fclose(fp);
  return 0; /* success */
}
The perror function seen here prints a descriptive error message based on the current errno value.
gcc myapp.c -o myapp.exe
./myapp.exe
File read failed: No such file or directory