I'm trying to write a program that adds line numbers to an already existing txt file.
For example, if the file is currently:
Hello
this is
an
exercise
Then after running the code, it will be:
(1) Hello
(2) this is
(3) an
(4) exercise
I wrote this code:
#include<stdio.h>
#include<conio.h>
FILE *fp;
void main()
{
int counter=1;
char newline;
fp=fopen("G:\\name.txt","r+");
if(fp==NULL)
printf("Failed to open file!");
fprintf(fp,"(%d)",counter);
newline=fgetc(fp);
while(newline!=EOF)
{
if(newline=='\n')
{
counter++;
fprintf(fp,"(%d)",counter);
}
newline=fgetc(fp);
}
printf("All done!");
getch();
fclose(fp);
}
And the output is strange.
Firstly, it does not print at the beginning of the file. For some reason, it starts at the end of the file. And another strange thing that happens is that only the first print is successful.
The ones inside the while
loop are gibberish (looks like small dots, doesn't resemble numbers at all)
When I use "r+" inside the fopen, the entire data is deleted, and all I can see is (1) and then gibberish.
If I use "a+" inside the fopen, it starts at the end of the file, and then writes (1) and gibberish.
AFAIK you basically cannot "insert" bytes in the middle of a file. Instead you will be overwriting bytes in the file. Thus when you use the same file for both reading and writing, you will be "interfering with yourself". I suggest you create a temporary file for the written output, or just write to standard output, allowing you to pipe the output to a suitable location.
Here is my suggestion:
#include <stdio.h>
// None conio.h
// Not global variable fp
#include <stdlib.h> // To use exit()
void handle_error(char* message);
int is_a10power(int n);
int main(void) // Standard form of main()
{
FILE *fp1 = fopen("G:\\name.txt","r"); // 1st file open for reading only
if (fp1 == NULL)
handle_error("Error open file for reading\n");
FILE *fp2 = fopen("G:\\name2.txt","w"); // 2nd file open for writting only
if (fp1 == NULL)
handle_error("Error open file for writting\n");
int io_result;
char c = '\n'; // The name "newline" is not adequate: changed by "c"
int counter = 0; // Start in 0 because increment will be done at the beginning
int no_digits = 0; // Number of digits of "counter"
for(;;) // Loop
{
if (c == '\n') // End-of-line handling
{
counter++;
if (is_a10power(counter))
no_digits++;
io_result = fprintf(fp2,"(%d) ", counter);
if (io_result < 3 + no_digits) // Error: not all bytes could be written to fp2
handle_error("Cannot write file\n");
}
c = fgetc(fp1); // Reads only 1 character from fp1
if (ferror(fp1))
handle_error("Cannot read file\n");
if (c == EOF)
break; // <--------- Loop exits here
io_result = fprintf(fp2,"%c", c);
if (io_result < 1) // Less than 1 bytes transmited implies "fail"
handle_error("Cannot write file\n");
}
io_result = fclose(fp1);
if (io_result == EOF)
handle_error("Close file error\n");
io_result = fclose(fp2);
if (io_result == EOF)
handle_error("Close file error\n");
printf("All done!"); // The success message goes after all operations are finished
getchar(); // I like more getchar() than getch()
return 0; // Success
}
void handle_error(char* message)
{
printf("%s",message);
exit(EXIT_FAILURE); // If error, end the program
}
int is_a10power(int n)
{
while (n % 10 == 0)
n /= 10;
return (n == 1);
}
It seems I am obsessive with I/O errors.
So, another style could be the following:
#include <stdio.h>
#include <stdlib.h> // To use exit()
FILE* safe_fopen(const char restrict * filename, const char restrict * mode);
void safe_fclose(FILE* F);
void safe_fprintf_int(FILE* F, int n);
void safe_fprintf_char(FILE* F, char c);
int safe_fgetc(FILE* F);
void handle_error(char* message);
int main(void)
{
FILE *fp1 = safe_fopen("G:\\name.txt","r"); // 1st file open for reading only
FILE *fp2 = safe_fopen("G:\\name2.txt","w"); // 2nd file open for writting only
char c = '\n';
int counter = 0;
for(;;) // Loop
{
if (c == '\n')
safe_fprintf_int(fp2, ++counter); // End-of-line handling
c = safe_fgetc(fp1);
if (c == EOF)
break; // <--------- Loop exits here
safe_fprintf_char(fp2, c);
}
safe_fclose(fp1);
safe_fclose(fp2);
printf("All done!");
return 0;
}
void handle_error(char* message)
{
printf("%s",message);
exit(EXIT_FAILURE); // If error, end the program
}
FILE* safe_fopen(const char restrict * filename, const char restrict * mode)
{
FILE* F = fopen(filename, mode);
if (F == NULL)
handle_error("Cannot open file");
else
return F;
}
void safe_fclose(FILE* F)
{
if (fclose(F) == EOF)
handle_error("Error closing file");
}
int no_digits(int n)
{
int nod = 0;
for ( ; n != 0; n /= 10)
nod++;
return nod;
}
void safe_fprintf_int(FILE* F, int n)
{
if (fprintf(F,"(%d) ",n) < 3 + no_digits(n))
handle_error("Error writting digits to file");
}
void safe_fprintf_char(FILE* F, char c)
{
if (fprintf(F,"%c",c) < 1)
handle_error("Cannot write character in file");
}
int safe_fgetc(FILE* F)
{
int r = fgetc(F);
if (ferror(F))
handle_error("Cannot read file");
else
return r;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.