I am trying to swap the existing characters from the file with new characters one by one. The new characters are obtained by manipulating the existing characters by subtracting one from the ASCII code. The file already exists with text, but I ended up getting an infinite loop for some reason. What am I doing wrong?
#include <stdio.h>
int main()
{
FILE *fp = fopen("myfile.txt", "r+");
if (fp == NULL)
printf("File cannot be opened.");
else
{
// Used for retrieving a character from file
int c;
// Pointer will automatically be incremented by one after executing fgetc function
while ((c = fgetc(fp)) != EOF)
{
// Decrement pointer by one to overwrite existing character
fseek(fp, ftell(fp)-1, SEEK_SET);
// Pointer should automatically increment by one after executing fputc function
fputc(c-1, fp);
printf("%c\n", c);
}
fclose(fp);
}
return 0;
}
-EDIT-
I changed datatype of c from char to int, but problem still persisted. However, my problem has been resolved by adding fseek(fp, 0, SEEK_CUR) after fputc() call. I believe Jonathan Leffler's comment should become an answer since this kind of problem was not answered from the other question.
try this
#include <stdio.h>
int main(void){
FILE *fp = fopen("myfile.txt", "r+");
if (fp == NULL) {
printf("File cannot be opened.");
return -1;
}
int c;
long pos = ftell(fp);
while ((c = fgetc(fp)) != EOF){
fseek(fp, pos, SEEK_SET);//In the case of text file Do not operate the offset.
fputc(c-1, fp);
fflush(fp);//To save the output.
pos = ftell(fp);
printf("%c\n", c);
}
fclose(fp);
return 0;
}
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 have a list of columns containing text but I just to fetch first upper row from this list. How to do that?
#include <stdio.h>
int main()
{
FILE *fr;
char c;
fr = fopen("prog.txt", "r");
while( c != EOF)
{
c = fgetc(fr); /* read from file*/
printf("%c",c); /* display on screen*/
}
fclose(fr);
return 0;
}
Your stop condition is EOF, everything will be read to the end of the file, what you need is to read till newline character is found, furthermore EOF (-1) should be compared with int type.
You'll need something like:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fr;
int c;
if(!(fr = fopen("prog.txt", "r"))){ //check file opening
perror("File error");
return EXIT_FAILURE;
}
while ((c = fgetc(fr)) != EOF && c != '\n')
{
printf("%c",c); /* display on screen*/
}
fclose(fr);
return EXIT_SUCCESS;
}
This is respecting your code reading the line char by char, you also have the library functions that allow you to read whole line, like fgets() for a portable piece of code, or getline() if you are not on Windows, alternatively download a portable version, and, of course you can make your own like this one or this one.
For whatever it's worth, here's an example that uses getline
#include <stdio.h>
int main()
{
FILE *fr;
char *line = NULL;
size_t len = 0;
ssize_t nread;
if (!(fr = fopen("prog.txt", "r"))) {
perror("Unable to open file");
return 1;
}
nread = getline(&line, &len, fr);
printf("line: %s, nread: %ld\n", line, nread);
fclose(fr);
return 0;
}
Some notes:
getline() can automatically allocate your read buffer, if you wish.
getline() returns the end of line delimiter. You can always strip it off, if you don't want it.
It's ALWAYS a good idea to check the status of I/O calls like "fopen()".
just replace EOF as '\n'(new line char). Than your code will read until reaching the new line. Here is what it looks like:
#include <stdio.h>
int main()
{
FILE *fr;
char c = ' ';
fr = fopen("prog.txt", "r");
while(c != EOF && c != '\n')
{
c = fgetc(fr); /* read from file*/
if(c != EOF){
printf("%c",c); /* display on screen*/
}
}
fclose(fr);
return 0;
}
I have not tested it yet but probably work. Please let me know if there is some problem with the code i will edit it.
Edit1:char c; in line 5 is initialized as ' ' for dealing with UB.
Edit2:adding condition (c != EOF) to while loop in line 7, for not giving reason to infinite loop.
Edit3:adding if statement to line 10 for not printing EOF which can be reason for odd results.
I'm writing a program that asks the user for a file name, and creates it if it doesn't exist. At the end of the program, I want to check if the created program is empty, and if it is, delete it. Not deleting it and then running the program with that same file name messes up the way the input is detected.
I've tried using rewind() to go back to the beginning and then checking feof() to see if the beginning of the file was the EOF character, but that didn't work.
Then, I did some searching online, and found a method that used fseek() to go to the end of the file, and then checked with ftell() whether the end of the file was at position 0, but again this did not work.
I went back and did more poking around, and found that the problem might be because I hadn't used fclose() first, so I tried the previous two attempted solutions again, this time being sure to close the file before trying to delete it. Still no dice.
I tried checking what errno was set to, and got 2: No such file or directory. This is patently false, since if that was the case, it would mean that I had accomplished my goal, and when I check the working directory, the file is still there.
I have absolutely no idea what to try next. Can anyone point me in the right direction?
Here are the ways I've tried to delete the file (fp is the file pointer, and file is a char pointer with the name of the file that fp points to.) :
Attempt 1:
rewind(fp);
if(feof(fp)){
remove(file);
}
Attempt 2:
fseek(fp, 1, SEEK_END);
long size = ftell(fp);
if(size == 0){
remove(file);
}
Attempt 3:
fseek(fp, 1, SEEK_END);
long size = ftell(fp);
fclose(fp);
if(size == 0){
remove(file);
}
Attempt 4:
rewind(fp);
int empty = 0;
if(feof(fp)){
empty = 1;
}
fclose(fp);
if(empty == 1){
remove(file);
}
UPDATE: Here's a couple MCVEs, one for each method.
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp;
char file[40];
scanf(" %[^\n]s", file);
fp = fopen(file, "r");
if(fp == NULL){
fp = fopen(file, "w");
int result;
rewind(fp);
int empty = 0;
if(feof(fp)){
empty = 1;
}
fclose(fp);
if(empty == 1){
result = remove(file);
}
printf("%d\n", result);
printf("%d\n", errno);
return 0;
}
Version 2:
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp;
char file[40];
scanf(" %[^\n]s", file);
fp = fopen(file, "r");
if(fp == NULL){
fp = fopen(file, "w");
int result;
fseek(fp, 1, SEEK_END);
long size = ftell(fp);
fclose(fp);
if(size == 0){
result = remove(file);
}
printf("%d\n", result);
printf("%d\n", errno);
return 0;
}
UPDATE 2:
I just realized that when I was making the MCVEs, when I ran them, result was returning 0, which should have meant that it was successful, but the file was still there in the directory. I'm at a loss for words.
The code wasn't reaching the remove statement.
I this code is used for reading the text file in reverse order. And it successful does, displaying the original content of file and the reversed content of file.
#include <stdio.h>
#include <stdlib.h>
int main() {
int count = 0, ch = 0;
FILE *fp;
if( (fp = fopen("file.txt", "r")) == NULL ) {
perror("fopen");
exit(EXIT_FAILURE);
}
printf("\tINPUT FILE\n");
printf("\n");
while(!feof(fp)) {
if((ch = getc(fp)) != EOF) {
printf("%c", ch);
count ++;
}
}
feof(fp);
printf("\n");
printf("\tREVERSED INPUT FILE\n");
printf("\n");
while(count) {
fseek(fp, -2, SEEK_CUR);
printf("%c", getc(fp));
count--;
}
printf("\n");
fclose(fp);
}
But when i replaced, this piece of code
while(!feof(fp)) {
if((ch = getc(fp)) != EOF) {
printf("%c", ch);
count ++;
}
}
by
fseek (fp, 0, SEEK_END); or feof(fp);
Basically i just went till end of file and directly without printing the original contents of file and tried printing the reversed content of file.
But for it does not print the reversed content filed either !!! it just display blank. Why is this happening ??
NOTE: fseek(fp, -2, SEEK_CUR); Have done this (in another while loop) as getc(fp) moves fp forward by one so need to rewind it back by two, also initially it will be pointing to EOF
What is happening here? Can any one please explain?
It breaks because the second loop is while (count), and count is zero if you haven't read through the file first while incrementing it. You can use ftell to obtain the equivalent of count in this case.
P. S. feof(fp) only tests whether fp is at end-of-file, it does not make it seek to EOF, so the line feof(fp) basically does nothing since you aren't using the return value.
As #Arkku already showed, when you replace the while loop with fseek(SEEK_END), count will not be incremented.
To fix this, you can use ftell after fseek, which returns the file length
fseek(fp, 0, SEEK_END);
count = ftell(fp);
Now the file will be printed backwards.
I use below code to read a char from file and replace it with another,
but I have an error.loop in going to end of file.
What is wrong?
I tested this code on linux (netbeans IDE) and it was correct and worked beautiful but when I tried to use VS 2008 in windows , I found a non end loop.
//address = test.txt
FILE *fp;
fp=fopen(address,"r+");
if(fp == 0)
{
printf("can not find!!");
}
else
{
char w = '0'; /// EDIT : int w;
while(1)
{
if((w = fgetc(fp)) != EOF)
{
if((w = fgetc(fp)) != EOF)
{
fseek(fp,-2,SEEK_CUR);
fprintf(fp,"0");
}
}
else
{
break;
}
}
}
fclose(fp);
You are storing the result of fgetc in a char, instead of an int.
char w = '0'; /* Wrong, should be int. */
Incidentally, this problem is mentioned in the C FAQ.
If type char is unsigned, an actual
EOF value will be truncated (by having
its higher-order bits discarded,
probably resulting in 255 or 0xff) and
will not be recognized as EOF,
resulting in effectively infinite
input.
EDIT
Reading your question again, it's highly fishy the way you seek back two characters and write one character. That could well lead to an infinite loop.
EDIT2
You (likely) want something like this (untested):
while ((w = getc(fp)) != EOF) {
fseek(fp, -1, SEEK_CUR);
fprintf(fp, "0");
fflush(fp); /* Apparently necessary, see the answer of David Grayson. */
}
The fopen documentation on cplusplus.com says:
For the modes where both read and
writing (or appending) are allowed
(those which include a "+" sign), the
stream should be flushed (fflush) or
repositioned (fseek, fsetpos, rewind)
between either a reading operation
followed by a writing operation or a
writing operation followed by a
reading operation.
We can add an fflush call after the fprintf to satisfy that requirement.
Here is my working code. It creates a file named example.txt and after the program exits that file's contents will be 000000000000n.
#include <stdio.h>
int main(int argc, char **argv)
{
FILE * fp;
int w;
fp = fopen("example.txt","w");
fprintf(fp, "David Grayson");
fclose(fp);
fp = fopen("example.txt","r+");
while(1)
{
if((w = fgetc(fp)) != EOF)
{
if((w = fgetc(fp)) != EOF)
{
fseek(fp,-2,SEEK_CUR);
fprintf(fp,"0");
fflush(fp); // Necessary!
}
}
else
{
break;
}
}
fclose(fp);
}
This was tested with MinGW in Windows.