Reputation: 29
#include <stdio.h>
int main() {
FILE *fp;
char ch = 'g';
fp = fopen("temp.txt", "r+");
while (feof(fp)) {
fputc(ch,fp);
fseek(fp, 1, SEEK_CUR);
}
fclose(fp);
}
As per this question, I want the code to update all the characters to 'g'. However I see that it does nothing.
Upvotes: 0
Views: 216
Reputation: 526
A successful call to the fseek() function clears the end-of-file indicator for the stream
mentioned here. And also writing bytes to file extend its size. So first in some way we need to make sure that we are not going beyond the size of file. As answer by @chqril in which He is making sure of bounds by reading the file and then writing to same portion with altered data.
Here is my solution in which I first found the size of file and then writing it from start to end. It only works when each character in file take exactly one byte.
#include <stdio.h>
int main()
{
unsigned char ch = 'g';
FILE* fp = fopen("tmp.txt","rb+");
if (fp == NULL)
{
printf("cannot open file\n");
return -1;
}
//seek to last byte
if (fseek(fp, 0, SEEK_END) != 0)
{
printf("error during seeking\n");
fclose(fp);
return -1;
}
/*get current offset relative to start.
*this is file size in bytes
*/
long size = ftell(fp);
if (size < 0)
{
printf("error during ftell");
fclose(fp);
return -1;
}
//reset pointer to start of file
rewind(fp);
/*overwrite every byte
*this only works if file
*size is static
*/
for (long i = 0; i < size; ++i)
{
fputc(ch, fp);
}
fclose(fp);
return 0;
}
Upvotes: 1
Reputation: 145277
So you want to change all bytes in the file to the letter g
. Doing this on a text stream portably and reliably is surprisingly difficult1. I suggest you open the stream in binary mode instead and do something like this:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(void) {
char buf[4096];
long len;
FILE *fp;
fp = fopen("temp.txt", "rb+");
if (fp == NULL) {
fprintf(stderr, "cannot open temp.txt: %s\n", strerror(errno));
return 1;
}
while ((len = fread(buf, 1, sizeof buf, fp)) > 0) {
fseek(fp, -len, SEEK_CUR);
memset(buf, 'g', len);
fwrite(buf, 1, len, fp);
fseek(fp, 0, SEEK_CUR);
}
fclose(fp);
return 0;
}
Your question is not completely clear: if by update all the characters to 'g' you mean to leave unchanged bytes that are not characters, such as newline markers, the code will be a bit more subtile. It is much simpler to write a filter that reads a stream and produces an output stream with the changes:
For example, here is a filter that changes all letters to g
:
#include <ctype.h>
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (isalpha(c))
c = 'g';
putchar(c);
}
return 0;
}
ftell()
in text mode to compute the number of characters in the file. You must use binary mode: C 7.21.9.4 the
ftell
functionSynopsis
#include <stdio.h> long int ftell(FILE *stream);
Description
The
ftell
function obtains the current value of the file position indicator for the stream pointed to bystream
. For a binary stream, the value is the number of characters from the beginning of the file. For a text stream, its file position indicator contains unspecified information, usable by thefseek
function for returning the file position indicator for the stream to its position at the time of theftell
call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.Returns
If successful, the
ftell
function returns the current value of the file position indicator for the stream. On failure, theftell
function returns−1L
and stores an implementation-defined positive value inerrno
.
Even counting characters read with getc()
and writing the same number of 'g'
s from the beginning of the file does not work: the newline sequences may use more than one byte and some of the file contents at the end may not be overwritten on some legacy systems.
Upvotes: 1