fwrite() appends instead of write C - c

I have to write a program witch reads from a file received by line and then it overwrites it with the read words uppercased.
This is my code
void toUpperCase(char* string) {
int i=0;
while(string[i])
{
string[i]=toupper(string[i]);
i++;
} }
int main(int argc, char** argv) {
if(argc==1)
{
puts("Error: INSERT PATH");
exit(0);
}
char* file=argv[1];
FILE* fd=fopen(file,"r+");
if(fd<0)
{
perror("Error opening file: ");
exit(0);
}
char buffer[30][30];
int i=0;
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
int j=0;
for(j=0; j<i; j++)
{
toUpperCase(buffer[j]);
fwrite(buffer[j],strlen(buffer[j]),1,fd);
}
fclose(fd);
return 0; }
but this program appends the words contained in buffer[][] instead of overwriting the file.
If the file contain was something like pippo pluto foo then, after the execution is pippo pluto fooPIPPOPLUTOFOO instead of PIPPO PLUTO FOO.
Where am i wrong? Thank you

You have to reset the file position indicator using fseek, as fscanf will advance it. Something like
fseek(fd, length_of_read_string, SEEK_CUR);
This allows you to read the file in chunks, but it will be tricky to get right. Or of course reset it to the file start because you read everything in 1 go:
fseek(fd, 0L, SEEK_SET);
I strongly recommend writing the modified data into a new file, and then after the program has run, delete the initial file and rename the new one. That will also take care of another issue with your program, you are reading the entire file into memory before handling it.

If you want to do in-place translation that doesn't change lengths, you can open the source file in two streams and then do read-chunk, write-chunk in lockstep. That has the advantage of being super-easy to convert to a non-in-place version that will work with nonseekable files too (stdin/stdout, pipes, and sockets).
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h> //toupper
inline void upcaseStr(char* str){
for(;*str;str++) { *str=toupper(*str); }
}
int upcaseStream(FILE* in, FILE* out){
char buf[BUFSIZ]; //BUFSIZ is an implementation-defined constant for an optimal buffer size
while(fgets(buf, BUFSIZ, in)){
upcaseStr(buf);
if(fputs(buf, out) == EOF){ return 1; }
}
if(!feof){ return 1; }
return 0;
}
int main(int argc, char **argv)
{
//default in and out
FILE* in = stdin;
FILE* out = stdout;
if(argc == 2) {
in = fopen(argv[1], "r"); //for reading
out = fopen(argv[1], "r+"); //for writing (and reading) starting at the beginning
if(!(in && out)){
fprintf(stderr, "Error opening file %s for reading and writing: %s\n", argv[1], strerror(errno));
}
}
return upcaseStream(in, out);
}
If you do use the in-place version, then in the unlikely event that the if(fputs(buf, out) == EOF){ return 1; } line should return, you're screwed unless you have a backup copy of the file. :)
Note:
You shouldn't name your FILE pointers fd because C people will tend to think you mean "file descriptor". FILE is a struct around a file descriptor. A file descriptor is just an int that you can use for FILE access with the raw system calls. FILE streams are an abstraction layer on top of file descriptors--they aren't file descriptors.

As you read from the file, its internal position indicator gets moved. Once you start writing, you start writing from that position on, which happens to be at the end of the file. So you effectively append the data to the file.
Rewind the handle to reset the position indicator before writing into the file:
rewind(fp);
On a side note, you are reading the file incorrectly:
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
When you reach the end of the file, fscanf will return an error and not read anything, yet you still increment variable i, as if the read was successful. And then you check feof() for end-of-file, but i was already incremented.
Check feof() and return of fscanf() immediately after calling fscanf():
while(1)
{
int read = fscanf(fd,"%s",buffer[i]);
if( read != 1 )
//handle invalid read
if( feof(fd) )
break;
i++;
}
Think about what happens if the string is longer than 29 characters and/or the file contains more than 30 strings. char buffer[30][30];

Welcome to StackOverflow!
Reopening the stream with fopen with the "w" parameter:
fd=fopen(file, "w");
It opens the file and if there are any contents in the file, it clears them.

Related

How to set the pointer back to the beginning of the file while parsing a csv file with the strtok() [duplicate]

How would I be able to reset a pointer to the start of a commandline input or file. For example my function is reading in a line from a file and prints it out using getchar()
while((c=getchar())!=EOF)
{
key[i++]=c;
if(c == '\n' )
{
key[i-1] = '\0'
printf("%s",key);
}
}
After running this, the pointer is pointing to EOF im assuming? How would I get it to point to the start of the file again/or even re read the input file
im entering it as (./function < inputs.txt)
If you have a FILE* other than stdin, you can use:
rewind(fptr);
or
fseek(fptr, 0, SEEK_SET);
to reset the pointer to the start of the file.
You cannot do that for stdin.
If you need to be able to reset the pointer, pass the file as an argument to the program and use fopen to open the file and read its contents.
int main(int argc, char** argv)
{
int c;
FILE* fptr;
if ( argc < 2 )
{
fprintf(stderr, "Usage: program filename\n");
return EXIT_FAILURE;
}
fptr = fopen(argv[1], "r");
if ( fptr == NULL )
{
fprintf(stderr, "Unable to open file %s\n", argv[1]);
return EXIT_FAILURE;
}
while((c=fgetc(fptr))!=EOF)
{
// Process the input
// ....
}
// Move the file pointer to the start.
fseek(fptr, 0, SEEK_SET);
// Read the contents of the file again.
// ...
fclose(fptr);
return EXIT_SUCCESS;
}
Piped / redirected input doesn't work like that. Your options are:
Read the input into an internal buffer (which you already seem to be doing); or
Pass the file name as a command-line argument instead, and do with it as you please.

Why does (while .. getchar()) does not write to my file, in C?

I need to write a program that asks the user to enter strings, each string ends when the user presses 'Enter'.
The program needs to receive the file name as a parameter, the file should be opened and closed for each operation and for every string entered, the program should append the string to the end of the file (on a new line).
This is my code so far:
int is_file_exists(char *file_name)
{
FILE *file;
if ((file = fopen(file_name,"r"))!=NULL)
{
/* file exists */
fclose(file);
return 1;
}
else
{
//File not found, no memory leak since 'file' == NULL
//fclose(file) would cause an error
return 0;
}
}
int main(int argc, char **argv)
{
char c;
FILE *file;
if (argc >= 2)
{
if (is_file_exists(argv[1]))
{
file = fopen(argv[1], "w");
}
else
{
return 0;
}
}
else
{
file = fopen("file.txt", "w");
}
while ((c = getchar()) != EOF)
{
putc(c, file);
}
return 0;
}
So far the code compiles and file is being created, but nothing is being written inside of it.
Edit: I also need some function pointers, see my comments on selected answer
I think one of the problem was that you were opening and closing a file, and then reopening it subsequently. It is better to just leave it open using a pointer while simultaneously testing that there were no issue to open the file. Another problem was that you were writing in the file, don't you prefer to append text to it? Well it's your decision. As for the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // exit
typedef struct mystruct {
char *exit_word;
void (*exit_fptr)(int); // man exit
int (*strcmp_fptr)(const char *, const char*); // man strcmp
} t_mystruct;
int is_file_exists(char *filename, FILE **file)
{
return (*file = fopen(filename,"a")) > 0;
}
#define BUFF_SIZE 1024
int main(int argc, char **argv)
{
char c;
FILE *file;
t_mystruct s = {.exit_word = "-exit", .exit_fptr = &exit, .strcmp_fptr = &strcmp};
if (argc >= 2) {
if (!(is_file_exists(argv[1], &file)))
return 0;
}
else
file = fopen("file.txt", "a"); // open the file in append mode
char buffer[BUFF_SIZE];
while (42) {
int i = 0;
memset(buffer, 0, BUFF_SIZE);
while ((c = getchar()) != '\n')
buffer[i++] = c;
if (!s.strcmp_fptr(buffer,s.exit_word)) {// exit if user type exit, allow you to fclose the file
fclose(file);
s.exit_fptr(EXIT_SUCCESS); // better to use the define
}
buffer[i] = '\n';
fputs(buffer, file);
}
fclose(file);
return 0;
}
your code can work
remember to press Ctrl+d when finished input. the file will have the content your expected
your code wait for EOF to quit the loop. Ctrl+d is a way to input EOF, or else the program never ends.
putc will write to cache at first, then write to disk. this an optimization mechanism of File System. you can choose to avoid this by DirectIO when open file.
when program terminate normally, file will be closed automatically, then data in cache will be copy to disk;
but when program terminated abnormally, data in cache might be lost.
file should be closed
fclose is needed.
open and close should be organized in pair just as malloc and free.

Why does the program print only the last line of the file, even after reading the entire file?

I want to write a program in C which just reads a file, stores it into an array and then prints the array. Everything works fine but when the text file has more than one line, I always just get the last line printed out.
This is my Code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
FILE * stream;
char dateiname[255];
stream = fopen("heute.txt", "r");
if(stream == NULL){
printf("Error");
}else {
while(!feof(stream)){
fgets(dateiname, 255, stream);
}
fclose(stream);
}
printf("%s\n", dateiname);
}
Thanks for help!
Everything works fine but when the text file has more than one line, I always just get the last line printed out
Reason: For every iteration, the data gets replaced with the next line data, and at the end dateiname will read only the last line.
while(!feof(stream))
Usage of feof() is not recommended. Please see this link for more information :https://faq.cprogramming.com/cgi-bin/smartfaq.cgi?id=1043284351&answer=1046476070
Please see the following code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char dateiname[1024];
int i = 0;
stream = fopen("heute.txt", "r");
if (stream == NULL)
{
printf("Error");
}
else
{
while (fgets(dateiname, sizeof(dateiname), stream) != NULL)
{
printf("Line %4d: %s", i, dateiname);
i++;
}
}
return 0;
}
If you want to just read and print the contents of the file you no need to worry about the size of the file and how many number of lines you have in file.
you can just run fgets() in the while and print each line until we reach NULL
But if you want to store them, we need to calculate the size of the file.
So we need to use functions like stat or fstat to get the size of the file and allocate memory dynamically then just read that many bytes.

C - How to extract specific comment lines from a code file

I want to write a code to extract todo task list from a code file.It's basically scanning a code file and detecting lines that include "TODO" string and then writing those lines into a text file.
So far my my code is like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE* f;
char line[200];
f = fopen("someFile.c", "r");
char c;
char str;
while(!feof(f)){
fgets(line,sizeof(line),f);
if(strstr(line, "TODO") != NULL)//Extracts every line with TODO
{
c=fgetc(f);//c = lines with TODO
}
}
fclose(f);
f= fopen("todoListFile.txt","w");
while(!feof(f))
{
fputs(c,f);//Writing the content of the c in to the text file.
}
fclose(f);
return 0;
}
When I run this code it crashes after 1-2 seconds.
My mistake is probably at the second part which is getting those "TODO" lines and writing down those to the text lines. But I'm pretty stuck at that part and don't know what to do.
Note: Content of someFile.c is basically some comment lines with "// TODO :"
The specification pretty much indicates that you have to open two files, one for reading, one for writing. As you read a line from the input file, if that line contains TODO, you need to write that line to the output file. That leads to the straight-forward code:
#include <stdio.h>
#include <string.h>
int main(void)
{
char file1[] = "someFile.c";
char file2[] = "todoListFile.txt";
FILE *fp1 = fopen(file1, "r");
if (fp1 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", file1);
return 1;
}
FILE *fp2 = fopen(file2, "w");
if (fp2 == NULL)
{
fprintf(stderr, "Failed to open file %s for writing\n", file2);
return 1;
}
char line[200];
while (fgets(line, sizeof(line), fp1) != 0)
{
if (strstr(line, "TODO") != NULL)
fputs(line, fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
Note that it checks that the files were opened successfully, and reports the file name if it failed, and exits with a non-zero status (you could add <stdlib.h> and use EXIT_FAILURE if you prefer).
When run on (a copy of) its own source, it leaves the todoListFile.txt containing one line:
if (strstr(line, "TODO") != NULL)
Simple modifications of the program would:
Write to standard output instead a fixed name file.
Take command line arguments and process all the input files named.
Read standard input if no input files are named.
Increase the line length. 200 is better than 80, but lines can be longer than that. I tend to use 4096 as a line length unless there's a reason to allow longer lines.

Reading a File as Strings

I want to read the data of the file into a string.
Is there a function that reads the whole file into a character array?
I open the file like this:
FILE *fp;
for(i = 0; i < filesToRead; i++)
{
fp = fopen(name, "r");
// Read into a char array.
}
EDIT: So how to read it "line by line" getchar() ?
Here are three ways to read an entire file into a contiguous buffer:
Figure out the file length, then fread() the whole file. You can figure out the length with fseek() and ftell(), or you can use fstat() on POSIX systems. This will not work on sockets or pipes, it only works on regular files.
Read the file into a buffer which you dynamically expand as you read data using fread(). Typical implementations start with a "reasonable" buffer size and double it each time space is exhausted. This works on any kind of file.
On POSIX, use fstat() to get the file and then mmap() to put the entire file in your address space. This only works on regular files.
You can do the following:
FILE *fp;
int currentBufferSize;
for(i = 0; i < filesToRead; i++)
{
fp = fopen(name, "r");
currentBufferSize = 0;
while(fp != EOF)
fgets(filestring[i], BUFFER_SIZE, fp);
}
Of course you would have to make this in a more robust way, checking if your buffer can hold all the data and so on...
You might use something like the following: where you read each line, carefully check the result and pass it to a datastructure of your choosing. I have not shown how to properly allocate memory, but you can malloc up front and realloc when necessary.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define FILE_BUFFER_SIZE 1024
int file_read_line(FILE *fp, char *buffer)
{
// Read the line to buffer
if (fgets(buffer, FILE_BUFFER_SIZE, fp) == NULL)
return -errno;
// Check for End of File
if (feof(fp))
return 0;
return 1;
}
void file_read(FILE *fp)
{
int read;
char buffer[FILE_BUFFER_SIZE];
while (1) {
// Clear buffer for next line
buffer[0] = '\0';
// Read the next line with the appropriate read function
read = file_read_line(fp, buffer);
// file_read_line() returns only negative numbers when an error ocurred
if (read < 0) {
print_fatal_error("failed to read line: %s (%u)\n",
strerror(errno), errno);
exit(EXIT_FAILURE);
}
// Pass the read line `buffer` to whatever you want
// End of File reached
if (read == 0)
break;
}
return;
}

Resources