getline startover - c

I'm using the get line function in C to read through the lines of a file. I want to loop over the function so that I can read through the file n number of times. For some reason though, it only reads through it once (I think there's a pointer somewhere still pointing to the last line) at the beginning of the subsequent loops. How do I get it to reset?
To make things clearer, if there were 100 lines in the file, below, the largest val would get would be 100 even though it should get up to 300.
Thanks!
FILE* fp = myfopen (inf, "r");
char* line = NULL;
size_t len = 0;
int num=3
int val=0
for (i=0;i<num;i++)
{
while (getline (&line, &len, fp) != -1)
{
val++;
}
}

Once you read past the end of the file, you have to call
rewind(fp);
to start at the beginning of the stream again.

As mentioned you can use the rewind() function to start over again, the other option is of course to move the open/close of the file into your loop:
FILE* fp; = myfopen (inf, "r");
for (i=0;i<num;i++)
{
fp = myfopen(inf, "r");
while (getline (&line, &len, fp) != -1)
{
val++;
}
fclose(fp);
}

Related

It takes very long time to read '.txt file' how can i solve this problem? ( C )

there is very long "dict.txt" file.
the size of this file is about 2400273(calculated by fseek, SEEK_END)
this file has lots of char like this 'apple = 사과'(simillar to dictionary)
Main problem is that reading file takes very long time
I couldn't find any solution to solve this problem in GOOGLE
The reason i guessed is associated with using fgets() but i don't know exactly.
please help me
here is my code written by C
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int line = 0;
char txt_str[50];
FILE* pFile;
pFile = fopen("dict_test.txt", "r");
if (pFile == NULL) {
printf("file doesn't exist or there is problem to open your file\n");
}
else {
do{
fgets(txt_str, 50, pFile);;
line++;
} while (txt_str != EOF);
}
printf("%d", line);
}
Output
couldn't see result because program was continuosly running
Expected
the number of lines of this txt file
Major
OP's code fail to test the return value of fgets(). Code needs to check the return value of fgets() to know when to stop. #A4L
do{
fgets(txt_str, 50, pFile);; // fgets() return value not used.
Other
Line count should not get incremented when fgets() returns NULL.
Line count should not get incremented when fgets() read a partial line. (I. e.) the line was 50 or longer. Reasonable to use a wider than 50 buffer.
Line count may exceed INT_MAX. There is always some upper bound, yet trivial to use a wider type.
Good practice to close the stream.
Another approach to count lines would use fread() to read chunks of memory and then look for start of lines. (Not shown)
Recommend to print a '\n' after the line count.
int main(void) {
FILE* pFile = fopen("dict_test.txt", "r");
if (pFile == NULL) {
printf("File doesn't exist or there is problem to open your file.\n");
return EXIT_FAILURE;
}
unsigned long long line = 0;
char txt_str[4096];
while (fgets(txt_str, sizeof txt_str, pFile)) {
if (strlen(txt_str) == sizeof txt_str - 1) { // Buffer full?
if (txt_str[sizeof txt_str - 1] != '\n') { // Last not \n?
continue;
}
}
line++;
}
fclose(pFile);
printf("%llu\n", line);
}
fgets returns NULL on EOF.
You are never assigning the result of
fgets(txt_str, 50, pFile);
to txt_str, your program never sees the end of the file and thus enters an endless loop.
try something like this:
char* p_str;
do{
p_str = fgets(txt_str, 50, pFile);
} while (p_str != NULL);

Getting excess characters with fread() in C

Okay, so I have tried to read a whole file with fread(), and I can do it successfully, but the longer the file, the more the excess characters I get on the output.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
FILE* fpointer = fopen("test.txt", "r");
char* wholeFile;
long int fileSize;
if (fpointer == NULL) return 0;
fseek(fpointer, 0, SEEK_END);
fileSize = ftell(fpointer);
rewind(fpointer);
printf("fileSize == %ld\n", fileSize);
wholeFile = (char*)malloc(fileSize+1, sizeof(char));
if (wholeFile == NULL) return 1;
fread(wholeFile, sizeof(char), fileSize, fpointer);
fclose(fpointer);
wholeFile[fileSize] = '\0';
printf("This is whole file:\n\n%s", wholeFile);
free(wholeFile);
return 0;
}
If the file looks like this:
This is cool file.
I get this as output:
This is cool file.²²²²
And if the file is like this:
This
is
cool
file.
I get this as the output:
This
is
cool
file.═══²²²²
Any idea where I'm wrong?
EDIT: Edited code according to comments.
You need to allocate one more than the size of the file and set the last position in the buffer to 0.
C expects character arrays to be null terminated.
Use "rb" to open the file in binary mode. This will ensure you get a reliable count of bytes in the file from Windows.
FILE* fpointer = fopen("test.txt", "rb");
wholeFile = (char*)malloc(fileSize + 1);
wholeFile[fileSize] = '\0';

Reading and writing to a file at the same time in C

Supposed to swap every two lines in a file until just one line remains or all lines are exhausted. I don't want to use another file in doing so.
Here's my code:
#include <stdio.h>
int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);
//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}
i /= 2; //no. of times to run the loop
rewind(fp);
while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fgetpos(fp, &pos);
}
fclose(fp);
return 0;
}
content in this.txt:
aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj
content after running the program
b
aaa
ddd
cc
ddd
c
c
c
i
jj
I've even tried using fseek in place of fgetpos just to get the same wrong result.
From what I figured, after the second while loop has run two times (i.e the first four lines have been processed), the cursor is rightfully at 17th byte where it is supposed to be (as returned by the call to ftell(fp)) and even the file contents after the 4th line are unchanged and somehow for some reason when fgets is called when the loop is running for the third time, the contents read into arrays line1 and line2 are "c\n" and "ddd\n" respectively.
AGAIN, I don't want to use another file to accomplish this, I just need to figure out what exactly is going wrong behind the screen
Any leads would be appreciated. Thank you.
There are multiple problems in your code:
You do not check if fopen() succeeds, risking undefined behavior.
The loop to determine the total number of lines is incorrect.Learn why here: Why is “while ( !feof (file) )” always wrong?
You do not actually need to compute the total number of lines.
You should call fflush() to write the contents back to the file before changing from writing back to reading.
The C Standard specifies this restriction for files open in update mode:
7.21.5.3 The fopen function
[...] output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
This explains why just reading the file position after writing the lines in reverse order causes problems. Calling fflush() should solve this issue.
Here is a corrected version:
#include <stdio.h>
int main(void) {
FILE *fp;
char line1[100], line2[100];
fpos_t pos;
fp = fopen("this.txt", "r+");
if (fp == NULL) {
fprintf(stderr, "cannot open this.txt\n");
return 1;
}
while (fgetpos(fp, &pos) == 0 &&
fgets(line1, sizeof line1, fp) != NULL &&
fgets(line2, sizeof line2, fp) != NULL) {
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fflush(fp);
}
fclose(fp);
return 0;
}
The buffer may not necessarily be flushed when changing the current position of the file. So it must be explicitly flushed.
E.g Use fflush(fp);
Change
fputs(line2,fp);
fputs(line1,fp);
to
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
Why not use two file pointers, both pointing to the same file, one to read and one to write? No need to keep track of the file position, no need to seek around, no need to flush then.
This approach spares you a lot of complicated stuff. Those unnecessary efforts are better invested in some sophisticated error checking/logging like below ;-):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t blocks = 0;
int l1_done = 0;
int l2_done = 0;
FILE *fpin = fopen("this.txt", "r");
FILE *fpout = fopen("this.txt", "r+");
if (NULL == fpin)
{
result = EXIT_FAILURE;
perror("fopen() to for reading failed");
}
if (NULL == fpout)
{
result = EXIT_FAILURE;
perror("fopen() for writing failed");
}
while (EXIT_SUCCESS == result && !l1_done && !l2_done)
{
result = EXIT_FAILURE;
char line1[100];
char line2[100];
if ((l1_done = (NULL == fgets(line1, sizeof line1, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks);
break;
}
}
if ((l2_done = (NULL == fgets(line2, sizeof line2, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks + 1);
break;
}
}
{
size_t len = strlen(line1);
if (((sizeof line1 - 1) == len) && ('\n' != line1[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks);
break;
}
}
{
size_t len = strlen(line2);
if (((sizeof line2 - 1) == len) && ('\n' != line2[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks + 1);
break;
}
}
if (!l2_done)
{
if (EOF == fputs(line2, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks + 1, 2*blocks);
break;
}
}
if (!l1_done)
{
if (EOF == fputs(line1, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks, 2*blocks + 1);
break;
}
}
++blocks;
result = EXIT_SUCCESS;
}
if (EXIT_SUCCESS == result && !ll_done && l2_done)
{
fprintf(stderr, "Odd number of lines.\n");
}
fclose(fpin); /* Perhaps add error checking here as well ... */
fclose(fpout); /* Perhaps add error checking here as well ... */
return result;
}

Why this way of copying files isn't working

I'm writing a wrapper to help me in my future projects (I finished C book), and want to copy a file without using fgetc. Here's my code, it doesn't work:
int CopyFile(char* filename, char* dest)
{
FILE* fp, *fout;
fp = fopen(filename,"rb");
//fout = fopen(dest, "wb");
if(fp == NULL)
{
return -1;
}
/*while((c = fgetc(fp)) != EOF)
{
fputc(c,fout);
}*/
long size = GetFileSize(fp);
printf("%lu", size);
char* file = malloc(size);
fread(file, size, 1, fp);
//fclose(fp);
fout = fopen(dest, "wb");
fwrite(file, size, 1, fout);
fclose(fp);
fclose(fout);
return 0;
}
I even open the files with a hexeditor and they aren't similar. What am I doing wrong?
The problem is in the GetFileSize function, where you move the file-pointer to the end, but you never rewind to the beginning again.
That means your fread function call will not actually read anything, as the pointer already is at the end of the file. So what's written is the contents of the allocated memory, which is indeterminate (and will be seemingly random).
If you checked what fread returned, you would have seen this immediately.
Let this be a lesson on always checking the return values of functions which can fail in one way or the other.

Reverse file text

I'm trying to make a program that uses fgets to take the text from a preexisting file, invert it and then write it to another file. This is the code I've written so far:
#include <stdio.h>
#include <string.h>
int main()
{
int c, d;
FILE *file1, *file2;
char string [100], *begin, *end, temp;
file1 = fopen("StartingFile.txt", "rt");
if (file1 == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fgets(string, 100, file1);
fclose (file1);
begin = string;
end = begin + strlen(string) - 1;
while (end > begin)
{
temp = *begin;
*begin = *end;
*end = temp;
++begin;
--end;
}
file2 = fopen("FinalFile.txt", "wt");
fprintf (file2, "%s", string);
fclose (file2);
printf ("%s\n", string);
return 0;
}
It works fine if the text in the preexisting file is all in one line, but if it has more than one line, only the first one is inverted and written to the new file. I think that fgets can only read one line, so I think I'll have to use a loop, but I'm having trouble implementing it. Can someone give me a hand? Thanks in advance!
To read each line separately from file use fgets in while loop as below,
while(fgets(string, sizeof(string), file1) != NULL)
{
...
}
fclose(file1);
Inside the loop operate on each line to reverse it.
Your code has quite a few logical errors in it. I would recommend using other f* methods instead.
If you want an easy solution, open the file, determine its length, create two buffers of the size of the file, fill the first buffer with the file's contents and then do a loop to copy the reverse to the other buffer, then write that buffer back. Roughly that would look like this:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *file;
file = fopen("StartingFile.txt", "rt");
if (file == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fseek(file, 0, SEEK_END); // move file pointer to end of file
long size = ftell(file); // file pointer position == character count in file
fseek(file, 0, SEEK_SET); // move back to beginning of file
char* buffer = malloc(size * sizeof(char));
fread(buffer, sizeof(char), size, file) // read file contents to buffer
for(long i = 0; i < size/2; ++i)
{
buffer[i] = buffer[size-i-1];
}
fseek(file, 0, SEEK_SET); // The fread set the file pointer to the end so we need to put it to the front again.
fwrite(buffer, sizeof(char), size, file); // Write reverted content
delete buffer;
fclose (file);
}
I haven't tested it and it may contain a few errors since I haven't programmed in C for some time. The only reason to still be programming in C anyways is efficiency and if you want your program to be efficient, the two buffer solution isn't the best either. At least not in terms of memory usage.
I highly recommend getting familiar with all the functions available in C (stdio and so on) cplusplus.com is a great reference for that.
Regards, Xaser

Resources