Updated December 29, 2023
What is fgets() in C?
The fgets() function in C reads characters from a stream and stores them in a string. It reads characters from the stream until it encounters a newline character, the end of the stream, or it has read up to the maximum number of characters specified. The newline character is included in the string, and the terminating null character is appended.
Syntax:
char *fgets(char *str, int n, FILE *stream);
Parameters:
- str: a reference to an array of characters containing the read string.
- n – Maximum number of characters to store into str, including the null byte
- stream – Pointer to the FILE stream to read from (stdin, file pointer, etc)
Return value:
- Returns the str pointer on success
- Returns a NULL pointer if EOF is encountered before reading anything or if an error occurs
The get()
The get() function in C reads a single character from a file stream or the stdin input stream.
Syntax:
int get(FILE *stream);
- It takes a file stream pointer as a parameter (for example, stdin, stdout, etc.).
- It returns the character read as an unsigned character cast to an integer.
- Returns EOF on the end of the file or input.
Here is an example with an explanation:
#include
int main() {
int c;
printf("Enter text: ");
// Get input
c = getchar();
// Print value
printf("You entered: %d", c);
return 0;
}
Output:
Explanation:
- It first prints “Enter text:” for user input
- We use getchar() to read the next character from the standard input
- This returns the unsigned char code of the key pressed, cast to an integer.
- We store it in the integer variable c and print it back out using the %c format specifier to print it as an actual character.
So, in summary, get() allows reading single-character input from streams in C. It is useful for simple user input routines involving character processing.
Table of Contents
Key Takeaways
- The fget function in C reads a string from a specified file stream.
- Until a newline character, or EOF (end of file), is encountered, it reads characters from the file.
- The function stores the characters in the specified buffer and appends a null character at the end.
- Error handling is important when using fget to handle potential issues with reading from the file stream.
- It is important to manage memory properly when using fget to prevent buffer overflow.
Working of fgets() in C
- fgets() attempts to read up to (n-1) characters from the given stream and store them into str.
- It stops reading under 3 conditions (whichever occurs first):
- Characters (n-1) have been read and saved.
- A newline character is read.
- EOF (End-of-file) is reached
- It appends the null byte \0 at the end of characters stored in str.
- If a newline character is read, it is also included as part of the string.
- If EOF is reached and no characters have been read, fgets() returns NULL.
- On success, it returns the same string pointer passed to it.
In summary, fgets() reads a line from a stream safely into a buffer while taking care to prevent buffer overflows. This makes it very useful for line-oriented input handling in C programs.
Examples of fgets() function in C
Find examples of using the fgets() function in C
Example 1: Reading a Line from Standard Input (stdin)
Code:
#include
int main() {
char str[100];
printf("Enter a line of text: ");
fgets(str, 100, stdin);
printf("You entered: %s", str);
return 0;
}
Output:
Explanation:
This code initially requests that the user input a line of text Then, it uses fgets() to read the input from stdin and store it in the str array. Finally, it prints the contents of the str array to the console.
Example 2: Reading a File Line by Line
#include
int main() {
FILE *file;
file = fopen("example.txt", "r");
if (file == NULL) {
perror("Error opening the file");
return 1;
}
char buffer[256];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}
fclose(file);
return 0;
}
Input Data:
Output:
Explanation:
This code first opens the file example.txt in read mode. Then, it uses a while loop to read each file line using fgets(). Until fgets() returns NULL, indicating that the file’s end has been reached, the loop keeps going. Ultimately, the file is closed, and the program exits.
Example of Handling Multiple Files
An example of using the below-mentioned code to read lines from two files, File1.txt and file2.txt, and print them to the console:
#include
#include
int main()
{
FILE *sf, *tf;
char fileName[50], c;
printf("Enter the source filename with the extension \n");
scanf("%s", fileName);
sf = fopen(fileName, "r");
if (sf == NULL)
{
printf("Cannot open file %s \n", fileName);
exit(0);
}
printf("Enter the target filename with the extension \n");
scanf("%s", fileName);
tf = fopen(fileName, "w");
if (tf == NULL)
{
printf("Cannot open file %s \n", fileName);
exit(0);
}
c = fgetc(sf);
while(c != EOF)
{
fputc(c, tf);
c = fgetc(sf);
}
printf("\nContents copied successfully to target file %s", fileName);
fclose(sf);
fclose(tf);
return 0;
}
Input:
File1.txt
File2.txt
After Compiling:
Output:
File1.txt
file2.txt
Comparison With Other Functions
Function | Description | Advantages | Disadvantages |
fgets() | opens a stream and reads a line of characters | Safe to use with line-based input | Not good for parsing complex data
|
gets() | Reads a line of characters from stdin | Simple to use | Unsafe and deprecated
|
scanf() | Reads formatted input from a stream | Flexible for parsing various data types | Can be vulnerable to buffer overflows |
fread() | Reads a block of data from a stream | Efficient for reading large amounts of data | Not suitable for reading lines of text |
getline() | Reads a line of text, dynamically allocating memory | Can handle any line length | Requires manual memory management |
Features of fgets()
Below are some of the key features of the fgets() function in C:
Reads line-based input:
- Like all other string functions in C, fgets() ends the string with a null character.
- This makes it ideal for reading user input from the console or lines of text from files.
Safe to use:
- Unlike the older gets() function, fgets() is considered safe because it checks for buffer overflows.
- It becomes less vulnerable to security flaws as a result.
Flexible:
- The second parameter allows you to specify the maximum number of characters to read.
- This allows you to control the amount of memory allocated and prevent accidental buffer overflows.
Includes newline character:
If the newline character is present in the input, it is included in the string returned by fgets().
This can be useful for preserving the original format of the data.
Appends a null character:
The null character is appended to the end by fgets() of the string, just like all other string functions in C.
This makes the string null-terminated, which many other string functions require.
Returns a pointer:
- fgets() returns a pointer to the string it has read.
- This makes it simple for you to access and handle the data.
Works with different streams:
fgets() can be used to read from various streams, including stdin, files, and network sockets.
This makes it a versatile function for various input needs.
Here are some additional features of fgets():
- It can be used to read binary data, not just text.
- It can read from a character device, such as a keyboard.
- It can be used to read from a memory buffer.
Overall, fgets() is a powerful and versatile function for reading data in C. It is simple to use, safe, and adaptable.
Best Practices and Tips to Use fgets() function
Here are some best practices and tips for using fgets() in C:
Always check the return value:
- fgets() returns NULL if an error occurs, such as reaching the end of the file or encountering a memory allocation error.
- Always check the return value to ensure the function is successful.
Specify the maximum number of characters to read:
- This helps prevent buffer overflows and ensures proper memory allocation.
- Choose a value based on the expected length of the input to avoid unnecessary memory usage.
Handle the newline character:
- The returned string contains the newline character string by fgets().
- You may need to remove it if it’s not desired in your application.
Validate user input:
- When reading user input, always validate it to ensure it’s in the expected format.
- This helps prevent errors and malicious attacks.
Use fgets() with other functions:
- fgets() can be used in conjunction with other functions like sscanf() to parse complex data.
- This allows you to handle various data types within your program.
Use fgets() responsibly:
- Avoid using fgets() with untrusted sources, as it can be vulnerable to buffer overflow attacks.
- Consider using safer alternatives like getline() in such situations.
Here are some additional tips:
- Use a larger buffer size if you expect long lines of input.
- Use a smaller buffer size if you are reading from a memory-constrained environment.
- Use fgets() with a loop to read multiple data lines from a file.
- Use fgets() with a file pointer to read from a specific file.
By following these best practices and tips, you can ensure that you are using fgets() safely and effectively in your C programs.
Common Errors and Solutions for fgets() in C
Here are some common errors you might encounter when using fgets() in C, along with solutions to fix them:
1. Buffer Overflow:
This occurs when you try to read more characters than the allocated buffer size. This can lead to unpredictable behavior and crashes.
Solution:
- Always specify the maximum number of characters to read as the second argument to fgets(). Ensure this value is large enough to hold the expected input plus the null terminator.
- Use malloc to allocate dynamic memory, and feel free to allocate a buffer of suitable sizes according to your requirements.
- Consider using safer alternatives like getline(), which handles memory allocation dynamically.
2. Not checking the return value:
If fgets() encounters an error, it returns null. Failing to check the return value can lead to program crashes and unexpected behavior.
Solution:
- Always check the return value of fgets() after calling it. If it returns null, handle the error appropriately. This might involve checking ferror() for specific error codes or displaying an error message.
3. Ignoring the newline character:
The returned string from fgets() contains the newlines character. This can cause issues if you don’t expect or handle the newline character appropriately.
Solution:
- If you need to remove the newline character, use functions like strcspn() or strchr() to find it, and then use strncpy() to copy the string without the newline character.
- Alternatively, consider using fgets in a loop to read lines without the newline character.
4. Reading from an invalid stream:
Trying to read from a closed or invalid stream will cause fgets() to fail.
Solution:
- Ensure that the stream you are reading from is open and valid before calling fgets().
- Check for errors before reading, such as using fopen with the correct mode and checking the return value.
- Close streams properly after you are finished using them.
5. Memory leaks:
To avoid memory leaks, make sure to release the memory allocated for a buffer using free after using malloc to allocate it dynamically.
Solution:
- Use a scope-based memory management approach with malloc and free within functions to ensure proper memory handling.
- Consider using alternatives like getline(), which automatically allocates and frees memory.
6. Appending without buffer flush:
Not clearing buffer before reusing to append strings.
Solution:
Use memset() or index from 0 before rewriting the buffer to avoid append issues.
7. Reading beyond a line:
Unintentionally read more lines than you meant to.
Solution:
Enter a variable’s count of read lines, and exit when a predetermined count is reached. Additional Tips:
- Be aware of potential security vulnerabilities when reading user input with fgets().
- Use additional input validation techniques to protect your program from malicious attacks.
- Always strive for clarity and readability in your code when using fgets(), making it easier to understand and maintain.
Understanding these common errors and solutions allows you to use fgets() safely and effectively in your C programs. Remember to prioritize proper memory management, error handling, and security practices for optimal performance and reliability.
Conclusion
The fgets() function is a powerful and versatile tool for reading data in C. It is simple to use, safe, and adaptable. However, it is important to understand its limitations and use it carefully to avoid common errors. You can use fgets() effectively and write robust C programs by adhering to the best practices and advice given.
FAQs
Q1: What is the difference between fgets() and gets()?
Answer: fgets() is a safer version of gets(). It checks for buffer overflows and stops reading at the newline character, while gets() does not have these safeguards and can be vulnerable to security vulnerabilities. gets() is also deprecated in C and should not be used in new code.
Q2: What is the maximum number of characters can fgets() read?
Answer: The second parameter determines the maximum number of characters that fgets() can read. The sizes of the buffer used to store the read characters are specified by this parameter. A buffer overflow will occur if you try to read more characters than the buffer size.
Q3: How do I handle the newline character in a string read with fgets()?
Answer: By default, fgets() includes the newline character in its return string. If you don’t need the newline character, you can remove it by using functions like strcspn() or strchr() to find it and then using strncpy() to copy the string without the newline character.
Q4: Is using fgets() related to any security risks?
Answer: Potential security risks are associated with using fgets() when reading user input. It can be vulnerable to buffer overflow attacks if not used carefully. To lessen these risks, it is critical to:
- Before using user input in your program, make sure it is valid.
- Use a safe buffer size to prevent overflows.
- Consider using alternative functions like getline(), which offer additional security features.