I am new to C programming. I am trying to practice a simple exercise problem: It is the following:
Write a program that reads input lines one by one until the end of file is reached, determines the length of each input line, and then prints only the longest line that was found. You may assume the maximum input line length is 1000 characters.
My code is pasted here:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 1000
int main(void)
{
char line[MAX_LEN], line_temp[MAX_LEN];
int largest_line_size = 0;
int current_line_size;
while ( gets ( line_temp ) != NULL)
{
if ( ( current_line_size = strlen( line_temp ) ) > largest_line_size )
{
strcpy(line, line_temp);
largest_line_size = current_line_size;
}
/*printf("%s\n", line); */
}
printf("%d", largest_line_size);
printf("%s", line);
return EXIT_SUCCESS;
}
The problem is that the code runs, accepts input, but I never get to a point where the while loop breaks. How do I encounters a NULL pointer when using gets() function?
Your help is much appreciated.
Thanks,
The question says You must read the input from a file.
Why are you accepting it at run time from the user?
For example, if fr is a file, you can do the following.
fr = fopen ("filename", "rt"); /* open the file for reading */
/* filename is the name of the file */
/* "rt" means open the file for reading text */
while(fgets(line_temp,MAX_LEN, fr) != NULL)
{ //...do your stuff }
Note that fgets() returns NULL when there are no more lines in the file.
I have figured out the problem myself. The way you get to terminate the loop in the above code when reading characters from stdin is by pressing CTRL-D (Unix) or CTRL-Z in Windows. In either cases, an EOF is triggered and the gets or fgets command returns a NULL pointer. Sorry for wasting time, if that.
Thanks
Related
Here's the file I want to read.
single
splash
single
V-Line
h-line
Macro for checking if string is equal.
#define STR_MATCH(a,b) (strncmp((a),(b),strlen(b)+1) == 0)
Here's what i'm using to read it.
void readMissilesFile(char* fileName)
{
FILE* mFile;
char missile[7];
/* Open the file. */
mFile = fopen(fileName, "r");
if (mFile != NULL)
{
while (!feof(mFile))
{
fgets(missile, 7, mFile);
if (!(STR_MATCH(missile, "\n")))
{
printf("Missile: %s", missile);
}
}
fclose(mFile);
}
else
{
perror("Could not open the file.");
}
}
So i'm having difficulties as its printing out spaces when I read the line. I tried to ignore this by ensuring it only reads 7 characters which is the max length of each missile. Then I made a macro called strcmp which just checks if they are equal(to hopefully not print it).
Please find the macro attached as well.
Thanks in advance and any help is great. :)
If I understand your question correctly you can replace the newline characters by using strcspn.
You should not use feof like this, this post explains why. A safe way to read the file till the end is to use fgets as stop condition in the while loop.
The container, missile should be one char bigger than the max size of the largest string to accomodate for '\0'.
Live sample
#include <string.h>
//...
char missile[10];
//...
if (mFile != NULL)
{
while (fgets(missile, 10, mFile)) //will read till there are no more lines
{
missile[strcspn(missile, "\r\n")] = '\0'; //remove newline characters
printf("Missile: %s ", missile);
}
}
//...
I would advise the reading of this post which has detailed info about fgets, namely the issue of newline characters consumption.
There is getline function in stdio.h which reads line until delimiter. Its a POSIX though, so if you are on Windows you may lack it.
Here is example implementation:
https://github.com/ivanrad/getline/blob/master/getline.c
I am trying to write user input to a txt file using a while loop.
But for some reason that I don't know, the while loop doesn't stop by clicking 'enter'.
when I click 'enter', I see "while loop executed" so I know the while loop iterated again even though I wanted to stop the while loop.
How to do it in a right way?
P.S: I use Microsoft Visual Studio recommended by my professor.
#include <stdio.h>
#include <string.h>
void main()
{
//writing to file
char write[100];
char fileName[100];
printf("give a name for file: ");
gets_s(fileName,99);
strcat(fileName,".txt");
FILE* pF = fopen(fileName, "w");
printf("what needs to be written?\n: ");
while(gets_s(write,99) != NULL)
{
printf("whileloop executed\n");
fprintf(pF,"%s\n", write);
}
fclose(pF);
}
Per Microsoft's gets_s() documentation, gets_s() returns NULL on end-of-file and error conditions:
Return Value
Returns buffer if successful. A NULL pointer indicates an error or
end-of-file condition. Use ferror or feof to determine which one
has occurred.
Hitting the enter key does not close the input stream and cause an end-of-file condition. It just places a zero-length line terminated with a newline in the input stream.
To do that on Windows from a terminal, one usually has to enter the CTRL-Z key combination.
You need to do some handling there as gets_s() will return and empty string when enter is hit. You can write an extra function to handle that:
size_t my_gets(char *buf,size_t len)
{
size_t ret=0;
if(gets_s(buf,len))
ret = strlen(buf);
return ret;
}
Then change your loop to:
while(my_gets(write,99))
{
...
P.S.- You should avoid calling variables with the same name of system functions (i.e. write).
I have seen programs for file handling and in one of the program using fseek as shown below:
/* This example opens a file myfile.dat for reading.
After performing input operations (not shown), it moves the file
pointer to the beginning of the file.
*/
#include <stdio.h>
int main(void)
{
FILE *stream;
int result;
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
if (fseek(stream, 0L, SEEK_SET)); /* moves pointer to */
/* the beginning of the file */
{ /* if not equal to 0
then error ... */
}
else {
/* fseek() successful */
}
}
Like this can one move the file pointer to the next line immediately after that line
BO_ 377 FC_DM_MISC: 8 FC
SG_ DATA3 m11 : 31|8#0+ (1,0) [0|0] "" DM
These are the two lines and I want to program in a way that when one identifies the number 377 the pointer should now go to the next line i.e., to the line SG_ DATA3 inspite of the white spaces after 8 FC. How can one do that using fseek in C?
Try this code . It may help you .Here the Each line of the Input file is converted to string ,since string manipulation is very simple comparing to complex fseek() function.This may not be perfect answer but this will be very simple solution.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *stream;
int result;
char tmp[100]; // assuming that max length of a line in myfile.dat is 100.
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
fscanf(stream, "%100[^\n]", tmp); // assuming that max length of a line in myfile.dat is 100.
printf("%s", tmp);
if (strstr(tmp, "377"))
{ // check for 337
fscanf(stream, "%100[^\n]", tmp); // next line is in the string tmp .
// continue your program.
//printf("%s", tmp);
}
}
}
fseek is used for binary data, if you work on a text file you should use either fgets or getline(recommended to use getline).
There's an open discussion of "fgets() vs getline" and many say that "fgets is deprecated" is only a gcc propaganda in favor to their specific getline().
A possible flaw in fgets() is that it doesn't tell you anything if there are null bytes being read, something you can get away with getline().
But then again if you don't like gcc, or use something different, use fgets(). If you are stuck with gcc, then use getline().
i wanted to ask you, how to read from file using in C language:
your_program <file.txt
cat file.txt
Line one
Line two
Line three
i have something like that, but it is not working. Thanks a lot
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int vstup;
input = getchar();
while( input != '\n')
printf("End of line!\n");
return 0;
}
You could use freopen() to make stdin refer to the input file instead of the keyboard.
This can be used for input or output redirection.
In your case, do
freopen("file.txt", "r", stdin);
Now stdin is associated with the file file.txt and when you read using functions like scanf(), you are actually reading from file.txt.
freopen() will close the old stream (which is stdin here) "otherwise, the function behaves just like fopen()". It will return NULL if some error occurred. So you better check the value returned by freopen().
Read more about freopen() here and here.
And as others have pointed out, the code as you posted it is probably having an infinite loop as the value of input never changes inside the loop.
compile/link the proposed code into some file, lets call that executable: run
when running the following proposed code, redirect 'stdin' from the input file
./run < file.txt
Here is the proposed code:
// <<-- document why a header is being included
#include <stdio.h> // getchar(), EOF, printf()
//#include <stdlib.h> <<-- don't include header files those contents are not used
int main( void ) // <<-- since the 'main()' parameters are not used,
// use this signature
{
int input; // <<-- 'getchar()' returns an integer and EOF is an integer
while( (input = getchar() ) != EOF ) // <<-- input one char per loop until EOF
{
if( '\n' == input ) // is that char a newline?
{
printf("End of line!\n"); // yes, then print message
}
}
return 0;
} // end function: main <<-- document key items in your code
I am trying to write a simple C program that loads a text-file, prints the first line to screen, waits for the user to press enter and then prints the next line, and so on.
As only argument it accepts a text-file that is loaded as a stream "database". I use the getline()-function for this, according to this example. It compiles fine, successfully loads the text-file, but the program never enters the while-loop and then exits.
#include <stdio.h>
#include <stdlib.h>
FILE *database = NULL; // input file
int main(int argc, char *argv[])
{
/* assuming the user obeyed syntax and gave input-file as first argument*/
char *input = argv[1];
/* Initializing input/database file */
database = fopen(input, "r");
if(database == NULL)
{
fprintf(stderr, "Something went wrong with reading the database/input file. Does it exist?\n");
exit(EXIT_FAILURE);
}
printf("INFO: database file %s loaded.\n", input);
/* Crucial part printing line after line */
char *line = NULL;
size_t len = 0;
ssize_t read;
while((read = getline(&line, &len, database)) != -1)
{
printf("INFO: Retrieved line of length %zu :\n", read);
printf("%s \n", line);
char confirm; // wait for user keystroke to proceed
scanf("%c", &confirm);
// no need to do anything with "confirm"
}
/* tidy up */
free(line);
fclose(database);
exit(EXIT_SUCCESS);
}
I tried it with fgets() -- I can also post that code --, but same thing there: it never enters the while-loop.
It might be something very obvious; I am new to programming.
I use the gcc-compiler on Kali Linux.
Change your scanf with fgetline using stdin as your file parameter.
You should step through this in a debugger, to make sure your claim that it never enters the while loop is correct.
If it truly never enters the while loop, it is necessarily because getline() has returned -1. Either the file is truly empty, or you have an error reading the file.
man getline says:
On success, getline() and getdelim() return the number of
characters
read, including the delimiter character, but not including the termiā
nating null byte ('\0'). This value can be used to handle embedded
null bytes in the line read.
Both functions return -1 on failure to read a line (including end-of-
file condition). In the event of an error, errno is set to indicate
the cause.
Therefore, you should enhance your code to check for stream errors and deal with errno -- you should do this even when your code works, because EOF is not the only reason for the function
to return -1.
int len = getline(&line, &len, database);
if(len == -1 && ferror(database)) {
perror("Error reading database");
}
You can write more detailed code to deal with errno in more explicit ways.
Unfortunately handling this thoroughly can make your code a bit more verbose -- welcome to C!