how to use EOF with fgets() in C - c

I'm trying to read in inputs from the terminal, I want to stop reading inputs if there is a blank line and enter is pressed. Here is what I have at the moment.
#include <stdio.h>
#include <string.h>
int main(int argc,char const *argv[]){
char input[1024];
while(fgets(input,1024,stdin)!=NULL){
printf("%s", input);
}
if(EOF){
printf("EOF");
}
return 0;
}

One easy thing that you could do is to check the length of the string read in by fgets. The newline character at the end of the input string is considered a valid character by fgets. That means that the length of the string you're testing would be 1 if you just entered a newline So, you want to move the test inside the loop instead of trying to test for EOF outside of the loop. So, your code should look like this:
#include <stdio.h>
#include <string.h>
int main(void) {
char input[1024];
while(fgets(input,1024,stdin)!=NULL) {
printf("%s", input);
if(strlen(input) == 1) {
printf("EOF\n");
break;
}
}
return 0;
}
Also note, to get the EOF test to work you wouldn't hit enter, instead you'd send the end of file key, like CTRL-D on linux to your program. In this case you wouldn't have a strlen test inside the loop.

Related

Why doesn't it wait for me to input string after I exit the loop using CTRL+D

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char c, char_array[100];
int i = 0;
printf("Enter characters (press CTRL+D to end):\n");
while(fgets(char_array+i,sizeof(char_array)-i,stdin)) {
i = i + strlen(char_array+i);
if(char_array[i-1] == EOF)
break;
}
char_array[i-1] = '\0';
strtok(char_array,"\n");
printf("\nEnter a string:\n");
char string[100];
fgets(string,sizeof(string),stdin);
printf("\nCharacter Array: %s\n", char_array);
printf("String: %s\n", string);
return 0;
}
This is the code and I have tried many different variations(simpler) but it always has the same problem... I enter the characters, press CTRL+D and it ends without waiting for me to input a string. please help
I tried everything I could but I just cant make it work and my friends cant too... I have and exam and I need this to be done in 3 days max so I need all the help I can get.
fgets() returns NULL when the stream is closed. On Linux Ctrl-D will flush the terminal buffer if it's not empty (but fgets() will not return as it remains line buffered), and a 2nd Ctrl-D is required to trigger the EOF state of the stream.
You also want to terminate the loop if the array is full otherwise it's an infinite loop:
#define ARRAY_LEN 100
//...
while(i < ARRAY_LEN - 1 && fgets(char_array + i, ARRAY_LEN - i,stdin)) {
fgets() will not emit EOF as part of the string being read, so this is simply incorrect, and as stdin is line buffered the last character is either \n or whatever if the last character was read if the buffer is full which could be -1 or 0xff (whatever char is signed or not but that's still wrong):
if(char_array[i-1] == EOF)
break;
The next line:
char_array[i-1] = '\0';
strips the last character which is either \n or whatever we read last if the array is full (i.e. data loss).
As the input stream is in the EOF state the 2nd fgets() will return NULL. You can clear that state with clearerr(stdin) before calling fgets() to get the 2nd string. If the stream indeed ended, as in, echo "hello world" | ./your_program, the 2nd fgets() with return NULL again of course.
I suggest you use a blank line to signify end of input:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_LEN 100
int main() {
printf("Enter characters (empty line to end):\n");
char char_array[ARRAY_LEN];
for(size_t i = 0; i < ARRAY_LEN - 1; i += strlen(char_array)) {
if(!fgets(char_array + i, ARRAY_LEN - i, stdin)) {
printf("fgets() failed\n");
return 1;
}
if(char_array[i] == '\n') {
char_array[i] = '\0';
break;
}
}
strtok(char_array, "\n");
printf("Enter a string:\n");
char string[ARRAY_LEN];
char *rv = fgets(string,sizeof(string),stdin);
printf("Character Array: %s\n", char_array);
printf("String: %s\n", string);
}
and example session:
Enter characters (empty line to end):
hello
world
Enter a string:
friend
Character Array: hello
String: friend
With stdio streams, error/eof is sticky -- that is, once an error or eof condition has occurred, further operations on the FILE * will continue to return EOF or NULL (depending on the function), rather than trying to read or write anything further.
To reset the eof state on the FILE *, you need to call clearerr(stdin). Once you do that, you can read additional input from the terminal.

Making a terminal in c

When I run this c snippet, it outputs something really random every time, and then segfaults...
Code:
#include <stdio.h>
#include <stdlib.h>
int parse(void) {
int i = 0;
int system(const char *command);
char line[1024];
scanf("%[^\n]", line);
system(line);
do {
line[i] = "\0";
i++;
} while (i != 1024);
parse();
}
int main(void) {
parse();
return 0;
}
What I expected was a prompt, and when any shell command is entered (I used pwd for my testing), the output of the command prints and the prompt returns. And this is what actually happened:
Output:
> pwd
/home/runner/c-test
sh: 1: �: not found
sh: 1: : not found
sh: 1: ׀: not found
signal: segmentation fault (core dumped)
Print prompt
Do not use scanf
Use static storage duration buffer
#include <stdio.h>
#include <stdlib.h>
int parse(void)
{
static char line[1024];
while(1)
{
printf(">>>");
if(!fgets(line, 1024, stdin)) return 1;
system(line);
}
}
int main(void) {
parse();
}
https://www.onlinegdb.com/wmPB3ZGNQ
The reason for your crash is most likely explained by the following:
scanf("%[^\n]", line);
means keep reading until there is a newline in the input stream. So once it completes the next character in the input stream is a newline.
The next time you do
scanf("%[^\n]", line);
that newline is still the first character, so the scanf will return without waiting for the user to type any input.
Since you are doing recursion this will happen again and again and again.... Then most likely the system crashes due to stack overflow after a while.
Solution: Read that newline from the input stream before calling scanf again.
Besides that you should:
Remove int system(const char *command);
Put a maximum field width on scanf
Check the return value of scanf
Change "\0" to '\0' (or delete the whole do-while loop as you don't need it)
Use a while(1) { ... } loop instead of recursive calls

scan a sequence of lines of strings with white spaces

My code is for reading an input of strings and newline is used as delimiter. But my code doesn't read the inputs correctly and the output is different from the input. In my code i used %*[\n]c to read the newline character for if any present and skip it so that it is not included while reading the next string.
#include<stdio.h>
main()
{
char s[100],s1[100],s2[100];
scanf("%[^\n]s%*[\n]c%[^\n]s%*[\n]c%[^\n]s%*[\n]c",s,s1,s2);
printf("%s%s%s",s,s1,s2);
return 0;
}
My inputs for this program are below:
this is 1st line
this is 2nd line
this is 3rd line
My output is
this is 1st line.N=ö
Can someone correct my code.Thank you.
In the posted code, there is a risk of buffer overflow since no maximum width is specified for the input buffers. Such widths should always be specified for safe code; remember to leave space for the null character that terminates the string.
scanf(" %99[^\n] %99[^\n] %99[^\n]", s, s1, s2);
The fgets() function is better suited to read lines of input. Note that fgets() keeps the newline when it reads a line of input, so you may want to remove this in some cases. Also, if the user inputs more characters than will fit in the specified buffer, the newline and some characters will remain in the input stream. But this is no different than using scanf(), in that one must always be careful about what may be left behind in the input stream after an IO operation. In any event, using fgets() is generally less error-prone than using scanf(), and there is benefit in having user input stored in a string. The sscanf() function can always be used on the string obtained with fgets(), but in this case you still have the input string to work with after calling sscanf().
Also, note that the function signature in the OP code needs to be one of:
int main(void)
int main(int argc, char **argv)
int main(int argc, char *argv[])
Here is an example using fgets() to read and then display lines of input:
#include <stdio.h>
#include <stdlib.h>
#define MAXLINES 25
#define BUF_LEN 1000
int main(void)
{
char lines[MAXLINES][BUF_LEN];
size_t num_lines = 0;
puts("Enter some lines of text (empty line to quit):");
for(num_lines = 0; num_lines < MAXLINES; num_lines++) {
if (fgets(lines[num_lines], BUF_LEN, stdin) == NULL) {
fprintf(stderr, "Error in fgets\n");
exit(EXIT_FAILURE);
}
if (lines[num_lines][0] == '\n') {
break;
}
}
for (size_t i = 0; i < num_lines; i++) {
printf("%s",lines[i]);
}
return 0;
}
#include<stdio.h>
main()
{
char s[100], s1[100], s2[100];
scanf("%[^\n] %[^\n] %[^\n]", s, s1, s2);
printf("%s\n%s\n%s\n", s, s1, s2);
}

C Program Help in Upper Casing First Letter of Input

I am a beginner coder and writing a code that
asks for the user's name
check if the length is >15, if it is, it will ask the user to input a shorter name when they restart the program
if the length is valid, upper case the first letter of the entered name
display something like "Hi name"
However, The program keeps exiting no matter what I enter. Here is what I did :
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
int main(void)
{
char str_name[15];
printf("Please enter your first name to begin: ");
scanf_s("%14s", str_name, _countof(str_name));
getchar();
if (strlen(str_name) > 15)
{
printf("The entered name is too long, please restart the program and try again.");
getchar();
exit(0);
}
else
{
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
getchar();
}
return 0;
}
You can simply use fgets() to read an input buffer.
char *fgets(char *str, int n, FILE *stream) reads a line from the specified stream and stores it in a buffer pointed to by str. It stops when either n-1 characters are read, the newline character is read, or the EOF is reached.
Some things to note about fgets():
Returns NULL on error.
Appends \n character at the end of buffer. Can replaced with \0 instead.
Buffer must be pointer to an array of characters. Either allocated on the stack or the heap.
Reads from stdin or FILE objects.
Here is some example code which shows this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NAMESTRLEN 16
int main(void) {
char str_name[NAMESTRLEN] = {'\0'};
size_t slen;
printf("Please enter your first name to begin: ");
if (fgets(str_name, NAMESTRLEN, stdin) == NULL) {
fprintf( stderr, "Error from fgets()\n");
return 1;
}
slen = strlen(str_name);
if (slen > 0 && str_name[slen-1] == '\n') {
str_name[slen-1] = '\0';
} else {
fprintf( stderr, "Too many characters\n");
return 1;
}
if (str_name[0] == '\0') {
fprintf( stderr, "No name entered\n");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
return 0;
}
There are several issues in your code:
The buffer size is too short: scanf() will not read more than 14 bytes into str_name, so it is not possible to test if the user entered a name longer than 15 characters.
toupper() should not be given a char argument because it is only defined for values of type unsigned char and the special value EOF. Cast the char as unsigned char.
your attempt at pausing before the terminal window closes fails on windows for long names because the extra characters entered by the user are still pending after the scanf_s(). getchar() reads one and returns immediately, and the program exits and the terminal window closes. Open the terminal window and run the program manually so it does not close automatically. With this approach, you can remove the getchar() and make the program more portable.
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char str_name[17];
printf("Please enter your first name to begin: ");
if (scanf_s("%16s", str_name, sizeof(str_name))) {
printf("Premature end of file.\n");
return 1;
}
if (strlen(str_name) > 15) {
printf("The entered name is too long, please restart the program and try again.");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s\n", str_name);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
char str_name[16] = {0};
size_t len = 0;
int ch;
printf("Please enter your first name to begin: ");
while ((EOF != (ch = fgetc(stdin))) && (ch != '\n') && (len<sizeof(str_name)))
{
if (isalpha(ch))
{
str_name[len++] = ch;
}
}
if (len==sizeof(str_name))
{
fprintf(stderr, "Name too long\n");
}
else
{
str_name[len] = '\0';
printf ("Hi %c%s.\n", toupper(str_name[0]), &str_name[1]);
}
return 0;
}
As you can see I changed the input grabbing function. To check the input str len you should read byte per byte, not a whole string: fgetc do it. Using scanf with a format specifier like %14s it will return you always a trimmed string and you are not able to warn user about a too long Name.
Another point is to check that inserted chars are letters and not other kind of chars: isalpha do the job.
Moreover a c-string is composed by chars plus a null terminator ('\0', 0x00 ), so: a 15 chars string wants a 16 bytes array.
Lastly the code you wrote to mahe the first letter uppercase is completely wrong: you are passing to print a 1 char array and not a c string. My solution is one of many.
The problem is:
char Name[1]; // Declare a single element array.
Name[0] = toupper(str_name[0]); // Set it to the upper-case first letter.
// Try and print the nul-terminated string in Name - but there is no
// trailing zero (and the rest of the name is missing).
printf("Hi %s.\n", Name);
What you need is:
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
There is another problem that str_name[0] is a char value, and char may be signed. If you are using Windows-1252 for example, then Ä is 196, or as a signed char, -60. toupper takes an int, which must be positive¹. When -60 as a signed char is converted to int, you will get -60, and an out of range error. You need to write this as:
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
(Sorry.)
¹ Chrqlie points out the requirement is actually that the argument must be one of the values of unsigned char (which are - by definition - non-negative) or EOF (which is negative)"

Decoding a file

#include <Windows.h>
#include <cstdio>
const int KEY=111;
void encryptStrA(char* sometext)
{
int length;
length=strlen(sometext);
for(int i=0; i<length;i++)
sometext[i]^=KEY;
}
int main(void)
{
FILE* pFile=fopen("pliczek","wb");
char sign;
char sampleString[]="Hello world!";
encryptStrA(sampleString);
fprintf(pFile,"%c%c%s%c%c",13^KEY,10^KEY,sampleString,13^KEY,10^KEY);
fclose(pFile);
pFile=fopen("pliczek","rb");
while(!feof(pFile))
{
fscanf(pFile,"%c",&sign);
printf("%c",sign^KEY);
}
fclose(pFile);
system("PAUSE");
return 0;
}
I evaded some tricky things
File is opened in binary mode
In encryptStrA strlen function isn't placed directly in the loop condition
In spite of these, it still has been outputting "Hell" instead of "Hello World!"? More precisely, cuts everything after spotting the key character .What's the reason? I use OS in which every line of text is ended with carriage return(ASCII 13) and line feed (10).
The code fprintf("%s", s); expects s to be a zero-terminated string. When you reach 'o'^111 it gives a null character, so the rest of the string is not written to the file.
You can use fwrite instead.

Resources