I am debugging my program using gdb, fgets(line, sizeof(line), fp2) reads nothing from a text file. so the program loops infinity ins side while(!feof(fp2)) and the EOF is never met i dont know why?
I'm putting part of the code for context,
here is the inputfile:
COPY START 1000
FIRST STL RETADR
CLOOP JSUB RDREC
LDA LENGTH
COMP ZERO
JEQ ENDFIL
ZERO WORD 0
RETADR RESW 1
LENGTH RESW 1
BUFFER RESB 4096
RSUB
END FIRST
here is the main program:
int main(int argc, char *argv[])
{
FILE *fp, *fp2, *fphex;
char line[1000] = "" ;
if (argc != 2)
{
printf("Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
fp2 = fopen("intermediate.asm", "w");
fp2 = removecomment(fp,fp2);
rewind(fp2);
while (!feof(fp2))
{
fgets(line, sizeof(line), fp2); /*this fgets reads only 4 bytes of empty spaces*/
parse(line);
}
struct node *print = head;
fphex = fopen("Hex_code", "w");
while(print == NULL)
{
fprintf(fphex, "%s", print->instruction);
print = print->next;
}
return(0);
}
EDIT:
While(!feof(File*pointer) was not the problem.
i was trying to read from a write only fopen file.
i resolved it by fclose(file) fopen("file","r")
or as suggested by others w+ mode.
I think closing and opening in read mode is safer.
Ok, here is the problem, you have "w" as a file opening mode.
fp2 = fopen("intermediate.asm", "w");
it should be
fp2 = fopen("intermediate.asm", "r");
file opening modes are
w - write (file is deleted if exists)
r - read (file must exist)
a - append
than you have + sign which means:
w+ - write and read (overwrite if file exists)
r+ - read and write (file must exist)
a+ - append and read (create file if it does not exist)
fp2 was opened in write mode "w", So it must be closed then opened in read mode "r" so lines could be read properly, people could have spotted that instead of saying its the While(!feof(fp2)).
I believe this is well addressed here, it will solve if you replace while(!feof(fp2)) ---> while(!feof(fp2) && !ferror(fp2))
Related
I'm learning about file commands and trying to write some programs. I want to specify two characters in command line, where the second one will replace the first one, every time the first character is found. The command line input would be [program_name].exe [file].txt [old_char] [new_char]. I came across this thread which had the same problem and I tried to fix my code by looking at the answer, but it creates an infinite loop.
int main(int argc, char *argv[])
{
FILE *fp;
char *string = {"Hellx"};
char c;
if ((fp = fopen(argv[1], "w")) != NULL)
{
fputs(string, fp);
printf("Successfully written.\n");
fclose(fp);
if ((fp = fopen(argv[1], "r+")) != NULL)
{
while ((c = fgetc(fp)) != EOF)
{
if (c == *argv[2])
{
fseek(fp, ftell(fp) - 1, SEEK_SET);
fprintf(fp, "%c", *argv[3]);
printf("Successfully changed.\n");
}
}
fclose(fp);
}
else
printf("Error on opening!");
}
else
printf("Error on writing!");
return 0;
}
So the output for this would be: Helloelloelloelloelloelloello..., while it should just change x to o. What's the problem with this code?
Your code does not work because you do not call fseek() or rewind() when switching from writing back to reading. Also note that you do not need to call ftell() to step back: you can use -1L and SEEK_CUR. It is also safer to open the file in binary more for this kind of file patching in place.
Furthermore, fgetc() returns an int value that does not fit in a char. Use int type for c to detect EOF reliably. Also note that the byte value returned by fgetc() when successful is the value of an unsigned char so comparing it to a char might fail for non-ASCII bytes.
Here is a modified version:
#include <stdio.h>
int main(int argc, char *argv[]) {
FILE *fp;
const char *string = { "Hellx" };
if (argc < 4) {
fprintf("missing command line arguments\n");
return 1;
}
char *filename = argv[1];
unsigned char c1 = argv[2][0];
unsigned char c2 = argv[3][0];
if ((fp = fopen(filename, "w")) == NULL) {
fprintf(stderr, "cannot open %s for writing\n", filename);
return 1;
}
fputs(string, fp);
printf("Successfully written.\n");
fclose(fp);
if ((fp = fopen(filename, "rb+")) == NULL) {
printf("Cannot reopen %s\n", filename);
return 1;
}
while ((c = fgetc(fp)) != EOF) {
if (c == c1) {
fseek(fp, -1L, SEEK_CUR);
fputc(c2, fp);
fseek(fp, 0L, SEEK_CUR);
printf("Successfully changed.\n");
}
}
fclose(fp);
return 0;
}
The man page for fopen(), in the section which discusses file opening modes, says
When the "r+", "w+", or "a+" access type is specified, both reading and writing are enabled (the file is said to be open for "update"). However, when you switch from reading to writing, the input operation must encounter an EOF marker. If there is no EOF, you must use an intervening call to a file positioning function. The file positioning functions are fsetpos, fseek, and rewind. When you switch from writing to reading, you must use an intervening call to either fflush or to a file positioning function.
(my bolding)
So I suggest adding
fflush(fp);
after the fprintf() statement, as no repositioning is needed.
As mentioned, you also should change the type to
int c;
so that EOF -1 can be distinguished from data 0xFF.
The reasons for why your program is failing were already extensively debated and solved in other answers and comments.
Is there a short way to do this without "r+" and without fflush?
There is, more than one, here is an example where the file is opened to read and write, this way there is no need to always be opening and closing it, using w+ flag, it will also create the file if it doesn't exist:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
int c;
char *string = {"Hellx"};
if (argc > 3)
{
if ((fp = fopen(argv[1], "w+")) != NULL) // open to write and read
{
fputs(string, fp);
printf("Successfully written.\n");
rewind(fp); // back to the beginning of the file
while ((c = fgetc(fp)) != EOF)
{
if(c == argv[2][0]) // if the character exists...
{
fseek(fp, -1, SEEK_CUR);
fprintf(fp, "%c", argv[3][0]); // replace
printf("Successfully changed.\n");
fseek(fp, 0, SEEK_CUR);
}
}
fclose(fp);
}
else
fprintf(stderr, "Error on writing!");
}
else
fprintf(stderr, "Too few arguments!");
}
Footnote:
I agree with William Pursell and Weather Vane, a more robust way to do this would be to use two different files.
I can't copy the contents of one file to another in C because there is a segmentation fault occurring and I don't know the cause.
I know it has something to do with the syntax of fgets or the way I am giving the size of the buffer.
char* argument = argv[2];
char buffer[argc + 1];
FILE *fp;
FILE *quiz_log;
fp = fopen(argument, "r+");
quiz_log = fopen("quiz.log", "a");
fgets(buffer, 80, fp);
memcpy("quiz.log", buffer, 80);
fclose(quiz_log);
fclose(fp);
Expected: Successful write to file "quiz.log"
Actual: Segmentation Fault: 11
argc has nothing to do with the size of the file, it's the number of command line arguments. So there's no reason to use it as the size of the buffer.
Rather than try to read the file all at once, use a fixed-size buffer and read the file in a loop. Use fread() rather than fgets(), since that just reads one line.
You need to use fwrite() to write to the output file, not memcpy().
#define BUFFER_SIZE 1000
char* argument = argv[2];
char buffer[BUFFER_SIZE];
FILE *fp;
FILE *quiz_log;
fp = fopen(argument, "r");
if (fp == NULL) {
printf("Unable to open input file\n");
exit(1);
}
quiz_log = fopen("quiz.log", "a");
if (quiz_log == NULL) {
printf("Unable to open quiz.log\n");
exit(1);
}
size_t n;
while ((n = fread(buffer, 1, BUFFER_SIZE, fp)) > 0) {
fwrite(buffer, 1, n, quiz_log);
}
fclose(quiz_log);
fclose(fp);
I have these lines in my C program:
int main(int argc, char **argv) {
int i=0, p=0;
FILE* fp;
fp = fopen("jacina.txt", "w+");
fscanf (fp, "%d", &i);
if (ftruncate(fp, 0) == -1) {
perror("Could not truncate")
};
p = i+10;
fprintf(fp, "%d", p);
}
After building this code to OPKG in OpenWRT (from Ubuntu), how can I read and write to this textual file which is located on any disk location where is located this OPKG?
Your code doesn't make any sense. To write the input given by user to a file:
Create a file first. Take input from user (say any string) and write it to the file with the help of file descriptor (fp) and close the file so that all buffers get flushed.
FILE *fp;
char comment[100] = {0};
fp=fopen("tempfile.txt","w");
if (fp == NULL)
{
printf("Error opening file!\n");
exit(1);
}
printf("Enter String: ");
gets(comment);
fwrite(comment, sizeof(comment), 1, fp) ;
fclose(fp);
fprintf() too can be used instead to write data into a file.
Similarly to read from a file you can use fgets() or fread() to store the contents of the file in a buffer and display the contents of the file. Hope it helps.
I am trying to get a user to enter a specific file name and have the program be able to read it.
FILE *fp;
char file[10];
fgets(file, sizeof(file), stdin);
fp = fopen(file, "r");
if (fp == NULL) {
printf("File doesn't open\n");
return 1;
}
This is a section of my code and what i'm currently trying to do. When i run the program and enter the file name, the output is "File doesn't open" which is my error message.
The problem is that fgets also incorporates the newline character '\n' in the string read. You need to remove it,
char* p;
if(p = *strchr( file, '\n' ))
*p = '\0';
otherwise fopen will fail.
Assuming you meant fopen(file,...), before you can do that you must strip file of a newline. See man pages for fgets and [I suggest] strchr.
Use perror to print system error diagnostics:
int main(){
FILE *fp;
char file[10];
fgets(file, sizeof(file), stdin);
fp = fopen(file, "r");
if (!fp) {
perror(file);
return 1;
}
}
If you ask for file f, it'll print:
f
: No such file or directory
which should point you at the source of the problem (the fopen call may also fail for permissions reasons, for example).
I have a program that opens files based on the char **argv command line arguments. Here's the logic:
char * openErrorString = "Error opening file: ";
FILE *fp1 = fopen(*++argv, "r");
if (fp1 == NULL) {
perror(openErrorString);
return 1;
}
FILE *fp2 = fopen(*++argv, "r");
if (fp2 == NULL) {
perror(openErrorString);
return 1;
}
The problem is, I later want to compare the two files and give meaningful output when lines in the files do not match. Here's the code I wrote for that:
while (fgets(fp1Line, max, fp1) != NULL &&
fgets(fp2Line, max, fp2) != NULL) {
if (strcmp(fp1Line, fp2Line)) {
printf("%s\n","Line discrepancy found:");
printf("%s: %s\n", argv[1], fp1Line);
printf("%s: %s\n", argv[2], fp2Line);
fclose(fp1);
fclose(fp2);
return 0;
}
}
However, when I call argv[1] in my printf statement, I get (null), i.e., the final entry in argv. When I call argv[2], I get TERM_PROGRAM=Apple_Terminal. I have no idea what that is. What appears to be happening is that because I incremented the argv pointer twice when accessing it to open the files, argv now starts at the second command line argument. Is there a good way to reset this behavior other than doing two lines of *argv-- after I open the files?
My advice would be to not modify argv. Make a copy of the pointer into another variable, and increment that. This way you can use argv again and again and not worry about where it's pointing right now.
Just don't increment argv, on example:
FILE *fp1 = fopen(argv[0], "r");
// ...
FILE *fp2 = fopen(argv[1], "r");
There is no reason to change the argv pointer if you need it again. Instead, replace
FILE *fp1 = fopen(*++argv, "r");
by
FILE *fp1 = fopen(argv[1], "r");
and
FILE *fp2 = fopen(*++argv, "r");
by
FILE *fp2 = fopen(argv[2], "r");