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.
Related
I have a question how to download a line of text from the file without specifying the size of this line? I wouldn't want to use fgets because you have to give the fgets to the characters in advance. I can load the whole file, but not one line.
FILE *f
long lSize;
char *buffer;
size_t result;
f = fopen("file.txt", "r");
fseek(f, 0, SEEK_END);
lSize = ftell(f);
rewind (f);
buffer = (char*)malloc(sizeof(char)*lSize);
result = fread(buffer,1,lSize, f);
fclose(f);
free(buffer);
Use malloc() to set an initial buffer for your text line. Say, 16 chars.
Loop over the file and retrieve one character at a time with fgetc(). Store it into your buffer, at the appropiate place. If it is a newline, put a NUL character instead in the buffer and exit the loop.
When the buffer is about to get full, realloc() it and expand it for 16 more chars. If the realloc is succesfull, go to step 2.
I am attempting to read a file into a character array, but when I try to pass in a value for MAXBYTES of 100 (the arguments are FUNCTION FILENAME MAXBYTES), the length of the string array is 7.
FILE * fin = fopen(argv[1], "r");
if (fin == NULL) {
printf("Error opening file \"%s\"\n", argv[1]);
return EXIT_SUCCESS;
}
int readSize;
//get file size
fseek(fin, 0L, SEEK_END);
int fileSize = ftell(fin);
fseek(fin, 0L, SEEK_SET);
if (argc < 3) {
readSize = fileSize;
} else {
readSize = atof(argv[2]);
}
char *p = malloc(fileSize);
fread(p, 1, readSize, fin);
int length = strlen(p);
filedump(p, length);
As you can see, the memory allocation for p is always equal to filesize. When I use fread, I am trying to read in the 100 bytes (readSize is set to 100 as it should be) and store them in p. However, strlen(p) results in 7 during if I pass in that argument. Am I using fread wrong, or is there something else going on?
Thanks
That is the limitation with attempting to read text with fread. There is nothing wrong with doing so, but you must know whether the file contains something other than ASCII characters (such as the nul-character) and you certainly cannot treat any part of the buffer as a string until you manually nul-terminate it at some point.
fread does not guarantee the buffer will contain a nul-terminating character at all -- and it doesn't guarantee that the first character read will not be the nul-character.
Again, there is nothing wrong with reading an entire file into an allocated buffer. That's quite common, you just cannot treat what you have read as a string. That is a further reason why there are character oriented, formatted, and line oriented input functions. (getchar, fgetc, fscanf, fgets and POSIX getline, to list a few). The formatted and line oriented functions guarantee a nul-terminated buffer, otherwise, you are on your own to account for what you have read, and insure you nul-terminate your buffer -- before treating it as a string.
This question already has answers here:
reading a text file into an array in c
(3 answers)
Closed 8 years ago.
I am trying to read 7M data from a file but it is failing. When I googled,I found that there is no limit for reading data.
My code given below is failing with segmentation fault.
char *buf = malloc(7008991);
FILE *fp = fopen("35mb.txt", "rb");
long long i = 0;
long long j = 0;
while(fgets(buf+i, 1024, fp)) {
i+=strlen(buf);
if(i==7008991)break;
}
printf("read done");
printf("ch=%s\n", buf);
Need some help
If you want to read the content of a large file into memory, you may:
1. actually read it
2. mmap it.
I'll cover how to actually read it, and assume using binary mode and no text-mode mess.
FILE* fp;
// Open the file
fp = fopen ("35mb.txt", "rb");
if ( fp == NULL ) return -1; // Fail
// Get file length, there are many use to do this like fstat
// TODO: check failure
fseek ( fp, 0, SEEK_END );
flen = ftell ( fp );
fseek ( fp, 0, SEEK_SET );
if ( fread ( buffer, flen, 1, fp ) != 1 ) {
// Fail
}
fclose ( fp );
There are a few things that could go wrong here.
Firstly, no this line, memory allocation can fail. (Malloc can return a NULL pointer, you should check this. (You should also check that the file opened without error.)
char *buf = malloc(7008991);
Next, in the loop. Remember that fgets reads one line, regardless of how long that is, up to a maximum of 1024-1 bytes (and appends a null-character). Please not that for binary input, using fread is probably more appropriate.
while(fgets(buf+i, 1024, fp)) {
After that, this is a good line, as you really do not know how long a line is.
i+=strlen(buf);
This line however is probably why you are failing.
if(i==7008991)break;
You are requireing the size to be exactly 77008991 bytes long to break. That is rather unlikely unless you are very very sure about the formatting of your file. This line should probably read if ( i >= 7008991 ) break;
You should probably replace your explicit size with a named constant as well.
Most probably the size of your file is exactly 7008991 bytes. But when you read the file with fgets you ask to write at most 1024 bytes. This is not true when you reach the end of the file. Suppose you already read 7008990 bytes, then you should call fgets with: fgets(buf+i, 1, fp) because your buffer has got no more than one byte left.
Another issue is that you want to print the buffer at the end of your program. For this to work your buffer must be NUL terminated. So you need to allocate one more byte than the file size. fgets will automatically append the NUL byte.
Yet another issue is the way you increment your counter: i += strlen(buf) this is wrong, the correct code is: i = strlen(buf)
All of this assume there is no NUL bytes in your code. As already explained in comments, it is wiser to use fgets only when dealing with text files. When reading binary files you'd better use fread.
The corrected code would be:
unsigned long FILE_SIZE = 7008991+1;
char *buf = malloc(FILE_SIZE);
FILE *fp = fopen("35mb.txt", "rb");
long long i = 0;
long long j = 0;
while(fgets(buf+i, FILE_SIZE-i, fp)) {
i = strlen(buf);
if(i==7008991)break;
}
printf("read done");
printf("ch=%s\n", buf);
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.
#define "/local/home/..."
FILE *fp;
short *originalUnPacked;
short *unPacked;
int fileSize;
fp = fopen(FILENAME, "r");
fseek (fp , 0 , SEEK_END);
fileSize = ftell (fp);
rewind (fp);
originalUnPacked = (short*) malloc (sizeof(char)*fileSize);
unPacked = (short*) malloc (sizeof(char)*fileSize);
fread(unPacked, 1, fileSize, fp);
fread(originalUnPacked, 1, fileSize, fp);
if( memcmp( unPacked, originalUnPacked, fileSize) == 0)
{
print (" unpacked and original unpacked equal ") // Not happens
}
My little knowldege of C says that the print statement in the last if block should be printed but it doesnt, any ideas Why ??
Just to add more clarity and show you the complete code i have added a define statement and two fread statement before the if block.
Few points for your consideration:
1. The return type of ftell long int so it is better to declare fileSize as long int (as sizeof(int) <= sizeof(long)).
2. It is a better practice in C not to typecast the return value of malloc. Also you can probably get rid of sizeof(char) when using in malloc.
3. fread advances the file stream thus after the first fread call the file stream pointer has advanced by the size of the file as dictated by fileSize. Thus the second fread immediately after that will fail to read anything (assuming the first one succeeded). This is the reason why you are seeing the behavior mentioned in your program. You need to reset the file stream pointer using rewind before the second call to fread. Also you can check the return value of fread which is the number of bytes successfully read to check how many bytes were actually read successfully. Try something on these lines:
size_t bytes_read;
bytes_read = fread(unPacked, 1, fileSize, fp);
/* some check or print of bytes read successfully if needed */
/* Reset fp if fread was successfully to load file in memory pointed by originalUnPacked */
rewind(fp);
bytes_read = fread(originalUnPacked, 1, fileSize, fp);
/* some check or print of bytes read successfully if needed */
/* memcmp etc */
4. It may be a good idea to check for the return values of fopen, malloc etc against failure i.e. NULL check in case of fopen & malloc.
Hope this helps!
The memory allocated with malloc is not pre-initialized, so its contents are random and thus almost certainly different for the two allocations.
The expected (probabilistically speaking, "certain") result is exactly what happens.
Did you mean to load the file into both of these buffers before testing with memcmp but forgot to do so?