Saturday, June 16, 2012

In this post, I'll be discussing on how to a make a SUDOKU solver-cum-helper.

lets start:
The basic point behind the helper is that for a particular cell of the board, we find the possible numbers that it can take based on:
1.its row,
2.column and
3.box
Exploring further, at first, we find what numbers we need for a row to be completely filled and satisfy the invariant.similar is for column and the box.
So, we represent the rows, columns and boxes by 2-D arrays.
Now, for the particular cell, the possible numbers it can take will be the numbers which are supported by all the three-its row,column and box, i.e. basically we want to AND the numbers common to the these three to ""produce"" the possibilities for the current cell.Therfore, to facilitate this, we will be using bitwise coding.

                       declaration
                             declaration and initialisation

Now, what's the use of this 3-D array?
Well, obviously we need something to store each cell's possibilities.Dont focus on the initialisation part now, you will get to know after the following explanation

Now, how the bitwise coding actually works in this case:
first, let me tell you what the above arrays represent:
a statement like row[1][i]=0110101001(i:0 to 9)->represents that ith row doesn't contain the numbers [1,2,4,6,9], i.e row[i][j] is set 'j' is not present in the ith row.This way, bitwise coding is used to show the possibilities, the respective row, column or box has.Similar logic for the Xboard array: Xboard[i][j][k] is set if board[i][j] cell be filled with k, and is '0' if 'k' can't be placed in board[i][j] in any case.The '0th' bit in all the above cases has a special purpose.It is set if the field is completely filled and unset in all other cases.
Now, the above image is quite easy to understand I suppose.

Now, the most important thing:
To calculate the each cell's possibility through its row,col & box.
Actually nothing great to be done, just AND the possibilities of all the three for a specific cell.This is obvious, since a number is an option in a field if it is allowed in it's row, column and group.
                                                                                                                    
possibility
                                         calculating the possibility

k..I guess the helper is ready now.
Yup, having the possibilities for each cell actually helps a lot in solving(At least it works for me always).
Additionally, warnings in following cases can be generated:
1) fields without any option but not completely filled.
2) rows, columns or groups with missing options can be generated.

Lets proceed with coding a small solver using the above info:
Actually, its quite simple.Having before yourself all the possibilities, now you just need to figure out the cells having only one possibility(yes there will be such cells) and yes, you guessed right man->FILL THEM !.
Filling these cells will obviously change the possibilities of the other cells.So, run the possibility checker again and this goes on like this(provided, you wish to solve the sudoku !).
But BEFORE THIS, you need to change the values of all the arrays accordingly.It doesn't needs an explanation I guess on why/how to change.
You need to do this after the scanning part also.
We have the easy level solver ready.

Now, this is the most basic step I explained above.There are more than a dozen of techniques present to solve the higher level sudoku's.I will be explaining one of these to help you get through the moderate level sudoku.

This technique can be called as "hidden singles".In this, as the name indicates, we search for the fields(r/c/box) where an number is just limited to only one cell.An example will explain it more clearly.
row[3][4]=1 -> 3th row can contain 4.
But in 3rd row, only for one cell, 4th bit has set, rest all are having it unset.So, obviously that cell ought to have 4.Clear enough !
Similarly, we check for each column and box.And after filling out the cells, run the possibility checker and again the whole procedure or you can also jump to possibility checker after all the fields of a particular kind and.. THIS IS IT for the moderate level.Here's an example of how we perform this operation with the rows:

                    
                              Hidden singles for the rows

Similar to this, you can refer the other techniques and code them, and build a FULL SUDOKU SOLVER of your own (sounds great !,I know)

k then..adiĆ³s to all !
Any queries are welcomed :)

Tuesday, May 15, 2012

GDB V/S BUGS - III

Finally, the last post for gdb!
In this section, we will go through the terms like backtrace, core dump and stack overflow.
Starting with the 'backtrace' command, as the name suggests, it is used while running the prog, to know about the previous function calls made, i.e we can get to know, from where the control has come to the current function.It gives us the list of stack frames(function calls ,yet to be returned and stored on the the stack in stack frames sequentially), each with a number.This number is used to get info about any stack frame.'Info' command is used for further info on these frames.
e.g. 'info args 4' lists the list of arguments with their values, passed to the function call, stored on the stack frame #4.
similarly,'info locals #' gives a detailed info about the local variables used in the respective call.If you want to get the whole info in one go, with some extra info,like:
• the address of the frame
• the address of the next frame down (called by this frame)
• the address of the next frame up (caller of this frame)
• the program counter saved in it (the address of execution in the caller
frame)
• which registers were saved in the frame

the command is 'info frame #'.These all commands can help you figure out, specially in the recursive programs, the control flow of the program, the sequence of calls with their details, which can greatly help you to chase the bugs.
Using these, you can also find where your program stopped working i.e the details of the program when ?? 
The command 'where' is an additional alias for backtrace.

The next significant term is stack overflow:
A stack overflow occurs when too much memory is used on the call stack. The call stack contains a limited amount of memory, often determined at the start of the program.When a program attempts to use more space than is available on the call stack (that is, when it attempts to access memory beyond the call stack's bounds, which is essentially a 'buffer overflow'), the stack is said to overflow, typically resulting in a program crash.
This is also one of the main reasons of Segfault.
Following is an example which causes stack overflow(recursion without a base case)
 int main()
 {                                    
    main();
    return 0;
 }

lets come to the last term of the session now, core dump:
A core dump is a file that consists of the recorded state of the working memory of a computer program at a specific time, generally when the program has terminated abnormally (crashed), including the processor registers, which may include the program counter and stack pointer, memory management information, and other processor and operating system flags and information. These dumps traditionally get created as "core".Core dumps are often used to assist in diagnosing and debugging errors in computer programs.Gdb itself can use these dumps to debug the programs, using the 'working history' of the program stored in these files.

So, this marks the end of this post and gdb as well!
Any queries, you can post here, or mail me at yash.girdhar@gmail.com.
adios :)

Sunday, May 13, 2012

GDB V/S BUGS - II

ok..time to continue divulging!

Lets commence this post with conditional breakpoints.Now, where there are so many benefits, bp's themselves can become tedious sometime.We have to keep stepping,..stepping and stepping...
So,in situations, where we have an idea of what the error could be..like not allocating memory to a pointer,crossing bounds of an array or stack overflow, we can avoid unnecessary breaks in our program, like at every iteration of a loop or at each call of a recursive function.So, we need to specify the condition for breaking at these points.Using 'conditional breakpoints' allow us to carry through this.
Syntax is just similar, except you have to supply a condition or an C-expression,which if true, will trigger the bp.
e.g. break 10 i >10 -> prog will stop at 10th line only if i exceeds 10.
This will most likely avoid all unnecessary stepping.
We can also use gdb variables for these conditions.Next two lines will explain this:
(gdb) set $i = 0
(gdb) break main: if ++$i == 10
':'->because we are specifying condition at a fn.Rest all is clear.

Now, there is something called 'breakpoint commands' in gdb.Yup, we can define a set of commands to be executed at a bp.This is a potent tool of gdb, I must say.
These commands can be any c expression or gdb commands.These commands can be used to turn on/off other breakpoints,jumping over a part of code, correct the code, to control automatically displayed expressions and many other things.
Two special commands of these are 'silent' & 'continue'.Silent causes gdb to skip the usual printing when arriving at a breakpoint, and continue, continues execution of your application.
So, proceeding with a basic example, following lines illustrate how to relate with other bp's:
We want to set bp on the print function in our program, but the condition is that run should stop on the print function that is present only in some function, say 'run'.Here is the solution:
(gdb) break print (bp #1)
(gdb) break run  (bp #2)
(gdb) commands
the following line will be displayed prompting you for the commands:
"Type commands for when breakpoint 2 is hit, one per line.
End with a line saying just "end"."
enter the following commands
>silent
>enable 1
>continue
>end

(gdb) break 48    (bp #3)        Break at end of run function
(gdb) commands
Type commands for when breakpoint 3 is hit, one per line.
End with a line saying just "end".
>silent
>disable 1
>continue
>end

Now, the execution stops at print only when it is discovered inside run function!.We are using silent and continue in these command sets, so that they doesn't need any intervention from the user.
With some modification, you can use the above function to skip over a part of code.Use gdb 'help' to get to know more about the commands("help commands").

Carrying on, Suppose you have forgotten to allocate memory to a struct pointer and you discovered it while running the program in gdb.Now what?
If your ans is--'Simple,jst open the file again,edit it,compile & run the gdb again'--yes,this post is specially for you..
Now this is the best part:fixing errors inside the debugger itself.Above example will best illustrate it:
your code:
#9    node *start;    //no memory allocated
#10    start->n=5; 

commands to rectify this:
(gdb) break 10        (bp #4)        Break on line just after the declaration
(gdb) commands
Type commands for when breakpoint 4 is hit, one per line.
End with a line saying just "end".
>silent
>print start = (node *) malloc(sizeof(node))
>continue
>end

These breakpoint commands stop before the 10th line, allocate the memory, and continue with the 10th line, to chase the other bugs !. So, you fix the bug in the debugger and go on automatically.
BUT, important to note that this change will not be applied to the original file.So, don't forget to propagate the changes back to your original source code to permanently fix the problem!

So,that's it for this post.Next post will be devoted to the recursive programs(yes, I said 'recursive programs').
Sayonara till then :)






 

Saturday, May 12, 2012

GDB V/S BUGS - I

Gdb vs Bugs..yup,this is the most apt title I could earmark for this post.In this post,I'll unwrap the power of gdb in debugging our C-programs.

To start with,let me give you an idea about how gdb can help you with your programs.So, with gdb,you can inspect what your program is doing at a certain point during execution,with different test variables.You can check or change a variable's value,skip or add a part of the code,dyanamically resolve a bug in the code,all these in b/w the execution.In progs including recursion,at any stage you can analyse all the previous calls,stored on the stack.On the whole,you CAN know whats happening inside your program.

So,lets kickoff with some brief introduction:
GDB(The GNU debugger),originated by Richard stallmen,is a free software under the GPL license,and can be used for other languages also, like c++,fortran.
In C, to make our executable file work with gdb,we have to use an extra '-g' flag,when we compile the code.This enables the gdb to implant some "debugging symbols" in the file, that help it with running the code.After that,to start gdb,jst run the command:'gdb "executable name"'.
e.g gdb a.out
gdb has an interactive shell, much like the terminal one. It can recall history with the arrow keys, executes the previous command with a 'return' hit, auto-complete words (most of the time) with the TAB key, and has other nice features.

Enough with the introduction part,lets jump to our program now:
To execute our program in gdb,we have the "run" command.It simply runs our program till the end or the first 'breakpoint'(explained later),if set, provided there is no error in the program and if it has errors,we should get some output like the line or function with its parameters, where the program crashed.
Imp to note that for seg fault,program receives "SIGSEGV" signal from the kernel.

Now, for debugging, we come to the most important term of gdb,'Breakpoints',rather "The Breakpoints"(recalling their importance).Breakpoints, as the name suggests,are the points in our program,set by us, that enable us to stop the program in between and look around it.This is necessary for systematic investication of aur program, to debug it.
We can set these breakpoints by the 'break' command."break space line_num" sets a breakpoint at that line number.We can also break the program at a specefic function,
e.g 'break main' will stop the program whenever the main function starts.
We can set as many breakpoints as we want and after setting a breakpoint(bp),we will get some info about that bp,including its number.You will need this number for referring to this bp later.Now,once you have set the bp's, run again.Execution will stop at the point specified by you.

After hitting the bp,you can inspect your program status at that point.To further execute the program,we have different functions.One is 'continue',which will run the program till next bp(if none is there,till the end).Second is "Step", which gives you a fine-grained control, by running the program line-by-line.So,you can now check your program's status even after each line.Similar to step,the third funtion is 'next',except this one doesn't execute each line of a sub-routine, rather treats it as a single instruction.But typing step or next each time can be tidious..ryt.
No worries,gdb has a solution for this also.If you hit RETURN,it will run the same command you just entered.

Stopped the program,time to check it out!
But how?
You can use "print" command to print any variables's value(print variable_name).Talking of checking the prog,there is one more important term-"watchpoints".Whereas breakpoints interrupt the program at a particular line or function, watchpoints act on variables.They pause the program whenever a watched variable’s value is modified.
e.g. 'watch i' will interrupt the program whenever i changes and print the new and old values.
But it relies on the variable's scope,relative to where we are at the time of watch.
There are other commands like info breakpoints,delete, whose name indicate their functions.

There are other things also in gdb like conditional breakpoints,commands combined with breakpoints,fixing program errors dynamically,jumping over misbehaving code,backtrace(mainly in recursive programs),core dumps,relating the breakpoints and many other.These all will be included in my upcoming posts.

Any queries regarding the above post are welcomed.
So, adios till then! and this time, I am sure this post will be helpful.




 

Tuesday, May 8, 2012

FILE HANDLING IN C

So,finally a post after some time..!
and in this post,I'll be discussing about performing simple operations with files in C, including creating,reading & updating.

Starting with some basic stuff, C views each file simply as a sequencial stream of bytes i.e whenever a file is opened in a C program, a stream is associated with the file.Use of these streams is to provide communication channels between files & programs and Each file ends with a 'end-of-file' marker i.e "Ctrl+D" in linux and "Ctrl+Z" in windows.You will find use of this end-of-file marker in many of your C programs, working with files.
 
It is quite interesting to know that whenever we execute any C program,three files and their associated streams are automatically opened-'Standard Input'(enables the program to read data through the keyboard),'Standard Output'(to print data on the screen) & Standard Error'(to print the error messages).These three streams are manipulated using the file pointers-'stdin','stdout' & 'stderr',respectively.
The stream stdout,stdin or in fact,any output stream is buffered,i.e. data coming to that stream is stored in a buffer and is not printed until the buffer is full.To avoid this,we can use fflush() function. 

Opening a file returns a pointer to the 'FILE' structure defined in <stdio.h>(defined in detail in previous post),that contains information used to process a file.This structure includes a 'file descriptor' that is used as an index into an operating system array(File Open Table).Each index(FCB-file control block) of this array is used to administer a particular file.

Now,time for some practical things:
With respect to performing operations on file,I'll be discussing merely the functions used for different operations,not the whole programs.

So,lets start with creating a file:
The standard library function 'fopen' is used to create a file or refer to an existing file,through a file pointer.
Syntax:        fp=fopen("filename","open-mode").
The above statement opens the file 'filename' for the specified mode & associates the file pointer fp to it. If the file doesn't exists,it will create a new one.
The second argument of fopen specifies the mode in which we want to open the file.There are mainly three modes-"r"(reading),"w"(writing:discards the previous contents of the file),"a"(append).Other extensions of these modes also exist like:"r+"(for update(reading and writing),"rb","wb","ab";'b' character is added to indicate that the file is a binary file. 
fopen returns NULL if the given file doesn't exists & it is not able to create a new file(reasons include, system running short of memory)

But what to do after opening the file??
So aur next operation is scanning & writing to a file, which is done using the functions 'fscanf' & 'fprintf'.
Both these functions are similiar to scanf & printf functions,except these have first argument as the required file pointer.If the file pointer is given as stdin/stdout,these will work as scanf & printf.
Syntax:     fscanf(fp,"%d",&number)
        fprintf(fp,"%d",number)
fscanf returns EOF if a problem occurs whie reading data,otherwise the number of data items succesfully read.

Other functions also exist for exist for scanning a charater or a string from a file.These are fgetc & fgets.These also have the same syntax as that of getchar or gets.
Synatx:        fgetc(fp)
        fgets(str,max_size,fp)
str refers to the string variable in which the scanned string will be stored,max_size,as the name indicates, is the max size of the string that can be scanned.Note that 'fgets' can be used to read a file linewise by providing appropriate size of the string.
Similarly,for writing,we have analogous 'fputc' function.

Now,while reading a file,we may need to shift the file pointer to the starting of file.This can be done by "rewind" function.
Syntax:        rewind(fp)

All the functions I've discussed above are mainly used for sequential files, i.e. where data is stored sequentially(characterwise).Therfore,in these type of files, its very difficult to randomly edit the file,because even numbers also are stored characterwise(i.e they don't occupy full 4 bytes resulting in varying size of different numbers).Therefore,editing can result in overwriting of the data.
So,we use other type of files known as random-access-files.In these type of files,length of different records are fixed i.e variables of each data-type are provided their respective size.Nowadays, these type of files are used almost everywhere..
Funcions used for reading & writing to a random-access-file are 'fread' & 'fwrite'.
Syntax:        fread(&n,sizeof(n-datatype),1,fp)
n refers to the variable in which we want to store the scanned data,'1' refers to the no. of elements of type 'n' to be scanned:this is mainly used to scan multiple elements of an array.
Similar syntax is for fwrite:         fwrite(&n,sizeof(n-dataype),1,fp)
If 'n' is an array,it can be used to write multiple elements of this array,by changing '1' to the required number.
fwrite returns the number of items it successfully output.If this number is less than the 3rd argument,there is a problem.Same is for fread.

Finally,the most important thing,how to reach the record that we want to edit??
The function used for shifting the file pointer, is 'fseek'.
Syntax:        fseek(fp,long int offset,int whence)
offset refers to the number of bytes to seek from the location 'whence' in the file.Argument whence can have three values->SEEK_SET(starting of the file),SEEK_CUR(current location of the pointer),SEEK_END(end of the file).
fseek returns a non-zero value if the seek opearion can't be performed.

These all are the functions that you will require for working with files.Any queries regarding the same are welcomed.
 
and like always,hope this post is helpful :)

Thursday, January 12, 2012

Getting started with LINKED LISTS

In this post, I will be discussing about basic operations in linked lists, basically inserting an element(at the end or beginning),deleting the same & printing the list(in a 'programmer's' fashion).I shall not be covering the basic concepts in the operations, rather just covering the main stuff.
So, let’s start with a brief introduction of 'linked list':
A linked list is basically a collection of entities, which are a collection of dissimilar data-types. These entities are linked to each other (each to its next one) through pointers of the same data-type. The end of this list is marked by the 'next' pointer of an entity, pointing to a 'NULL'.
Throughout the post, i will be talking about the following structure:
typedef struct nod
{
      int n;
      struct nod *next;
}node;
//typecasting the name 'struct nod' to 'node'.
And, I have taken a dummy node first (why?, u will get to know after going through the post).
So, what I have now, is a linked list with a single dummy node, having no value & whose next pointer is pointing to NULL.


Ok, time to expand our list, presenting straightaway the function which inserts the no's at the end of the list:
void insert_rec(node *start,int x)
{
      if(start->next==NULL)
      {
            start->next=(node *)malloc(sizeof(node));
            start->next->next=NULL;
            start->next->n=x;
            return ;
      }
      insert_rec(start->next,x);
}
In this, we are traversing the list till the end,i.e. till we encounter that next pointer is pointing to NULL, through 'recursion'.When the same is encountered,we are assigning the memory(equal to the structure) to generate the next node and then, assigning the no. and maintaining the terminating condition.
We can perform this without recursion also, as the following code for entering the no at the beginning demonstrates:
void insert_beg(node *start,int x)
{
      node *temp;
      temp=(node *)malloc(sizeof(node));
      temp->next=start->next;
      temp->n=n;
      start->next=temp;
}
Now this is where dummy node comes into play.Initially, the start pointer is pointing to the dummy node.So, the only thing we have to do is to enter the element between the dummy node and rest of the list.So, we are taking another block of memory, providing it required specifications and just making the appropriate changes in the links.After this, perhaps, u can appreciate the idea of dummy node.

But, to prevent some of you becoming "emotional”, let me clear you that we CAN do it without dummy node, but then, we will have to use double pointer,i.e. we will have to pass the address of the head node to the node, so as to 'change the head pointer' after inserting the new node. Following code explains it well:
void in_beg(node **start,int x)
{
      node *temp;
      temp=(node *)malloc(sizeof(node));
      temp->next=*start;
      temp->n=x;
      *start=temp;//shifting the head pointer
}

Now, which of the two functions is better, depends on your perception.
Similar code for inserting the elements at the end will be:
void insert(node **start,int num)
{
      node *temp,*r;
      if(*start==NULL)
      {
            temp=malloc(sizeof(node));
            temp->next=NULL;
            temp->n=num;
            *start=temp;
            printf("<%d>\n",temp->n);
      }
      else{
      temp=*start;
      while(temp->next)//similiar to (temp->next!=NULL)
            temp=temp->next;
      temp->next=(node*)malloc(sizeof(node));
      temp->next->next=NULL;
      temp->next->n=num;
      }
}
I think there is no need to explain this func,still if any of you has a doubt, can post in comments.

Enough with inserting I think, it’s time to delete now!!

But before deleting, let’s check if we have made our list correctly (of course we have, trust me!).
But only for those emotional people, let’s check it man..
void print(node *start)
{
      start=start->next;//for passing the dummy node
      while(start!=NULL)
      {
            printf("%d",start->n);
            start=start->next;
      }
      printf("\n");
}
This will print the list,BUT it's a quite simple function I think, lets modify it a little bit. Check this out:
void print(node *start)
{
     start=start->next;
    while(start && printf("%d ",start->n))        
       start=start->next;
      printf("\n");
}

This function uses some more facts, apart from linked lists:1.Usage of '&&' operator(lazy evaluation in C)
                                              2.return value of printf
This you all must know that, "a printf function returns the length of the string which is to be printed".So,as long as there is some no. in start->n,it will return a non-zero value and this will continue till the NULL is encountered.Therefore,first printf will be executed, the value will be returned to '&&' operator.
So, what is lazy evaluation?
In C,if the first expression in '&&' operator returns a 'zero' value, then the second condition is not even evaluated and the operator ofcourse,returns a zero value.                
But WHY we need this?
It is because after traversing the list,when the start pointer is pointing to NULL,the printf still tries to print 'start->n',i.e. tries to access the NULL, which is not allowed, resulting in the most common error in structure handling-"segmentation fault".But,when we '&&' it with start, at this situation, it will return a zero value, and therefore the printf will not be executed.
So, start should come first in '&&' operator(U can check by reversing the order)

                       
Finally, time to free some of our precious memory.
The function to delete is rather a simple one, but needs to be dealt carefully.
Following code demonstrates deleting from  beginning and the end:
void delete_beg(node *start)
{
      node *temp;
      temp=start->next;
      start->next=start->next->next;
      free(temp);
}
void delete_end(node *start)
{
      while(start->next->next!=NULL)
                  start->next=start;
      node *temp;
      temp=start->next;
      start->next=start->next->next;
      free(temp);
}
The shifting of the links, I think, do not needs an explanation.Deleting from beginning makes use of 'dummy' node, as in inserting. But yes, here again, we can use a double pointer to perform the same.
void del_beg(node **start)
{
      node *temp;
      temp=*start;
      (*start)=(*start)->next;
      free(temp);
}
The 'free' function is use to free a specific block of memory.

What if we biasly want to delete a particular node?  nothing, refer to the next function:->
void delete(node *start,int x)
{
      while(start->next && (start->next)->n!=x)
            start=start->next;
      if(start->next)
            return;
      node *temp=start->next;
      start->next=(start->next)->next;
      free(temp);
}
The only thing we need to do is-first, reach that node(the extra condition in while) & delete it! and make sure that you don't cross the NULL(if you do reach the NULL, just return the pointer).

So, these were some of the operations to get started with linked lists. In the next post,I will be covering some advanced operations, like sorting a list,reversing,merging two sorted lists..

Hope, this is helpful:)





 
 

Sunday, January 8, 2012

What does FILE *fp means ??

What exactly does the following statement means?
'FILE *fp;
fp=fopen("filename","mode");
'

Many of you might answer:we have declared a file pointer 'fp' which points to the file 'filename'.
But actually,this is not correct.

C has a special "data type" for handling files which is defined in the standard library 'stdio.h '.
It is called the file pointer and has the syntax FILE*.

First of all let me confirm you that **FILE is not a key word** , perhaps its a user defined data type defined in 'stdio.h' , presenting you the following code to justify my answer !

typedef struct {
int level; /* fill/empty level of buffer */
unsigned flags; /* File status flags */
char fd; /* File descriptor */
unsigned char hold; /* Ungetc char if no buffer */
int bsize; /* Buffer size */
unsigned char *buffer; /* Data transfer buffer */
unsigned char *curp; /* Current active pointer */
unsigned istemp; /* Temporary file indicator */
short token; /* Used for validity checking */
}FILE;

This is the structure stored in 'stdio.h' under the name FILE.This file pointer is just to store the composite information about a file subject to manipulation.These components specify certain things about the file to the operating system.
Thus, FILE, which contains all the information about the file, is subsequently used as a communication link between the system and the program.

Starting with the actual process which happens when we use 'FILE':
First of all,u all should know that while doing any operation on a file in C,we are not working on the actual file.
What happens is that the contents of the file we want to perform, are copied in a memory buffer.

and whenever we execute the above two statements, a structure as defined above is created,its elements are setup for the file referred and the base addresss of this srtucture is returned in pointer 'fp'.Thus,fp is not pointing to the file's buffer.
Within the structure to which fp is pointing,there is a character pointer called 'buffer'(refer to the structure).It is this pointer which points to the file's buffer.
It can be explained like this:
address of structure=1500 => address stored in fp=1500
address of file buffer=1700 => address stored in 'char *buffer'=1700

and we dont need to increment this 'buffer' pointer while using func such as getc().This is done by the function itself.To do this internally, operation of the form 'fp->buffer=fp->buffer+1' is done.

This whole information is a basic prerequisite if u want to start-up with using file i/o functions.

hope, this is helpful:)