How to replace a character in text file using C? - c

I need to read a text file (E3-5.txt), and search for character c1 to be replaced by c2.
This is my incomplete code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char c;
char c1 = 'm';
char c2 = 'a';
int i;
FILE* fp;
fp = fopen("C:\\E3-5.txt", "r+");
if (fp == NULL)
{
printf("File not found!");
return 0;
}
for(c = getc(fp); c != EOF; c = getc(fp))
{
if(c == 'm')
{
i = ftell(fp);
printf("\nPosition %d", i);
}
}
}
I am having trouble how to locate the position of c1 in the text and how to rewrite it.
Edit:
I used the code from the answer, but it didn't change the text.
This is the new code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char c;
char c1 = 'm';
char c2 = 'a';
int i;
FILE* fp;
fp = fopen("C:\\E3-5.txt", "rb+");
if (fp == NULL)
{
printf("File not found!");
return 0;
}
else
{
for(c = getc(fp); c != EOF; c = fgetc(fp))
{
if(c == c1)
{
fseek(fp, -1, SEEK_CUR);
fputc(c2, fp);
}
else
{
return 0;
}
}
}
return 0;
}
The program returned 0 without writing anything in the text

Here you have a very naive one:
int freplace(FILE *f, char needle, char repl)
{
int result = 1;
int c;
if(f)
{
while((c = fgetc(f)) != EOF)
{
if(c == needle)
{
fseek(f, -1, SEEK_CUR);
fputc(repl, f);
//all I/O functions require error handling
}
}
}
return result;
}

getc() returns an int so you need to declare int c not char c to check for the EOF.
ftell() gets the location. Use fwrite() or fputc() to write to file at that location by setting with fseek().
Go to https://en.cppreference.com/w/c for reference. Lots of beginners fail to read all of the standard library functions, and some even reinvent the wheel.

You really don't want to directly manipulate a file. Ever. Doing so is just asking for data corruption. Instead, create a new file and move it when you're done. Also, it's a lot easier to write the code. You can do so with something like:
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int c1 = argc > 1 ? argv[1][0] : 'm';
int c2 = argc > 2 ? argv[2][0] : 'a';
const char *path = argc > 3 ? argv[3] : "stdin";
FILE *in = argc > 3 ? fopen(path, "r") : stdin;
if( in == NULL ){
perror(path);
return 1;
}
FILE *out = stdout;
char tmp[1024] = ".tmpXXXXX";
char *outpath = "stdout";
if( argc > 3 ){
outpath = tmp;
int fd = mkstemp(tmp);
if( fd == -1 ){
perror("mkstemp");
return 1;
}
if( (out = fdopen(fd, "w")) == NULL ){
perror(tmp);
return 1;
}
}
int c;
while( (c = fgetc(in)) != EOF ){
if( c == c1 ){
c = c2;
}
if( fputc(c, out) == EOF ){
perror(outpath);
return 1;
}
}
if( argc > 3 ){
if( fclose(out) ){
perror(outpath);
return 1;
}
if( rename(outpath, path) ){
perror(path);
return 1;
}
}
return 0;
}

String replace
Just for completeness, here is a bit of code to replace a word in a file! This will replace a single character, so of course it answers the question and shows some useful examples.
This is also my first and only non-trivial golden program, written in May 1994! Although you can certainly find fault with it, it worked as intended and my co-workers and I used it many different ways for sysadmin-related tasks. Compiled on MS C/C++
#include <stdio.h>
#include <string.h>
#define err(e) {_fcloseall(); fprintf(stderr, \
"USAGE: chg source dest oldstr newstr\n%s\n",e); exit(1);}
main (int argc,char *argv[])
{
FILE *in,*out;
char buffer[200];
char *old,*new;
int i,j,k;
if (argc!=5)
err("invalid # of parameters");
if ((in=fopen(argv[1],"r"))==NULL)
err("Can't open source");
if ((out=fopen(argv[2],"w"))==NULL)
err("Can't open dest");
old=argv[3];
new=argv[4];
if (*old=='"')
old++;
if (*new=='"')
new++;
if (i=strlen(old) && old[i-1]=='"')
old[i-1]=0;
if (i=strlen(new) && new[i-1]=='"')
new[i-1]=0;
if (!*old)
err("Can't search for nothing!");
if (!*new)
err("Can't replace nothing!");
j=0;
while (!feof(in))
{
if ((buffer[j]=fgetc(in))==EOF)
break;
buffer[j+1]=0;
j++;
if (!old[j-1])
{
fprintf(out,new);
fputc(buffer[j-1],out);
j=0;
}
else if (_strnicmp(buffer,old,j))
{
fprintf(out,buffer);
j=0;
}
else if (j>195)
err("Internal error, buffer filled past 195");
}
}

Related

Check if file contains content from another file C

So I'm working on a project, and I need to check whether or not a certain file contains the contents of another file.
I made a function in c (It's c not c++) to try and to it but it seems to get into an infinite loop and not work overall, I tried using the Visual Studio debugger, and it didn't give me more info.
Note: I am including stdlib.h
the code:
int findFileInFile(const char* wherePath, const char* whatPath)
{
FILE* fpBigger = fopen(wherePath, "r");
FILE* fpSmaller = fopen(whatPath, "r");
if (fpBigger != NULL && fpSmaller != NULL)
{
unsigned char cs = 0;
unsigned char cb = 0;
while ((cb = fgetc(fpBigger)) != EOF)
{
cs = fgetc(fpSmaller);
if (cs == EOF)
return 1;
if (cs != cb)
{
fseek(fpSmaller, 0L, SEEK_SET);
}
}
return 0;
}
else
{
printf("File names are wrong!\n");
exit(-1);
}
}
Thank you.
I guess this is what you're looking for:
#include <stdio.h>
#include <stdlib.h>
int findFileInFile(const char *wherePath, const char *whatPath)
{
FILE *fpBigger = fopen(wherePath, "rb");
FILE *fpSmaller = fopen(whatPath, "rb");
if (fpBigger != NULL && fpSmaller != NULL)
{
unsigned char cs = 0;
unsigned char cb = 0;
int s;
int b;
while (1)
{
b = fgetc(fpBigger);
s = fgetc(fpSmaller);
if (s == EOF && b == EOF) //if both return values from fgetc are EOF, it means you've reached the end of the file which wouldn't have been possible if both of the files weren't equal
{
return 1;
}
else if (s == EOF || b == EOF)
{
return 0;
}
cs=(unsigned char)s; //casting the int to unsigned char
cb=(unsigned char)b; //casting the int to unsigned char
if (cs != cb) //compare the characters gotten from the files, if not equal, return 0
{
return 0;
}
}
}
else
{
printf("File names are wrong!\n");
exit(-1);
}
}
int main()
{
printf("%d", findFileInFile("file1.txt", "file2.txt"));
}
Last but not the least, you can also use feof() to check if the end of file stream has been reached.
Edit: (this may not be the most optimal solution but it checks if the bigger file contains the smaller file)
#include <stdio.h>
#include <stdlib.h>
int findFileInFile(const char *wherePath, const char *whatPath)
{
FILE *fpBigger = fopen(wherePath, "rb");
FILE *fpSmaller = fopen(whatPath, "rb");
unsigned char cs = 0;
unsigned char cb = 0;
int s;
int b;
int loc;
if (fpBigger != NULL && fpSmaller != NULL)
{
s = fgetc(fpSmaller);
cs=(unsigned char)s;
while((b=fgetc(fpBigger))!=EOF){ //checks for the first instance of the first character of the smaller file in the bigger file
cb=(unsigned char)b;
if(cs==cb){
loc=ftell(fpBigger)-1; //set loc to the position where the first character of the smaller file is found in the bigger file
break;
}
}
if(b==EOF){ //if the character is not found, return 0
return 0;
}
fseek(fpBigger,loc,SEEK_SET);
rewind(fpSmaller);
while((b=fgetc(fpBigger))!=EOF){
if((s=fgetc(fpSmaller))==EOF){ //check if the end of smaller file is reached, and return 1 if true
return 1;
}
cs=(unsigned char)s;
cb=(unsigned char)b;
if(cs!=cb){
rewind(fpSmaller); //if the characters gotten from both the files are not equal, go to the very beginning of smaller file
loc++; //increase the position to start the search from in the bigger file by 1
fseek(fpBigger,loc,SEEK_SET);
}
}
if(b==EOF&&fgetc(fpSmaller)==EOF){
return 1;
}
return 0;
}
else
{
printf("File names are wrong!\n");
exit(-1);
}
}
int main()
{
printf("%d", findFileInFile("file1.txt", "file2.txt"));
}

Infinite Loop While Modifying Binary File

I am trying to open a binary file read a part from it and then modify it but this ends up in an infinite loop.
Things I had in mind before writing the program:
EOF is a value that is returned by a function that reads/writes from/to the stream when End of file is found or if an error occurs.
File indicator will go the size of the bytes it read plus to right with every successful read/write.
(i.e. if position indicator is at 0 position it will go to position 44 if it reads/writes 44 bytes after a successful read/write.)
The code below is one of my many approaches with no success:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stoixeia
{
char e[30];
char t[5];
float mo;
int ilikia;
};
int main(void)
{
FILE *fptr;
struct stoixeia st;
int c;
if((fptr = fopen("sxoleio","rb+")) == NULL)
exit(1);
while((c = fread(&st,sizeof(struct stoixeia),1,fptr)) != EOF)
{
fseek(fptr,-44,SEEK_CUR);
for(int i = 0; i < strlen(st.e); i++)
st.e[i] += 1;
fwrite(&st,sizeof(struct stoixeia),1,fptr);
}
fclose(fptr);
return 0;
Other unsuccessful approaches:(feof,check for eof inside the loop etc.)
The only success I had so far was with the code below:
while((c = fgetc(fptr)) != EOF)
{
fseek(fptr,-1,SEEK_CUR);
fread(&st,sizeof(struct stoixeia),1,fptr);
fseek(fptr,-44,SEEK_CUR);
for(int i = 0; i < strlen(st.e); i++)
st.e[i] += 1;
fwrite(&st,sizeof(struct stoixeia),1,fptr);
fseek(fptr,1,SEEK_CUR);
fseek(fptr,-1,SEEK_CUR);
}
fclose(fptr);
Using fgetc() as the while condition and moving indicator by one byte to the right after the operations and then moving it back by one byte seems to trigger EOF and the program ends with success.
What is the reason for this behavior?
I really want to understand the behavior for this so anything would be much appreciated.
Thanks in advance.
There are a few issues with your code, but I think the biggest misconception is the return value of fread. Its return value should not be compared to EOF. When you reach end of file, fread will return a short count. In this case, that means it will return zero. Try:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stoixeia {
char e[30];
char t[5];
float mo;
int ilikia;
};
static void die(const char *msg) { perror(msg); exit(EXIT_FAILURE); }
int
main(int argc, char **argv)
{
FILE *fptr;
struct stoixeia st;
size_t c;
const char *path = argc > 1 ? argv[1] : "sxoleio";
if( (fptr = fopen(path, "rb+")) == NULL ){
die(path);
}
while( (c = fread(&st, sizeof st, 1, fptr)) == 1 ){
if( fseek(fptr, -sizeof st, SEEK_CUR) == -1 ){
die("fseek");
}
for( size_t i = 0; st.e[i] && i < sizeof st.e; i++ ){
st.e[i] += 1;
}
if( fwrite(&st, sizeof st, 1, fptr) != 1 ){
die("fwrite");
};
}
if( fclose(fptr) ){
die("fclose");
}
return EXIT_SUCCESS;
}
But, it's probably cleaner to skip the seeks completely and use two different file handles. Something like:
if( (rf = fopen(path, "r")) == NULL) {
die(path);
}
if( (wf = fopen(path, "r+")) == NULL) {
die(path);
}
while( (c = fread(&st, sizeof st, 1, rf)) == 1) {
for( size_t i = 0; st.e[i] && i < sizeof st.e; i++ ){
st.e[i] += 1;
}
if( fwrite(&st, sizeof st, 1, wf) != 1 ){
die("fwrite");
};
}

Is there a way to go to the beginning of a file and at a specified index with fgetc in C?

For my algorithm, I would like to backtrack after going through all the chars in a file back to specific index char. For example, I have a file with ABCDEF, I want to access in the order ABCDEF then BCDEF then CDEF and so on. Is there a way I can do that with just fgetc and no string buffer?
FILE *file = fopen("temp.txt", "r");
int c;
while (1) {
c = fgetc(file);
if (feof(file)) {
break;
}
// Access and print char
}
You'll probably want to handle edge cases and error more cleanly than this, but...:
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
int c;
long offset = 0;
FILE *ifp = argc > 1 ? xfopen(argv[1], "r") : stdin;
while( fseek(ifp, offset++, SEEK_SET) == 0 ) {
while( (c = fgetc(ifp)) != EOF ) {
putchar(c);
}
if( ferror(ifp) ) {
return EXIT_FAILURE;
}
if( offset == ftell(ifp) ) {
break;
}
}
return EXIT_SUCCESS;
}

Basic File IO in C Produces all a's

I am using CodeBlocks on Windows to compile.
Why the program gives me this answer? Why there are so much as and don't get the answer 123456abcdef?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
char s[100] = "abcdef";
char c1 = '0';
int i = 0;
fp = fopen("ot.txt", "w");
if (fp == NULL) {
printf("file open error");
exit(0);
}
while (s[i] != '\0') {
fputc(s[i], fp);
i++;
printf("%d", i);
}
while (c1 != EOF) {
c1 = fgetc(fp);
putchar(c1);
}
fclose(fp);
}
There are multiple problems in your code:
c1 should be defined with type int to accommodate for all values returned by fgetc(). a char cannot unambiguously store EOF.
You should open the file in write+update mode "w+"
You should rewind the stream pointer before reading back from it for 2 reasons: a seek operation is required between read and write operations and you want to read the characters from the start of the file.
You need to test for EOF after reading a byte with fgetc(), otherwise you will output the EOF converted to unsigned char to stdout before exiting the loop.
It is good style to return 0; from main() to indicate success and non-zero to indicate failure.
Here is a corrected version:
#include <stdio.h>
int main(void) {
FILE *fp;
char s[] = "abcdef";
int i, c;
fp = fopen("ot.txt", "w+");
if (fp == NULL) {
printf("file open error\n");
return 1;
}
i = 0;
while (s[i] != '\0') {
fputc(s[i], fp);
i++;
printf("%d", i);
}
rewind(fp);
while ((c1 = fgetc(fp)) != EOF) {
putchar(c1);
}
printf("\n");
fclose(fp);
return 0;
}

How to split a text file into multiple parts in c

What i need to do, is to take a file of n lines, and for every x lines, create a new file with the lines of the original file. An example would be this:
Original File:
stefano
angela
giuseppe
lucrezia
In this case, if x == 2, 3 file would be created, in order:
First file:
stefano
angela
Second FIle:
giuseppe
lucrezia
Third File:
lorenzo
What i've done so far is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
int getlines(FILE *fp)
{
int c = 0;
int ch;
do{
ch = fgetc(fp);
if(ch == '\n')
{
c++;
}
}while(ch != EOF);
fseek(fp, 0 , SEEK_SET);
return c;
}
int ix = 0;
void Split(FILE *fp, FILE **fpo, int step, int lines, int *mem)
{
FILE **fpo2 = NULL;
char * filename = malloc(sizeof(char)*64);
char * ext = ".txt";
char number[2];
for(int i = ix; i < *mem; i++)
{
itoa(i+1, number,10);
strcpy(filename, "temp");
strcat(filename, number);
strcat(filename, ext);
if(!(fpo[i] = fopen(filename, "w")))
{
fprintf(stderr, "Error in writing\n");
exit(EXIT_FAILURE);
}
}
char ch;
int c = 0;
do{
ch = fgetc(fp);
printf("%c", ch);
if(ch == '\n')
{
c++;
}
if(c >= step)
{
c = 0;
ix++;
if(ix >= *mem && (ix*step) <= lines)
{
*mem = *mem + 1;
fpo2 = realloc(fpo, sizeof(FILE*)*(*mem));
Split(fp, fpo2, step, lines, mem);
}
}
putc(ch, fpo[ix]);
}while(ch != EOF);
}
int main()
{
FILE * fp;
if(!(fp = fopen("file.txt", "r")))
{
fprintf(stderr, "Error in opening file\n");
exit(EXIT_FAILURE);
}
int mem = N;
int lines = getlines(fp);
int step = lines/N;
FILE **fpo = malloc(sizeof(FILE *)*N);
Split(fp, fpo, step, lines, &mem);
exit(EXIT_SUCCESS);
}
I'm stack with segmentation error, i couldn't find the bug doing
gdb myprogram
run
bt
I really appreciate any help.
EDIT:
I've changed some things and now it works, but it creates an additional file that contains strange characters. I need to still adjust some things:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
int getlines(FILE *fp)
{
int c = 0;
int ch;
do{
ch = fgetc(fp);
if(ch == '\n')
{
c++;
}
}while(ch != EOF);
fseek(fp, 0 , SEEK_SET);
return c;
}
int ix = 0;
void Split(FILE *fp, FILE **fpo, int step, int lines, int *mem)
{
FILE **fpo2 = NULL;
char * ext = ".txt";
for(int i = ix; i < *mem; i++)
{
char * filename = malloc(sizeof(char)*64);
char * number = malloc(sizeof(char)*64);
itoa(i+1, number,10);
strcpy(filename, "temp");
strcat(filename, number);
strcat(filename, ext);
if(!(fpo[i] = fopen(filename, "w")))
{
fprintf(stderr, "Error in writing\n");
exit(EXIT_FAILURE);
}
free(number);
free(filename);
}
char ch;
int c = 0;
do{
ch = fgetc(fp);
printf("%c", ch);
if(ch == '\n')
{
c++;
}
if(c >= step)
{
c = 0;
ix++;
if(ix >= *mem && ((ix-1)*step) <= lines)
{
*mem = *mem + 1;
fpo2 = realloc(fpo, sizeof(FILE*)*(*mem));
Split(fp, fpo2, step, lines, mem);
}
}
putc(ch, fpo[ix]);
}while(ch != EOF);
}
int main()
{
FILE * fp;
if(!(fp = fopen("file.txt", "r")))
{
fprintf(stderr, "Error in opening file\n");
exit(EXIT_FAILURE);
}
int mem = N;
int lines = getlines(fp);
int step = lines/N;
FILE **fpo = malloc(sizeof(FILE *)*N);
Split(fp, fpo, step, lines, &mem);
exit(EXIT_SUCCESS);
}
There are a few problems in your code. But first I think you need to fix the most important thing
int step = lines/N;
Here step is 0 if your input file has less than N lines of text. This is because lines and N both are integer and integer division is rounding down.
I won't fix your code, but I'll help you with it. Some changes I
suggest:
Instead of getlines, use getline(3) from the standard
library.
fseek(fp, 0 , SEEK_SET) is pointless.
In char * filename = malloc(sizeof(char)*64), note that
both arguments to malloc are constant, and the size is arbitrary.
These days, it's safe to allocate filename buffers statically,
either on the stack or with static: char filename[PATH_MAX].
You'll want to use limits.h to get that constant.
Similarly you have no need to dynamically allocate your FILE
pointers.
Instead of
itoa(i+1, number,10);
strcpy(filename, "temp");
strcat(filename, number);
strcat(filename, ext);
use sprintf(filename, "temp%d%s", i+1, ext)
get familiar with err(3) and friends, for your own convenience.
Finally, your recursive Split is -- how shall we say it? -- a nightmare. Your whole program
should be something like:
open input
while getline input
if nlines % N == 0
create output filename with 1 + n/N
open output
write output
nlines++

Resources