Allocating Memory for String Input
Before reading a string, sufficient memory must be allocated to store it. The compiler does not automatically allocate space based on input length.
Incorrect approach:
char *ptr;
scanf("%s", ptr); // ptr is uninitialized, leading to undefined behavior.
Correct approach:
char buffer[100];
scanf("%s", buffer);
The gets() Function
The gets() function reads a line from standard input until a newline is encountered, discards the newline, and stores the characters, appending a null terminator.
Prototype:
char *gets(char *str);
Example usage:
#include <stdio.h>
int main() {
char input_line[100];
gets(input_line);
printf("%s\n", input_line);
return 0;
}
Critical Flaw of gets()
gets() does not check buffer boundaries. Input longer than the allocated space causes a buffer overflow, potentially crashing the program or creating security vulnerabilities. Consequently, gets() was deprecated in C99 and removed from the C11 standard, though some compilers still support it for legacy code.
The fgets() Function
fgets() is a safer alternative, allowing specification of a maximum read size and the input stream.
Prototype:
char *fgets(char *str, int num, FILE *stream);
It reads up to num-1 characters or until a newline, storing the newline if encountered, and appends a null terminator. It returns str on success or NULL on error or end-of-file.
Example reading from stdin:
#include <stdio.h>
int main() {
char data[20];
fgets(data, sizeof(data), stdin);
printf("%s", data);
return 0;
}
If input is "Hello World\n", data contains "Hello World\n\0".
Managing the Newline Character
fgets() includes the newline in the buffer. To remove it:
#include <string.h>
char data[50];
if (fgets(data, sizeof(data), stdin)) {
char *newline_pos = strchr(data, '\n');
if (newline_pos) *newline_pos = '\0';
}
Handling Excess Input
If input exceeds the buffer size, remaining characters stay in the input stream. To clear them:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
The gets_s() Function
Introduced in C11 Annex K as an optional safer version of gets().
Prototype:
char *gets_s(char *str, rsize_t n);
It reads from stdin up to n-1 characters, discards the newline, and appends a null terminator. If n characters are read without encountering a newline, it sets str[0] to '\0', discards remaining input up to a newline or EOF, and may invoke a runtime constraint handler, potentially terminating the program.
Example:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
int main() {
char line[10];
if (gets_s(line, sizeof(line)) == NULL) {
// Handle error or constraint violation.
}
printf("%s\n", line);
return 0;
}
Function Comparison and Selection
gets(): Avoid. Inherently unsafe due to lack of bounds checking.fgets(): Recommended for most cases. Provides control over input size, allows handling of leftover input, and is widely portable. Requires management of the newline character.gets_s(): A bounds-checked alternative, but its runtime behaivor on constraint violation can be abrupt. It is an optionnal extension, not universally supported, and less flexible thanfgets()for error recovery.
For robust input handling, fgets() combined with explicit buffer management is generally the preferred approach.