I am trying to read values from a file line by line and print them.. and the output is that it prints the last line twice.. Why would it do this being that the last line is the end of the file?
int main(int argc, char* argv[]) {
FILE *file = fopen(argv[1], "r");
if (file == NULL){
printf("error\n");
return 1;
}
unsigned long long address;
int rv = fscanf(file, "%lli", &address);
printf("%lli\n", address);
do{
rv = fscanf(file, "%lli", &address);
printf("%lli\n", address);
} while (rv!=EOF);
fclose(file);
return 0;
}
You don't check if the "inside" fscanf actually succeeded. If you're at the end of the file, it WON'T read anything, &address doesn't get updated, and rv gets 0 for bytes read.
Then you unconditionally print out whatever's in address, which happens to be whatever you did successfully read last - the last line.
Don't use a do/while, use a while()
while((rv = fscan(...)) != EOF) {
printf(...);
}
That way, if fscanf fails, the printf is simply NOT executed.
do/while is basically "do the following at least once", while a while is "do the following zero-or-more times".
Related
I'm new to programming in C. And I'm trying to print the first 10 lines of a text file. When I run my program with a text file containing 11 lines of text, only the first line is displayed. I'm not sure why it does that, but I suspect there is something wrong in my while loop. Can someone please help me?
#include <stdio.h>
int main(int argc, char *argv[]){
FILE *myfile;
char content;
int max = 0;
// Open file
myfile = fopen(argv[1], "r");
if (myfile == NULL){
printf("Cannot open file \n");
exit(0);
}
// Read the first 10 lines from file
content = fgetc(myfile);
while (content != EOF){
max++;
if (max > 10)
break;
printf ("%c", content);
content = fgetc(myfile);
}
fclose(myfile);
return 0;
}
You have been already advised to use fgets. However, if your file has lines of unknown length, you may still want to use fgetc. Just make sure you count only newlines, not all characters:
int max = 0;
int content;
while ((content = fgetc(myfile)) != EOF && max < 10){
if (content == '\n') max++;
putchar(content);
}
fgetc() returns the next character in the file, not the next line. You probably want to use fgets() instead, which reads up to the next newline character into a buffer. Your code should probably end up with something like:
// allocate 1K for a buffer to read
char *buff = malloc(1024);
// iterate through file until we are out of data or we read 10 lines
while(fgets(buff, 1024, myfile) != NULL && max++ < 10) {
printf("%s\n", buff);
}
free(buff);
// close your file, finish up...
Read more about fgets() here: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
fgetc function reads the next character not the next ine. for reading the number of lines you should use fgets function. this function reads the full string till the end of the one line and stores it in a string.
your code Shuld be as:-
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *myfile;
char content[200];
int max = 0;
// Open file
myfile = fopen(argv[1], "r");
if (myfile == NULL)
{
printf("Cannot open file \n");
exit(0);
}
// Read the first 10 lines from file
fgets(content, 200, myfile);
while (content != EOF)
{
max++;
if (max > 10)
break;
printf("%s", content);
fgets(content, 200, myfile);
}
fclose(myfile);
return 0;
}
In this code I opened my files in my open_file function. Then the process_file function needs to copy the text from my in file and Copy it to an out file. Right now it produces a new file but it is blank. It does not give me any error messages. I do not know what is wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 100
FILE* open_file(char prompt[], char mode[]);
FILE* process_file(FILE* in, FILE* out);
int main(int argc, const char * argv[]) {
FILE* in = NULL;
FILE* out = NULL;
printf("MAD-LIBS Text Processor\n");
printf("The Program will open a mad-libs file, ask you to fill various words, and produce a funny story.\n");
open_file("Enter mad-lib file name:\n", "r");
open_file("Enter file name for resulting story:\n", "w");
process_file(in, out);
fclose(in);
fclose(out);
return 0;
}
/* open_file = prompts user for file name & and attempts to open it, if it fails it prompts the user again. */
FILE* open_file(char prompt [], char mode[]) {
char filename[255];
FILE* in;
do {
printf("%s", prompt);
scanf("%s", filename);
in = fopen(filename, mode);
if (in == NULL) {
printf("Unable to open file: %s. Try Again!\n", filename);
}
} while(in == NULL);
return in;
}
/* process_file = processes entire input file and writes it to output file */
FILE* process_file(FILE* in, FILE* out) {
char content[MAX_LEN];
char NewContent[MAX_LEN];
//gets whats in file in
while(fgets(content, content[MAX_LEN], in) != NULL) {
fputs (content, stdout);
strcat(NewContent, content);
}
// copies it
while (fgets(content, content[MAX_LEN], in) != NULL) {
fprintf(out, "%s", content);
}
printf("Successfully copied file\n");
return in;
}
You never assign the FILE* from open_file function to your variable, so it never gets processed.
in = open_file("Enter mad-lib file name:\n", "r");
out = open_file("Enter file name for resulting story:\n", "w");
You are not storing the FILE pointers that open_file is returning, so in
and out remain uninitialized.
You have to do:
in = open_file("Enter mad-lib file name:\n", "r");
out = open_file("Enter file name for resulting story:\n", "w");
process_file(in, out);
Also your process_file is wrong. NewContent is not initialized, when you do
strcat(NewContent, content);
this yields undefined behaviour. Declare NewContent like this:
char NewContent[MAX_LEN] = { 0 };
so that it is properly \0-terminated.
Also depending on the size of the file you are copying, MAX_LEN might not be
long enough to hold the whole file. In that case you would overflow the buffer.
It would be better not to use NewContent in the first place and write to out
in the same reading loop:
FILE* process_file(FILE* in, FILE* out) {
char content[MAX_LEN];
//gets whats in file in
while(fgets(content, MAX_LEN, in) != NULL) { //<- your fgets was wrong
fputs (content, stdout);
fprintf(out, "%s", content); // or fputs(content, out);
}
printf("Successfully copied file\n");
return in;
}
And you were calling fgets incorrectly (look at my corrected code)
Also bear in mind, that you did have 2 loop doing while(fgets(...) != NULL.
Well, the first loop ends, that's because fgets returns NULL, most likely
because the whole file was read or there was an I/O error. In either case
subsequent calls of fgets will return NULL as well, so your second loop
would not even be executed at all.
So what I'm basically doing here is using a command line argument to open a file but only open it 4 lines at a time, then a prompt to print out add'l lines. I can get the file to print out but I cannot figure out how to get it to only print out a few lines at a time. This is where I'm at....thoughts?
#include <stdio.h>
int main(int argc, char *argv[])
{
char line[1000];
FILE *pt;
pt = fopen(argv[1], "r");
if(pt == NULL) return -1;
printf(argv[1], line);
while(fgets(line, 1000, pt) != NULL)
printf("%s", line);
fclose(pt);
return 0;
}
I start from strange line of your code, and then I will try to answer the question.
Statement
printf(argv[1], line);
make me curious - what you what to print, actually?
Here line is not initialized, and argv[1] can hardly be used as format line.
So I suppose it should be just
printf(argv[1]);
or
printf("Filename is %s\n", argv[1]);
As for reading from a file with name provided as argv[1] your code looks able to work, I mean your code read line by line till the end of file and prints these lines at the screen.
If you want to change this logic, e.g. read only 4 first line, add condition with counter, e.g.:
int cnt;
for (cnt = 0; cnt < 4; cnt++) // repeat reading 4 times
{
if (fgets(line, 1000, pt) != NULL)
printf("%s", line);
else
break; // stop when reading fails
}
or (I prefer this version)
int cnt = 0;
while (fgets(line, 1000, pt) != NULL && cnt < 4)
{
printf("%s", line);
cnt++;
}
Such changes allows to stop reading (as well as output), so only 4 or less lines will be shown at console screen.
Finally, for case when you want to show file by groups of 4 (or other constant value), consider the following snippet:
#include <stdio.h>
#define MAX_LINES_TO_PRINT 4
int main(int argc, char *argv[])
{
char line[1000];
FILE *pt;
pt = fopen(argv[1], "r");
if (pt == NULL) return -1;
printf("Filename is %s\n", argv[1]);
int cnt = 0;
while (fgets(line, 1000, pt) != NULL)
{
printf("%s", line);
cnt++;
if (cnt % MAX_LINES_TO_PRINT == 0)
{
int answer;
printf("[%d lines printed] Continue? (Y/N) : ", cnt);
answer = getchar(); // get user's response
while (getchar() != '\n'); // clean input buffer after getchar
if (toupper(answer) == 'N')
{
break; // stop reading the file
}
}
}
fclose(pt);
return 0;
}
Try this program with your file and ask question if something is unclear.
Changing the value in the line #define MAX_LINES_TO_PRINT 4 you can regulate maximum number of lines printed at once (before the next request to continue), e.g. #define MAX_LINES_TO_PRINT 15 make your program printing up to 15 lines.
so I have this file called "score.txt" with contents
NAME
20
NAME2
2
And I'm using this code but it gets an error and I have no idea on how to put the integers from the file in an array.
int main(){
FILE* file = fopen ("score.txt", "r");
int i = 0;
fscanf (file, "%d", &i);
while (!feof (file))
{
printf ("%d ", i);
fscanf (file, "%d", &i);
}
fclose (file);
system("pause");
}
I'm only self learning and i've been trying to figure this out for 2hours already
The problem with using fscanf for input where some lines will fail the format is that the file will not be advanced per iteration of the while loop, so you get stuck.
You can get a solution by using fgets to grab the data and sscanf to grab the number:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
int i = 0;
int ret = 0;
char buf[50];
FILE *file = fopen("score.txt", "r");
if (file == NULL) {
fprintf(stderr,"Unable to open file\n");
exit(1);
}
while (fgets(buf,sizeof(buf),file)) {
ret = sscanf(buf,"%d",&i);
if (ret == 1) { // we expect only one match
printf("%d\n", i);
} else if (errno != 0) {
perror("sscanf:");
break;
}
}
fclose(file)
return(0);
}
This will output, for your input:
20
2
We check the output of sscanf as it tells us if the format has been matched correctly, which will only happen on the lines with integer, and not the 'NAME' lines. We also check for 'errno' which will be set to non-zero if sscanf encounters an error.
We used char buf[50]; to declare a char array with 50 slots, which fgets then uses to store the line its reading; however if the line is more than 50 chars in length it will be read in 50 char chunks by fgets, and you may not get the results you desire.
If you wish to store the integers you read into an array, you'll have to declare an array, then on each read assign a slot in that array to the value of the int you read i.e. int_array[j] = i (where j will have to change with each slot you use). I'll leave it as an exercise to implement this.
I am writing code which very simply reads in a file and prints out what was in the file appropriately.
I have always struggled with getting such a program to terminate upon end of file and think I've found the appropriate solution, however each line is printing twice in my output, for a reason beyond me.
Here is my main file:
int main(int argc, char *argv[]) {
// insure 2 arguments given, one for a.out and one for the test file
if (argc != 2) {
// result if request fails
printf("Requires 2 arguments. Be sure to include test file location\n");
return 0;
}
FILE *fp; //open the file
fp = fopen(argv[1], "r");
char option;
int key;
int i = 0;
while (fscanf(fp, "%c %d", &option, &key) != EOF) {
printf("%d\n", key);
}
}
The key is printing twice!
Hopefully this is a simple error I'm just overlooking due to overexposure to the problem.
You probably want:
fscanf(fp, "%c %d\n", &option, &key);
And you also want to check the return value of fscanf to make sure it equals 2.
In the first iteration of your loop, the newline is not being consumed.
In the second iteration, the newline is consumed and put in option, and the %d does not match, and fscanf returns 1. key is unchanged which is why it gets printed again.
In the third iteration, fscanf finally returns EOF.
General rule: Always check return values to ensure they are what you expect. (You also violate this rule by failing to check the return from fopen.) At worst it does nothing; at best, it helps you debug problems like this.
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Requires 1 argument - a file name\n");
return 1;
}
FILE *fp; //open the file
if ((fp = fopen(argv[1], "r")) == 0)
{
fprintf(stderr, "Failed to open file %s\n", argv[1]);
return 1;
}
char option;
int key;
while (fscanf(fp, "%c %d", &option, &key) == 2)
printf("%d\n", key);
return 0;
}
Note the changes in error reporting, and in the file reading process. The code is still probably not quite what you want; you might get the newline after the number after the first line of input stored in option after the first line. Fixing that requires fgets() and sscanf():
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Requires 1 argument - a file name\n");
return 1;
}
FILE *fp; //open the file
if ((fp = fopen(argv[1], "r")) == 0)
{
fprintf(stderr, "Failed to open file %s\n", argv[1]);
return 1;
}
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
char option;
int key;
if (fscanf(fp, "%c %d", &option, &key) == 2)
printf("%d\n", key);
else
{
fprintf(stderr, "Format mismatch on %s", buffer);
fclose(fp); // Not 100% necessary here, but tidiness is important
return 1;
}
}
fclose(fp); // Not 100% necessary here, but tidiness is important.
return 0;
}
Although I closed fp before the end, it is not crucial when the program is about to exit, and return from main() is pretty much equivalent to exit(). If it was in a function other than main() though, it is very important to ensure that you free any resource you allocate, such as the file stream fp.
Warning: uncompiled code. Caveat Lector.