When I use this code
FILE *f = fopen(file, "rb");
const char *d;
if (f!=NULL) {
static char c[100000];
fread(c, sizeof(char), 10000000, f);
d = c;
fclose(f);
return d;
}
else{
/*
char *ff = f;
perror(ff);
*/
d = "Error";
fclose(f);
return d;
}
to read from a file that has text like this
This
Is a test
it reads it fine. However, if I open a different file that has this text
Test
it will read something like
Test Is a test
Why does it combine both into one when the file is closed?
I put this now, but I still get the same results
if (f!=NULL) {
fread(c, sizeof(c), len, f);
d = c;
fclose(f);
c[99999] = '\0';
return d;
}
Looks like there are characters left in your array from the last read. You should null terminate the string before returning, fread() won't do this for you.
You've got some other issues too, such as the character limit for fread() being way bigger than your buffer size.
Unless you really need c for this, you should think about using c++ or even some other language with more sophisticated file and text processing libraries, it would make your life easier.
fread() doesn't NUL-terminate the buffer which it reads to. If the second read is shorter than the first one, the rest of the first which is not overwritten will remain there. And anyway your program invokes undefined behavior at so many places it's not even funny.
For example, this:
static char c[100000];
fread(c, sizeof(char), 10000000, f);
is most likely a typo - you're allowing fread() to read 100 times more data than the size of the buffer. That's why you should always (I mean, A-L-W-A-Y-S) use the sizeof() operator and the size of the array element instead of its type. Also, sizeof(char) is always 1, don't spell out redundant data:
fread(c, sizeof(c), 1, f);
You are reading the data into a static buffer, and you don't terminate the string when you're done.
Since c is static, it is zero initialized. You partly overwrite that with the data from the fread() call.
So, you should use the returned value from fread() and set c[len] to '\0'.
Related
I'm trying to read the contents of a file into one string without reading in the first two lines.
Right now I have:
char* LoadDocument(char* name) {
char* buffer = 0;
long length;
FILE* f = fopen(name, "r");
if(f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(length);
if (buffer) {
fgets (buffer, 100, f);
}
fclose (f);
}
return buffer;
}
But I'm not sure how to skip the first two lines. Also, it appears my malloc is insufficient to hold the whole file here, because it's not getting the whole file.
One solution is to read the complete file into the buffer, manually find the end of the second line, and move the remaining data to the beginning of the buffer.
Also, don't forget to add the string terminator, if you want to use the buffer as a string.
The easiest way is just to read two lines before your "real" reading begins:
char line[1024];
fgets(line, sizeof line, f);
fgets(line, sizeof line, f);
You should probably error-check this too, since the file might be shorter in which case you won't get the expected results. Also the length might be too short. If you really want to support any length, read single characters until you find the end of line, twice.
Your final fgets() should probably be a fread() call, to read the entire rest of the file. You might want to compensate for the lost length due to the initial skipping, too.
Why is the output of this code is some random words in memory?
void conc()
{
FILE *source = fopen("c.txt", "r+");
if(!source)
{
printf("Ficheiro não encontrado");
return;
}
short i = 0;
while(fgetc(source) != EOF)
i++;
char tmp_str[i];
fgets(tmp_str, i, source);
fclose(source);
printf("%s", tmp_str);
}
This should give me the content of the file, I think.
Because after you have walked through the file using fgetc(), then the position indicator is at end-of-file. fgets() has nothing to read. You need to reset it so that it points to the beginning using rewind(source);.
By the way, don't loop through the file using fgetc(), that's an extremely ugly solution. use fseek() and ftell() or lseek() instead to get the size of the file:
fseek(source, SEEK_END, 0);
long size = ftell(source);
fseek(source, SEEK_SET, 0); // or rewind(source);
alternative:
off_t size = lseek(source, SEEK_END, 0);
rewind(source);
Use rewind(source); before fgets(tmp_str, i, source);
After your fgetc() - loop you have reached EOF and if you don't fseek( source, 0l, SEEK_SET ) back to the beginning you won't get any more data.
Anyway you should avoid reading the file twice. Use fstat( fileno(source), ... ) instead to determine the file size.
fgetc reads a character from the stream.
fgets reads a string from the stream.
Now in your code you are iterating through the end of the file. So the call to fgets on the stream will simply return NULL and leave the buffer content unchanged. In your case, your buffer is not initialised. This explains the random values you are seeing.
Instead of reading the complete file content with fgetc to get the character count, I recommend using fseek / ftell (see answer from this thread)
Your code is wrong. As was said before:
You should not read file twice
To allocate array dynamically you must use operator new (in c++)
or function malloc (in c)
If you need code to read content of the file, try next (sorry, but I didn't compile it. anyway it should work well):
FILE* source = fopen("c.txt", "r+b");
if(!source){return;}
fseek(source, 0, SEEK_END);
size_t filesize = ftell(source);
fseek(source, 0, SEEK_SET);
char* buf = new char[filesize+1]; // +1 is for '/0'
fread(buf, sizeof(char), filesize, source);
fclose(source);
buf[filesize]=0;
printf("%s", buf);
delete buf;
Each time you call fgetc() you advance the internal file pointer one character further. At the end of your while() loop the file pointer will then be at the end of the file. Subsequent calls intented to read on the file handle will fail with an EOF condition.
The fgets manual says that :
If the end-of-file is encountered while attempting to read a character, the eof indicator is set (feof). If this happens before any characters could be read, the pointer returned is a null pointer (and the contents of str remain unchanged).
The consequence is that tmp_str is left unchanged. The garbage you get back when you call printf is actually a part of the conc() function stack.
A solution to your problem would be rewinding the file pointer with fseek() just before calling fgets().
fseek(source, 0, SEEK_SET);
Then a better way to get the size of your file would be to fseek to the end of the file, and use ftell to get the current position :
long size;
fseek(source, 0, SEEK_END);
size = ftell(source);
This being said, your code still has a problem. When you allocate on the stack (variables local to a function) you have to tell the size of the variable at compile time. Here your compiler allocates a char array of length 0. I suggest you investigate dynamic allocation with malloc of the keyword new if you're coding in C++.
A proper allocation would look like this :
char *tmp_str = malloc(size);
// Here you read the file
free(tmp_str);
An simpler solution could be to preallocate a string large enough to hold your file.
char tmp_str[1024 * 100]; // 100Kb
Then use the size variable we got earlier to check the file will fit in tmp_str before reading.
When I type, for example, test \n test and try to use this code to write it
FILE *f = fopen(file, "w+");
fflush(f);
if (f==NULL) {
//perror(f);
return 0;
}
else{
int i = fprintf(f, "%s", text);
if (i>0) {
fclose(f);
return 1;
}
else{
fclose(f);
return 0;
}
}
and then read it using this
FILE *f = fopen(file, "r");
static char c[100000];
const char *d;
if (f!=NULL) {
if (fgets(c, 100000, f) !=NULL){
d = c;
}
else{
d = "No text";
}
}
else{
/*
char *ff = f;
perror(ff);
*/
d = "File not found";
}
fclose(f);
return d;
it will only read and write test, not test, new line, test. Why won't this work?
The fgets() function reads up to the first newline it encounters, or stops when it runs out of space to store the result, or when it gets EOF (so there is no more data to read).
A subsequent call to fgets() will collect the information after the first newline.
If you want to read it all at once, consider fread(). OTOH, there are issues you'll have to resolve there, too (notably: (1) you may ask for up to 1000 bytes, but only get back 20, so your code will have to handle short reads correctly; and (2) fread() will not null terminate the input string for you, unlike fgets() etc).
When it comes to writing, fwrite() would be the logical complement to fread(), but you can perfectly well continue using fprintf() and friends, or fputs(), or putc(), or any of the other standard I/O writing functions. There's no formal constraint on 'if you write with these functions, you must read with these other functions'. It depends on the nature of what you're writing and reading, but you are often at liberty to switch as seems most convenient.
http://www.cplusplus.com/reference/cstdio/fgets/
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
I'm using C and I want to read from a binaryFile.
I know that it is contain strings in the following way: Length of a string, the string itself, the length of a string, string itself, and so on...
I want to count the number of times which the string Str appears in the binary file.
So I want to do something like this:
int N;
while (!feof(file)){
if (fread(&N, sizeof(int), 1, file)==1)
...
Now I need to get the string itself. I know it's length. Should I do a 'for'
loop and get with fgetc char by char? I know I'm not allowed to use fscanf since
it's not a text file, but can I use fgetc? And would I get what I'm expecting for
my string? (To use dynamic allocation for char* for it with the size of the length
and use strcpy to add it to the current string?)
You could allocate some memory with malloc then fread into that buffer:
char *str;
/* ... */
if (fread(&N, sizeof(int), 1, file)==1)
{
/* check that N > 0 */
str = malloc(N+1);
if (fread(str, sizeof(char), N, file) == N)
{
str[N] = '\0'; /* terminate str */
printf("Read %d chars: %s\n", N, str);
}
free(str);
}
You should probably loop on:
while (fread(&N, sizeof(int), 1, file) == 1)
{
// Check N for sanity
char *buffer = malloc(N+1);
// Check malloc succeeded
if (fread(buffer, N, 1, file) != 1)
...process error...
buffer[N] = '\0'; // Null terminate for sanity's sake
...store buffer (the pointer) for later processing so you aren't leaking...
...or free it if you won't need it later...
}
You could use getc() or fgetc() in a loop; that would work. However, the direct fread() is much simpler (and is coded as if it uses getc() in a loop).
You might want to do some sanity checking on N before blindly using it with malloc(). In particular, negative values are likely to lead to much unhappiness.
The file format as written is tied to one class of machine — either big-endian or little-endian, and with the fixed size of int (probably 32-bits). Writing more portable data is slightly fiddlier, but eminently doable — but probably not relevant to you just yet.
Using feof() is seldom the correct way to test for whether to continue with a loop. Indeed, there is not often a need to use feof() in code. When it is used, it is because an I/O operation 'failed' and you need to disambiguate between 'it was not an error — just EOF' and 'there was some sort of error on the device'.
The Problem was to find and replace a string in a C File.
I am new to C Files. I have tried the following code but I didnt get any output:
#include<stdio.h>
#include<string.h>
int main()
{
FILE *f1,*f2;
char *src,*dest,*s1,ch,ch1,ch2,ch3;
int i;
f1=fopen("input.txt","rw");
f2=fopen("dummy.txt","rw");
src="mor";
dest="even";
while(ch!=EOF)
{
ch=fgetc(f1);
if(ch==src[0]) //Finding 1st char of src
{
fgets(s1,strlen(src),f1);
if(strcmp(src+1,s1)==0) //Finding occurance of "src" in file
{
fseek(f1,strlen(src)-1,SEEK_CUR);
while(ch1!=EOF) //Copying remaining data into another file
{
ch1=fgetc(f1);
fputc(ch1,f2);
}
fseek(f1,-strlen(src),SEEK_CUR);
for(i=0;i<strlen(dest);i++) //replacing "src" with "dest"
{
ch2=dest[i];
fputc(ch2,f1);
}
fclose(f1);
f1=fopen("input.txt","a");
while(ch3!=EOF) //Appending previosly copied data into 1st file
{
ch3=fgetc(f2);
fputc(ch3,f1);
}
}
}
}
fclose(f1);
fclose(f2);
}
The Contents of input.txt is "morning".
Kindly point the ERROR in the logic and also give an efficient code for the same.
Thanks in Advance.
Reading files in C is usually a bit messy. The first problem that I see is the way ch is used in the main loop. The first time
while (ch != EOF)
is executed, ch is uninitialized, and if it happens to hold EOF, the main loop will not execute at all. I usually use the following structure for reading from files:
FILE *fInput = fopen("input.txt", "r");
int ch; /* need an int to hold EOF */
for (;;)
{
ch = fgetc(fInput);
if (ch == EOF) break;
...
}
In addition, you may need to read up on file pointer concept. For example, after reading the remainder of src, you fseek() forward, and skip some more characters before you copy data to f2. Essentially, you read m, read or (with fgets() - and into an unallocated buffer s1 that would go ka-boom on you some time in the near future), skip 2 more characters (now your pointer is at last n of "morning"), copy "ng" into f2, try to write EOF to f2 in this loop (hence the above pattern for reading until EOF), seek two characters back (which may fail once you reach EOF, my C file functions are a bit rusty these days), write "even" to f1 (which should, if I am wrong about seek after EOF, set input file to "mornieven", and not change it if I am correct). In summary, I don't think the code does what you intend it to do.
I would recommend building up your function. Each one of the following can be written as a program that you should test and finish before going to next step:
read the file safely, and print it out
detect the contents of src, and print the rest of input
save the rest of the input to second file instead of printing
replace src with dest in first file, and ignore the rest (since you open input file with 'rw', this will truncate the rest of input). You may need to do an fseek() to clear the EOF status. Also look at ftell() to record a position that you can jump back to using fseek()
finally, copy in everything you have saved to second file after replacing src with dest (no need to close f1 here. But it is better to open f2 as write, close after copy from first file, and reopen as read to perform the copy back to f1).
In addition, when you need a buffer (such as s1), just use a large enough array for now, but look into malloc() and free() functions to perform dynamic memory allocations for situations like these.
One simple way to do the replace would be to first read in the whole file into a buffer
e.g.
FILE* fpIn = fopen("file.txt","rb");
fseek(fpIn, 0L, SEEK_END);
size_t s = ftell(fpIn);
fseek(fpIn, 0L, SEEK_SET);
void* buf = malloc(s);
fread(buf,s,1,fpIn);
now while writing the file, check for your string
char src[] = "mor";
char dest[] = "even";
int lenSrc = strlen(src);
int lenDest = strlen(dest);
for (char* ch = buf; ch < buf + s; ++ch)
{
if ( !memcmp( ch, src, lenSrc ) )
{
fwrite( dest, 1,lenDest, fpOut );
ch += lenSrc;
}
else
{
fputc( *ch, fp );
}
}
disclaimer: haven't compiled this
You are printing the wrong thing in your output. Print, "ch", not the file pointer.
while(ch!=EOF)
{
ch=getc(f1);
printf("%c",ch);
}
while(ch!=EOF)
{
ch=getc(f2);
printf("%c",ch);
}
Also, f2 is closed at the end during your output. You'll have to reopen it (just like you do with f1.)
At first glance, I see that your code to call fgets is wrong. You have not allocated any memory and you are reading a string into an uninitialized pointer. Read into an array or dynamically allocated memory.
Another problem is that you are declaring ch as char. fgetc() returns an int, and for good reason. It is good to be able to return any possible character or EOF, so EOF shouldn't be a character, so ideally fgetc() returns a bigger type than char.
The upshot is that the loop may well never end, since ch can't possibly hold EOF on some standard implementation. Declare it (and ch1 and ch3) as int.