I'm trying to copy the elements from a file to another if the line is an odd number;
for example I have in first file:
6
5 6 8
3
6 9 32
And the output should be
5 6 8
6 9 32
but I get nothing.
Here is my code:
int main() {
FILE *data_input = fopen("data.in", "r");
FILE *data_out = fopen("data.out", "w");
char str;
int nr = 0;
if (data_input == NULL || data_out == NULL)
printf("error");
while ((str = fgetc(data_input)) != EOF) {
str = fgetc(data_input);
if (str == "\n")
nr++;
if (nr % 2 != 0)
fputc(str, data_out);
}
fclose(data_input);
fclose(data_out);
return 0;
}
You don't need to read another time after the while. By doing that you are discarding half the characters (You read 2 but only write one).
You compare with with '\n' (with single quotes, not double).
You should initialize nr with one, since the first row probably isn't the count as the number 0.
int main() {
FILE *data_input = fopen("data.in", "r");
FILE *data_out = fopen("data.out", "w");
char str;
int nr = 1;
if (data_input == NULL || data_out == NULL)
printf("error");
while ((str = fgetc(data_input)) != EOF) {
if (str == '\n')
nr++;
if (nr % 2 != 0)
fputc(str, data_out);
}
fclose(data_input);
fclose(data_out);
return 0;
}
First, what do you start counting from? 0 or 1? The following code starts from zero, so the first line is even.
In addition to the other issues, you emit your newline with the wrong line, which could make the last line of the file incorrectly empty because you emitted the newline for the last even line if it's empty:
int main() {
FILE *data_input = fopen("data.in", "r");
FILE *data_out = fopen("data.out", "w");
char str;
int nr = 0;
if (data_input == NULL || data_out == NULL)
printf("error");
while ((str = fgetc(data_input)) != EOF) {
str = fgetc(data_input);
if (str == "\n")
nr++; <--- this should be *AFTER* emitting the output
if (nr % 2 != 0)
fputc(str, data_out);
}
fclose(data_input);
fclose(data_out);
return 0;
}
would be better as
int main() {
FILE *data_input = fopen("data.in", "r");
FILE *data_out = fopen("data.out", "w");
int nr = 0;
if (data_input == NULL || data_out == NULL)
printf("error");
// note that this is now easier to read and -
// importantly - to *debug* along with being
// **MUCH** less bug-prone
for (;;) {
int str = fgetc(data_input);
if (str == EOF)
break;
if (nr % 2 != 0)
fputc(str, data_out);
if (str == '\n')
nr++;
}
fclose(data_input);
fclose(data_out);
return 0;
}
There are multiple problems:
you do not exit the program if the files cannot be opened
you have a redundant fgets() inside the loop
fgetc() returns an int, do not use a char variable to store it and test for EOF
naming a byte str is very confusing
you should test and output the byte before testing for the end of line: the trailing newline is part of the line.
line numbers are usually 1 based. The first line has number 1 which is odd. From your expected output, you want the lines with an even line number.
Here is a modified version:
#include <stdio.h>
int main() {
FILE *data_input = fopen("data.in", "r");
FILE *data_out = fopen("data.out", "w");
int c;
int lineno = 1; // the first line is line 1
if (data_input == NULL || data_out == NULL) {
printf("error opening files\n");
return 1;
}
while ((c = fgetc(data_input)) != EOF) {
if (lineno % 2 == 0) // output lines with an even line number
fputc(c, data_out);
if (c == "\n") // update the line number after the newline
lineno++;
}
fclose(data_input);
fclose(data_out);
return 0;
}
Related
I am trying to make a program in C, that reads a text file and replace \r\n with \n to the same file converting the line ending from DOS to UNIX. I use fgetc and treat the file as a binary file. Thanks in advance.
#include <stdio.h>
int main()
{
FILE *fptr = fopen("textfile.txt", "rb+");
if (fptr == NULL)
{
printf("erro ficheiro \n");
return 0;
}
while((ch = fgetc(fptr)) != EOF) {
if(ch == '\r') {
fprintf(fptr,"%c", '\n');
} else {
fprintf(fptr,"%c", ch);
}
}
fclose(fptr);
}
If we assume the file uses a single byte character set, we just need to ignore all the '\r' characters when converting a text file form DOS to UNIX.
We also assume that the size of the file is less than the highest unsigned integer.
The reason we do these assumptions, is to keep the example short.
Be aware that the example below overwrites the original file, as you asked. Normally you shouldn't do this, as you can lose the contents of the original file, if an error occurs.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
// Return a negative number on failure and 0 on success.
int main()
{
const char* filename = "textfile.txt";
// Get the file size. We assume the filesize is not bigger than UINT_MAX.
struct stat info;
if (stat(filename, &info) != 0)
return -1;
size_t filesize = (size_t)info.st_size;
// Allocate memory for reading the file
char* content = (char*)malloc(filesize);
if (content == NULL)
return -2;
// Open the file for reading
FILE* fptr = fopen(filename, "rb");
if (fptr == NULL)
return -3;
// Read the file and close it - we assume the filesize is not bigger than UINT_MAX.
size_t count = fread(content, filesize, 1, fptr);
fclose(fptr);
if (count != 1)
return -4;
// Remove all '\r' characters
size_t newsize = 0;
for (long i = 0; i < filesize; ++i) {
char ch = content[i];
if (ch != '\r') {
content[newsize] = ch;
++newsize;
}
}
// Test if we found any
if (newsize != filesize) {
// Open the file for writing and truncate it.
FILE* fptr = fopen(filename, "wb");
if (fptr == NULL)
return -5;
// Write the new output to the file. Note that if an error occurs,
// then we will lose the original contents of the file.
if (newsize > 0)
count = fwrite(content, newsize, 1, fptr);
fclose(fptr);
if (newsize > 0 && count != 1)
return -6;
}
// For a console application, we don't need to free the memory allocated
// with malloc(), but normally we should free it.
// Success
return 0;
} // main()
To only remove '\r' followed by '\n' replace the loop with this loop:
// Remove all '\r' characters followed by a '\n' character
size_t newsize = 0;
for (long i = 0; i < filesize; ++i) {
char ch = content[i];
char ch2 = (i < filesize - 1) ? content[i + 1] : 0;
if (ch == '\r' && ch2 == '\n') {
ch = '\n';
++i;
}
content[newsize++] = ch;
}
So, I have a file like this:
12345 name1 18 500.000000
12345 name2 18 500.000000
And I wanted to read the file and each column go to a different variable. So I coded this:
void updateStruct() {
char c;
int lines, i;
accounts account[accMAX];
FILE *acc = fopen("acc.dat", "r+");
if (acc == NULL)
return;
for (c = getc(acc); c != EOF; c = getc(acc))
if (c == '\n')
lines += 1;
fscanf(acc, "%d %s %d %f", &account[0].number, account[0].name,
&account[0].age, &account[0].balance);
}
Somehow, the fscanf() doesn't attribute any value to the variables. What am I doing wrong?
The for loop leaves the file pointer at the end of the file. Call rewind to position the file pointer back at the start of the file before calling fscanf.
The for loop to compute the number of lines reads the whole file. fscanf() fails to convert anything and returns EOF.
You must rewind the position to the beginning of file with rewind(acc) or fseek(acc, 0L, SEEK_SET).
Note also that variable c must have type int for the EOF test to function correctly. Furthermore you should also count the last line that may or may not have a newline.
Here is a modified version:
accounts *updateStruct(int *countp) {
int c, last, lines, i;
FILE *acc = fopen("acc.dat", "r");
if (acc == NULL)
return NULL;
last = EOF;
while ((c = getc(acc)) != EOF) {
if (c == '\n')
lines += 1;
last = c;
}
if (last != '\n') { // last line did not have a newline
lines += 1;
}
rewind(acc);
accounts *account = calloc(lines, sizeof(account));
if (account == NULL) {
fclose(acc);
return NULL;
}
for (i = 0; i < count;) {
if (fscanf(acc, "%d %s %d %f", &account[i].number, account[i].name,
&account[i].age, &account[i].balance) != 4) {
// invalid line: skip to the newline
while ((c = getc(acc)) != EOF && c != '\n')
continue;
if (c == EOF)
break;
} else {
i++;
}
}
fclose(acc);
*countp = i;
return account;
}
I'm trying to read a file that contains 10 numbers then adding them to an array so I can sort them later on but I'm having trouble reading them in. Not sure why this isn't working for me, can someone explain what is wrong? There's only a number on each lines.
10.05
11.01
9.03
double nums[10] = {0};
int count;
if ((fptr = fopen("filename", "r")) == NULL){
printf("Error opening file.\n");
}
while ((c = getc(fptr)) != EOF){
if (c != '\n'){
nums[count] = (double)c;
count = count + 1;
}
}
fclose(fptr);
What is wrong:
You are storing only one character.
You are updating count each times on non-newline characters while updating should be on newline characters.
count is used without being initialized.
Casting to double is not for this usage.
Possible fix:
int c;
FILE* fptr;
char line[1024]; // add line buffer and size tracking
int lineCount = 0;
double nums[10] = {0};
int count = 0; // initialize count
if ((fptr = fopen("filename", "r")) == NULL){
printf("Error opening file.\n");
} else { // avoid using NULL to read file
while ((c = getc(fptr)) != EOF){
if (c == '\n'){ // update nums on newline character
line[lineCount] = '\0'; // don't forget to terminate the string
nums[count] = atof(line); // atof() from stdlib.h is useful to convert string to number
count = count + 1;
lineCount = 0; // start to read next line
} else { // read line contents
line[lineCount] = (char)c;
lineCount = lineCount + 1;
}
}
fclose(fptr);
}
Here I go
#include <stdio.h>
#include <stdlib.h>
int main()
{
double values[10];
int count;
FILE *f = fopen("filename", "r");
if (f == NULL)| {
fprintf(stderr, "Some error message");
return EXIT_FAILURE; // We cannot go any further - file is dead
}
// This is basic - you could overcome error problems
// When able to read (including white space) we carry on until the array is full
// This is an area for improvement - error checking etc.
for (count = 0; count < 10 && fscanf(f, " %lf", &values[count]) != 1; count ++);
fclose(f);
return EXIT_SUCCESS;
}
I currently have to add, and make it so it goes in an order like this
content of file 1
content of file 2
content of file 1
content of file 2
its currently only writing the contents of one text file into the output file, i cant see where i'm going wrong so any help is greatly appreciated.
**** Edit, hi done some digging and found that this exact question has already been answered, didnt want to get in trouble with mods and couldnt delete, thanks all
You are not storing the stream pointers returned by fopen() and you are not interleaving lines from file1 and file2. Here is how to fix these issues:
...
// file 3
printf("Please enter the name of the output file : ");
if (scanf("%s", file3) != 1) {
printf("input error\n");
exit(1);
}
FILE *OpenFile = fopen(file1, "r");
FILE *OpenFile2 = fopen(file2, "r");
FILE *OpenFile3 = fopen(file3, "w");
if (OpenFile == NULL || OpenFile2 == NULL || OpenFile3 == NULL) {
perror("Error opening files");
printf("Press any key to exit!\n");
exit(1);
}
int c1 = 0, c2 = 0;
while (c1 != EOF || c2 != EOF) {
if (c1 != EOF) {
/* copy a line from file1 */
while ((c1 = fgetc(OpenFile)) != EOF && c1 != '\n') {
fputc(c1, OpenFile3);
}
fputc('\n', OpenFile3);
}
if (c2 != EOF) {
/* copy a line from file2 */
while ((c2 = fgetc(OpenFile)) != EOF && c2 != '\n') {
fputc(c2, OpenFile3);
}
fputc('\n', OpenFile3);
}
}
printf("The two files were successfully merged into %s\n", file3);
fclose(OpenFile);
fclose(OpenFile2);
fclose(OpenFile3);
return 0;
You need to alternate your fgetc calls, not do each loop all at once.
int file2_ok = 1, file_ok = 1;
while (file_ok && file2_ok) {
if (file2_ok) {
c = fgetc(OpenFile2);
if (c == EOF) {
file2_ok = 0;
} else {
fputc(c, OpenFile3);
}
}
if (file_ok) {
c = fgetc(OpenFile);
if (c == EOF) {
file_ok = 0;
} else {
fputc(c, OpenFile3);
}
}
}
This assumes that the two files have the same number of characters. The question doesn't indicate how they should be merged if they don't match up evenly.
This merges alternates lines of two text files. The input files and the output file are program arguments.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
FILE *OpenFile;
FILE *OpenFile2;
FILE *OpenFile3;
char buffer[10000]; // hopeful
int finished = 0;
if(argc < 4) {
exit(1);
}
OpenFile = fopen(argv[1], "rt"); // "t" is for MSVC
OpenFile2 = fopen(argv[2], "rt");
OpenFile3 = fopen(argv[3], "wt");
if(OpenFile == NULL || OpenFile2 == NULL || OpenFile3 == NULL) {
exit(1);
}
while(finished != 3) {
if(fgets(buffer, sizeof buffer, OpenFile) != NULL) {
fputs(buffer, OpenFile3);
}
else {
finished |= 1;
}
if(fgets(buffer, sizeof buffer, OpenFile2) != NULL) {
fputs(buffer, OpenFile3);
}
else {
finished |= 2;
}
}
fclose(OpenFile);
fclose(OpenFile2);
fclose(OpenFile3);
return 0;
}
Input file 1:
File 1 line 1
File 1 line 2
File 1 line 3
File 1 line 4
Input file 2:
File 2 line 1
File 2 line 2
Output file 3:
File 1 line 1
File 2 line 1
File 1 line 2
File 2 line 2
File 1 line 3
File 1 line 4
The solution could be more efficient if it took notice of the finished status instead of calling fgets after any file has reached EOF.
I'm trying to compare 2 text files and print the first line where they differ but I'm using a buffer of 500 in the fgets() command and I think I'm wasting space.
How can I make the same program if I don't know the length of the line?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
FILE *fp1, *fp2;
int nLine = 1;
char l1[500], l2[500];
system("clear");
if (argc < 3)
{
printf("Usage: %s <file1.txt> <file2.txt>\n",argv[0]);
exit(1);
}
if ((fp1 = fopen(argv[1],"r")) == NULL){
printf("Can't open file: %s\n", argv[1]);
exit(1);
}
if ((fp2 = fopen(argv[2],"r")) == NULL){
printf("Can't open file: %s\n", argv[2]);
exit(1);
}
fgets(l1,500,fp1);
fgets(l2,500,fp2);
while ((l1 != 0) && (l2 != 0)){
if(strcmp(l1,l2) != 0){
printf("Line number: %d\n", nLine);
printf("%s", l1);
printf("%s\n", l2);
exit(1);
} else {
fgets(l1,500,fp1);
fgets(l2,500,fp2);
nLine++;
}
}
return 0;
}
If you do not want to "waste space", remember that the data are in file memory. Read 1 character at time. When you find a difference, just seek to that location of the previous line feed and report the following lines.
long index = 0;
long index_lf = 0;
int c1,c2;
// read until a difference or done
while ((c1 = fgetc(fp1)) == (c2 = fgetc(fp2)) && (c1 != EOF)) {
index++;
if (c1 == '\n') index_lf = index;
}
if (c1 == c2) {
puts("same");
} else {
puts("differ");
fseek(fp1, index_lf, SEEK_SET);
fseek(fp2, index_lf, SEEK_SET);
// read and print each file until a following \n or EOF occurs.
// TBD code for OP
}
[Edit] Some improvements to cope with various issues: mis-match on last byte, files opened in different modes, error handling, etc.
long offset1 = ftell(fp1);;
long offset2 = ftell(fp2);;
int c1,c2;
// read until a difference or done
while ((c1 = fgetc(fp1)) == (c2 = fgetc(fp2)) && (c1 != EOF)) {
if (c1 == '\n') {
offset1 = ftell(fp1);
offset2 = ftell(fp2);
}
}
if (offset1 == -1 || offset2 == -1 || ferror(fp1) || ferror(fp2)) {
puts("problem");
} else if (c1 == c2) {
puts("same");
} else {
puts("differ");
fseek(fp1, offset1, SEEK_SET);
fseek(fp2, offset2, SEEK_SET);
// read and print each file until a following \n or EOF occurs.
// TBD code for OP
}