how to set file pointer with fseek - c

I know my file pointer is at end of the line after printing this string: "xyz".
How can I get it to the start of the line? (pointing to x)
offset = ftell(fp);
fseek(fp, offset - sizeof("xyz") , SEEK_SET);
Above doesn't seem to work.
How can I achieve that?

I would store the offset by issuing a beginning = ftell(fp) before reading/writing you "xyz".
Then fseek(fp, beginning, SEEK_SET);
Would this be possible?

sizeof("xyz") will return 4 since you have the three characters plus the terminating null. You should use strlen("xyz") instead or subtract one from the sizeof result to account for the null.

As the type of "xyz" is char const *, sizeof("xyz") will return the size of a standard pointer, typically 4 or 8.
Also note that fseek does not work in text mode, only if the file has been opened in binary mode, as it's not possible to tell how big newlines are on the underlying host system.
In addition, it's better to use SEEK_CUR, as it will more the read/write point relative to the current position.

Related

C: SEEK_END in a printf shows unexpected value

When I use SEEK_END, I expect it to correspond to the position of the last character in the stream. But inside a printf it seems like it does not.
I have a file that contains 1010 characters. I open it with fopen, then I try to print the position of the last character of this file:
printf("Last position is: %d\n", SEEK_END);
The output is Last position is: 2 whereas I expect it to be Last position is: 1010. 2 does not correspond to the last line or last column, since I have 101 lines of 10 characters each. I don't know what it is.
Curiously, this code works well:
fseek(file, 0, SEEK_END);
printf("Last position is: %d\n", ftell(file));
The output is Last position is: 1010. But the problem here is that I am moving the virtual cursor in the file, which I do not want.
How can I print the value of SEEK_END without having to change the position of the virtual cursor, and more importantly, why do my printf outputs 2?
You have a misunderstanding. SEEK_END is not a magical symbol that somehow stores the length of the file you're thinking of right now. It is a constant, used as a code to tell fseek() what reference point to use for the specified file offset.
If you want to determine the size of a file whose name you know, and you are on a POSIX system, then you can use fstat(). If all you have is a FILE *, then your best bet is probably to record the current position, seek to the end of the stream, determine the position, and then seek back to the starting point:
fpos_t current;
long end;
/* error checks omitted for brevity */
fgetpos(file, &current);
fseek(file, 0, SEEK_END);
end = ftell(file);
fsetpos(file, &current);
printf("Last position is: %ld\n", end);
Of course, all that depends on the stream being seekable. Not all of them are. If you have a non-seekable stream then very likely there is no meaningful sense of its last position to begin with.
There is also a potential issue with file offsets exceeding the size of a long. fgetpos() and fsetpos() can be expected not to be sensitive to that, but their accompanying fpos_t type may be an aggregate type (i.e. a struct), and thus not direct interrogable. You can work around that with lseek(), but that comes from POSIX, not standard C.
SEEK_END is a parameter to fseek, it tells the fseek function how it should position in the file. You see 2 probably because in stdio.h it says #define SEEK_END 2 although the actual value is unspecified.
In order to get the offset you need to use ftell().
You can have a look at a specific implementation of fseek here.
From here is possible to see that SEEK_END is an integer constant. It is not like a variable that holds the last position of your file. So, whenever you print SEEK_END value, it will be 2.

fseek behavior with binary file

I'm working with a binary format.
I've noticed that
fseek(fp, offset, SEEK_SET);
fread(&mystruct, sizeof(struct mystruct_thing), 1, fp);
produces output that's different from simply
fread(&mystruct, sizeof(struct mystruct_thing), 1, fp);
which follows expected behavior.
Why is this the case? Is it because SEEK_SET overrides the offset parameter?
The second argument of fread is the size of each item to be read, in this case the struct. I don't understand how you would expect the offset to go there – it should be something like sizeof(mystruct).
Edit: Now that the question has been edited, the reason why the two pieces of code produce different results is simply that the first one seeks the position of fp to offset before reading and the second one doesn't. fread reads sizeof(struct mystruct_thing) bytes starting from the current position of fp, so the starting position differs (assuming offset is not the same position at which you are already at before fseek) because fseek sets the position for future reads (and writes).
The first fragment will read a struct from offset bytes into the file, the second fragment will read it from the current file position - if the file has just been opened, that will be zero.
The obvious explanation perhaps is that offset is not equal to zero.

Why the ftell returns 0 in this function?

When I run my program and I choose to see the product list, it doesn't print anything. After some time, I find out that the value of fl_size is always 0. Why is this?
void view_prdct_code_list() {
FILE *stock = fopen("stock.dat","r+");
assert(stock);
int fl_size=ftell(stock);
int prd_size= sizeof(product);
int quantity= fl_size/prd_size;
printf("fl_size=%d",fl_size);
fseek(stock,0,SEEK_SET);
prdct cprd= (product *)malloc (sizeof(product)*quantity);
assert(cprd);
int i;
fread(cprd,prd_size,quantity,stock);
for (i=0;i<quantity;i++){
printf("PRODUCT CODE: %d\n",cprd->code);
}
free(cprd);
fclose(stock);
}
ftell does not return the total size of the file; it returns the current read or write position within the file. You call ftell immediately after opening the file, so that position is the very beginning of the file. You can either use fseek(stock, 0, SEEK_END) to seek to the end before calling ftell, or you can drop down a layer and use fstat(fileno(stock)) to retrieve the file size directly from the OS.
Further notes:
Neither of these options will work if you are reading from a pipe. (In general, you need to check for the success of every single one of your file access operations.)
fread is not guaranteed to read the entire file in one gulp even if you ask it to.
As 'alk' points out, ftell returns a long, not an int.
If long is only 32 bits, it is possible for a file to be so large that its size does not fit in a long. If your program needs to handle files that big, you need to #define _FILE_OFFSET_BITS 64 at the top of every .c file (before all the includes) and use fseeko and ftello. (Or whatever the Windows equivalent is.)
You should be opening this apparently-binary file with mode "r+b".
Binary files with no file header (and in particular with no magic number, of at least four bytes, at offset zero) are a Bad Thing.
Do not cast the return value of malloc. (It is necessary to do this in C++, but in C it is not only unnecessary, it can hide bugs.)
Check man page for ftell, for example this one: http://linux.die.net/man/3/ftell
Here is the relevant part: "The ftell() function obtains the current value of the file position indicator for the stream pointed to by stream."
When you open the file, cursor position will be at the start. So distance from start will be zero. Therefore ftell returns zero.
To find the size of file, see this link: How can I get a file's size in C?. Here's a snippet in short:
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
Make sure to call fseek(fp, 0L, SEEK_SET); after above.
Because ftell returns the size from the beginning to the current position of the file.
fseek(stock,0,SEEK_SET);
Means you set the position to the first bite of the file.
Also you gotta set fl_size=ftell(stock); after the fseek.

Going backwards by one in file stream

Say I have a file pointer like this:
file_ptr = fopen(“test.txt”, “r+”);
and I want to change each char's ASCII value as I move through the stream (I am doing this as a cipher, so if there is a better or more efficient way to do this, please let me know).
I am trying to use a while(!feof(file_ptr)) {} loop with fgetc() and fputc, but the file_ptr will be pointing to the next char, so i want to know if there is something i can do point it backwards one spot.
Essentially, I want to know the file stream equivalent for:
char* blah="blah blah";
char* index=blah;
index++;/*how to navigate a file stream in this way*/
Yes: you can use the fseek function:
fseek(file_ptr, -1L, SEEK_CUR); // move backwards one character
Furthermore, after your fputc and before your fgetc, you'll want to call fseek again:
fseek(file_ptr, 0L, SEEK_CUR); // don't move
just to notify the system that you're switching between reads and writes, so that it knows to properly flush all buffers and whatnot. (Otherwise you might not actually be where you think.)
By the way, for this to work properly, you'll want to open the file in binary mode rather than text mode:
file_ptr = fopen("test.txt", "rb+");
since otherwise the within-C definition of "character" might not exactly match the inside-the-file definition of "character" (especially when it comes to line endings), and fseek might put you in the middle of one of the latter.

C using fread to read an unknown amount of data

I have a text file called test.txt
Inside it will be a single number, it may be any of the following:
1
2391
32131231
3123121412
I.e. it could be any size of number, from 1 digit up to x digits.
The file will only have 1 thing in it - this number.
I want a bit of code using fread() which will read that number of bytes from the file and put it into an appropriately sized variable.
This is to run on an embedded device; I am concerned about memory usage.
How to solve this problem?
You can simply use:
char buffer[4096];
size_t nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp);
if (nbytes == 0)
...EOF or other error...
else
...process nbytes of data...
Or, in other words, provide yourself with a data space big enough for any valid data and then record how much data was actually read into the string. Note that the string will not be null terminated unless either buffer contained all zeroes before the fread() or the file contained a zero byte. You cannot rely on a local variable being zeroed before use.
It is not clear how you want to create the 'appropriately sized variable'. You might end up using dynamic memory allocation (malloc()) to provide the correct amount of space, and then return that allocated pointer from the function. Remember to check for a null return (out of memory) before using it.
If you want to avoid over-reading, fread is not the right function. You probably want fscanf with a conversion specifier along the lines of %100[0123456789]...
One way to achieve this is to use fseek to move your file stream location to the end of the file:
fseek(file, SEEK_END, SEEK_SET);
and then using ftell to get the position of the cursor in the file — this returns the position in bytes so you can then use this value to allocate a suitably large buffer and then read the file into that buffer.
I have seen warnings saying this may not always be 100% accurate but I've used it in several instances without a problem — I think the issues could be dependant on specific implementations of the functions on certain platforms.
Depending on how clever you need to be with the number conversion... If you do not need to be especially clever and fast, you can read it a character at a time with getc(). So,
- start with a variable initialized to 0.
- Read a character, multiply variable by 10 and add new digit.
- Then repeat until done.
Get a bigger sized variable as needed along the way or start with your largest sized variable and then copy it into the smallest size that fits after you finish.

Resources