File pointer in c - c

I am trying to understand what does file pointer increment means .
I have declared file pointer fp and assuming that when I use fopen for any file (say test99.txt) and try to read it then
compiler dynamically allocate memory ( in heap ofcourse because I think internally fopen make use of malloc in order to put file in main memory)
and once file stream/data of file is put in memory then I am assuming fp contains the start address of that file stream.
Now incrementing fp by 1 (++fp) which is pointer of type FILE will increase/hop the position of fp by total size of data/stream inside that file
test99.txt. If not, and let's say incrementing fp will move fp pointer to the next character (1 byte) within the file stream then why is the below output ? ( why fp moved by 16 bytes:see the diff)
Where am I misunderstanding .
Information : size of file is 66 bytes(8KB) . Using program on unix platform on 64 bit machine (ia64 hp server) . Compiler is of HP HP-ACC-Link. Program in C
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;
char ch;
fp=fopen("/home/akhils/file_dir/test99.txt","r");
printf("Address of file is %d", fp);
printf("\nLet's see value of ++fp %d\n", ++fp);
fclose(fp);
}
Output : Address of file is 2130569600
Let's see value of ++fp 2130569616

You should not be incrementing FILE* pointers, it only points to one FILE structure allocated by fopen for you.

fp is a pointer to object of type FILE. It doesn't refer to any data of the actual file, it contains some internal data like handles and stuff.
When you increase this pointer, it is increased by the size of the FILE object (it depends on implementation, 16 bytes in your example). So if it was 2130569600, it will become 2130569616. But if you try to access something by this incremented address, you will probably get an error.

The incremental function adds a number which is the weight of the type you are using.
For pointers, it permits you to go to the next pointer if you have a table of pointer. Otherwise, it's a bad use.
Here, it adds 16 bytes to the original address because a FILE pointer weight 16 bytes, like all pointers. Like Maxim Egorushkin said, it only point to the the structure allocated.
Sorry for my bad english, I hope I'll be helpfull for you.

Related

Does fopen give back an adress?

So I have declared a pointer *f of type FILE and now I say that that pointer is equal to fopen("text.txt", "r"). So since a pointer stores an address, is fopen giving back the address of a file?
FILE *f;
f = fopen("text.txt","r");
is fopen giving back the adress of a file?
No. There is no such thing as "address of a file".
What fopen returns is a pointer to dynamically allocated opaque structure FILE, which describes how to get the contents of the file. This description is opaque in a sense that it provides no useful info to you. But routines such as fgets(), fread(), etc. know how to use that info to get the actual file contents.
fclose deallocates this structure, so if you have matching fopen and fclose there are no memory leaks (from these functions).
The function fopen is returning the address of an object of type FILE. According to §7.21.1 ¶2 of the ISO C11 standard, this object must be capable of
recording all the information needed to control a stream, including its file position indicator, a pointer to its associated buffer (if any), an error indicator that records whether a read/write error has occurred, and an end-of-file indicator that records whether the end of the file has been reached;
The exact size and contents of this object may differ from compiler to compiler and is of no interest to the average programmer. All that the average programmer must know is that they must pass the pointer returned by fopen to other I/O functions provided by the C standard library.
The standard does not specify how FILE should be defined. The only thing it says is what result you will get when you pass an object of that type to various functions. This means that this type may be different in various implementations. This is ONE way that is used:
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
It comes from MinGW32.
Yes, it's giving back the address of a FILE object. Now that type is opaque. That is, you are meant to not know the actual contents of the data structure being referenced and hence must never dereference the pointer (happily, the compiler will not let you get away with this).

Why FILE pointer after being passed to a function changes when back in main in C?

As far as I understand passing a pointer to a function essentially passes the copy of the pointer to the function in C. I have a FILE pointer that I pass to a function func(), func() reads a line from a file and then when we return to main(). I read another line from the file using the same FILE pointer.
However, while I would imagine that I'd read the line exactly from before func() was called, I actually read the next line after what func() had read. Can you please explain why FILE pointer behaves this way?
This is my code:
#include <stdio.h>
#define STR_LEN 22
void func(FILE *fd);
int main() {
FILE *fd;
char mainString[STR_LEN];
if (!(fd = fopen("inpuFile", "r"))) {
printf("Couldn't open file\n");
fprintf(stderr, "Couldn't open file\n");
}
func(fd);
fgets(mainString, STR_LEN, fd);
printf("mainString = %s\n", mainString);
fclose(fd);
return 0;
}
void func(FILE *fd) {
char funcString[STR_LEN];
fgets(funcString,STR_LEN, fd);
printf("funcString = %s\n", funcString);
}
However, while I would imagine that I'd read the line exactly from before func was called ...
I can't imagine why you would imagine that. What if the FILE* references a network connection that has no replay capability at all where reading is consumption. Where would the line be stored such that you could read it again? There would be absolutely no place to put it.
Not only would I not imagine that, it's kind of crazy.
As far as I understand passing a pointer to a function essentially passes the copy of the pointer to the function in C.
Correct. But a copy of a pointer points to the very same object. If I point to a car and you copy me, you're pointing to the very same one and only car that I'm pointing to.
Because FILE pointer points on some data that gets changed when the file is read/written.
So the pointer doesn't change (still points to the handler structure of the file) but the data pointed by the structure does.
Try passing pointer as const FILE * you'll see that you cannot because fread operation (and others) alter the pointed data.
One way would be to duplicate the file descriptor, which dup does, but doesn't work on buffered FILE object, only raw file descriptors.
The problem is in your initial statement:
As far as I understand passing a pointer to a function essentially passes the copy of the pointer to the function in C.
This does not change much, as whatever you are accessing as a pointer, still holds the location of the FILE you are accessing, the whole point of using pointers as arguments for a function in C, is so that you can modify a certain value outside the scope of a function.
For example, common usage of an integer pointer as a function argument:
void DoSomethingCool(int *error);
Now using this code to catch the error would work like this:
int error = 0;
DoSomethingCool(&error);
if(error != 0)
printf("Something really bad happened!");
In other words, the pointer will actually modify the integer error, by accessing it's location and writing to it.
An important thing to keep in mind to avoid these kinds of misunderstandings is to recognize that all a pointer is, is essentially the address of something.
So you could (in theory, by simplifying everything a lot) think of an int * as simply an int, the value of which happens to be an address of some variable, for a FILE *, you can think of it as an int, where the value of the int is the location of the FILE variable.
FILE *fd is a pointer only in the sense that its implementation uses C construct called a "pointer". It is not a pointer in the sense of representing a file position.
FILE *fd represents a handle to a file object inside the I/O library, a struct that includes the actual position of the file. In a grossly simplified way, you can think of fd as a C pointer to a file pointer.
When you pass fd around your program, I/O routines make modifications to the file position. This position is shared among all users of fd. If a func() makes a change to that position by reading some data or by calling fseek, all users of the same fd will see the updated position.

Will file pointer move with the change of file position?

When reading K&R, I became interested in how the file position is determined. By file position, I mean where in the file the stream is currently reading or writing. I think it must have something to do with the file pointer, or the piece of data it's pointing to. So I checked stack overflow, and find the following answer:
Does fread move the file pointer?
The answer indicates that file pointer will change with the change of file position. This makes me very confused, because in my understanding, a file pointer for a certain file should always point to the same address, where information about this file is stored. So I wrote a small piece of code, trying to find the answer:
#include<stdio.h>
int main(void)
{
char s[1000];
FILE *fp,*fp1,*fp2;
fp = fopen("input","r");
fp1 = fp; /* File poiter before fread */
fread(s,sizeof(char),100,fp);
fp2 = fp; /* File pointer after fread */
printf("%d\n",(fp1 == fp2) ? 1 : -1);
}
It gives the output 1, which I believe indicates that the file pointer actually doesn't move and is still pointing to the same address. I have also changed the fread line to be a fseek, which gave the same output. So does file pointer move with the change of file position, or where am I wrong in the verifying process?
Thanks!
I think you are confusing the general concept of pointers in C, vs. the nomenclature of a "file pointer". FILE is just a structure that contains most of the "housekeeping" attributes that the C stdio runtime library needs to interact with when using the stdio functions such as, fopen(), fread(), etc. Here is an example of the structure:
typedef struct {
char *fpos; /* Current position of file pointer (absolute address) */
void *base; /* Pointer to the base of the file */
unsigned short handle; /* File handle */
short flags; /* Flags (see FileFlags) */
short unget; /* 1-byte buffer for ungetc (b15=1 if non-empty) */
unsigned long alloc; /* Number of currently allocated bytes for the file */
unsigned short buffincrement; /* Number of bytes allocated at once */
} FILE;
Note that this may be somewhat platform-dependent, so don't take it as gospel. So when you call fopen(), the underlying library function interacts with the O/S's file system APIs and caches relevant information about the file, buffer allocation, etc, in this structure. The fopen() function allocates memory for this structure, and then returns the address of that memory back to the caller in the form of a C Pointer.
Assigning the pointers values to another pointer has no effect on the attributes inside the FILE structure. However, the FILE structure, internally, may have indexes or "pointers" to the underlying O/S file. Hence, the confusion in terminology. Hope that helps.
You are right fp is never changed by fread, fseekor other f... functions. Except, of course, if you do fp = fopen(...), but then you are assigning the return value of fopen to fp and then fp changes of course.
Remember, in C parameters are passed by value, so fread cannot change it's value.
But fread does change the internal structure fp points to.
You made some confusion between a file pointer, under common definition, and the pointer in the file.
Normally with the term file pointer we refer to a pointer to a FILE structure. That structure contains all variables necessary to manage file access. This structure is created upon a successful opening of a file, and remains the same (same address) for all the time until you fclose() the file (when became undefined).
Inside the FILE structure there are many pointers that points to the file block on disk and to the position inside the current record. These pointers, managed by file I/O routines, changes when file is accessed (read or write).
And these pointers are that to which the answer you cited refers.

Why would C automatically process the next available pointer if the designated pointer is closed?

I have a question about FILE pointer operations in C; specifically, what happens when a command uses a closed file pointer.
Here is an example
FILE *fp1;
fp1 = fopen(file1,"r");
function1(fp1);
fclose(fp1);
FILE *fp2;
fp2 = fopen(file2,"r");
function2(fp1);
fclose(fp2);
So what I found out is: since fp1 is closed, the code will automatically use the next open/linked pointer, in this case, is fp2. However, if the code is changed to
FILE *fp1;
//fp1 = fopen(file1,"r");
//function1(fp1);
fclose(fp1);
FILE *fp2;
fp2 = fopen(file2,"r");
function2(fp1);
fclose(fp2);
There will be segmentation fault. In addition, if there is an open file pointer fp3 in between fp1 and fp2, and fp1 is closed, the code will select fp3.
I am not sure this way of C dealing with deleted/closed FILE pointer is just a language specific fail-safe mechanism, or has something to do with the way these pointer variables lie in the physical memory? And what happens to these pointers after fclose()?
eg. If all FILE pointers are stored consecutively in memory and fclose only delete the memory the current pointer uses, then C will access the next available memory chunk to get the value.
PS: I am not sure if all FILE pointers are stored separately from other variables so I tested it by inserting a new int pointer assignment between the above fp1 and fp2 segments. It does not interfere with the FILE pointer "inherit" process. So probably the FILE pointers are stored separately?
eg. However, if flcose() make the current pointer a NULL pointer, should any command using the current pointer just produce an error?
Thank you!
Performing any action on the FILE pointed to by fp1 after calling fclose on it results in Undefined Behavior. In all likelihood, what's happening is that, since the memory pointed to by fp1 was freed for reuse, fp2 happens to have the same value that fp1 had prior to it becoming invalid, and thus when the implementation dereferences fp1, it accesses the memory pointed to by fp2.
If you are going to open something and assign it to a pointer, the very next thing that you should do is verify that this was successful. Aside from this, here is the explanation of the behavior that you are seeing based on the code that you have posted:
First, it is not "automatically using" the next file pointer. When you close fp1 and then immediately fopen and assign it to fp2, the dynamic memory module is simply reusing that same chunk of memory. You aren't guaranteed this behavior, but since your code is so trivial it is almost guaranteed to happen regardless of the memory management library in use.
Second, when you fclose(fp1) without opening it, the system isn't generating a segmentation fault... You are. You are effectively causing a free() call to occur on something that was never allocated.

fread a single int from bin file gives me a segmentation fault in C

I want your help in something that should be easy and I do not know why it does not work. I want to read the first data from a bin which I know that it is an int. I am using the following part of code, but I am getting a segmentation fault:
int main(int argc, char **argv)
{
int *data;
/*opening file*/
FILE *ptr_myfile;
ptr_myfile=fopen(myfile.bin","rb");
if (!ptr_myfile)
{
printf("Unable to open file!\n");
return 1;
}
/*input file opened*/
printf("I will read the first 32-bit number\n");
/*will read the first 32 bit number*/
fread(&data,sizeof(int),1, ptr_myfile);
printf("Data read is: %d\n",*data);
fclose(ptr_myfile);
return 0;
}
I also tried calling it like this:
fread(data,sizeof(int),1, ptr_myfile);
It should be something with the pointer but I cannot see what.
Change:
int *data; to int data;
printf("Data read is: %d\n",*data); to printf("Data read is: %d\n",data);
You are reading the int into a pointer, then trying to dereference the pointer (which is has a value that's meaningless as a pointer).
You don't have any memory allocated to data and in the first example code you are not using the pointer correctly. This is an alternative that could work:
int data;
and then you would use it like so:
fread(&data,sizeof(int),1, ptr_myfile);
In your original code, here you are writing an int into a pointer:
fread(&data,sizeof(int),1, ptr_myfile) ;
and then this *data will be dereferencing an invalid pointer. In the alternative case:
fread(data,sizeof(int),1, ptr_myfile);
you will be using a pointer that has no memory allocated to it.
You are passing address of a non-allocated pointer. Remove * from data:
int data;
...
fread(&data, sizeof(int), 1, ptr_myfile);
You are overthinking the question of pointers. The function fread() needs to know the address at which to store the data it reads, so it is passed a pointer. That does not mean that the buffer used by fread should be a pointer, just that fread needs a pointer to that buffer.
So your first error is writing int *data; where you really just mean int data;. You say the data element to be read is an int, so you would just declare an int to hold it.
You correctly called fread to read the data by passing a pointer to actual allocated and valid memory (i.e. &data), avoiding a different beginner pitfall of passing the uninitialized pointer to integer you declared earlier.
Your actual error is caused by writing *data in the call to printf. The * operator takes a pointer and dereferences it. In other words, it assumes that the pointer points to something, and retrieves that value. However, when the pointer being dereferenced does not point to any valid something, you have a problem.
And here is where you were lucky. The value you read from the file was then treated by the * operator as an address in memory, but happened to be an address that was not part of the memory accessible to your process, which caused the system to take notice and halt the process with a segmentation fault. As a result, you learned immediately that there was an error in your code.
If you were not lucky, the integer you read from the file when treated as an address of memory could have been the address of something already present in your process. You would not have caused a segmentation fault, and you would by puzzled by why printf produced a strange answer.
Now imagine if you read a value from an untrusted source and treated it as an arbitrary address. An attacker could use that error to learn something about your program. Worse, if you had written to the memory referenced by that pointer, the attacker could conceivably change the behavior of your program.
As a final point, note that reading and writing int (or any other data type) is safe and acceptable as long as that file will never be transferred to a different system. Not all systems agree on even the simplest definitions like the number of bytes occupied by an int (which you did handle correctly by using sizeof(int), but not in a way that would allow exchanging the file with a system with a different integer size), or even the order of those bytes in memory. Correctly addressing these issues is a large subject.

Resources