The Syntax of C and C++ Function Pointers


Define a Function Pointer

Regarding their syntax, there are two different types of function pointers: On the one hand there are pointers to ordinary C functions or to static C++ member functions. On the other hand there are pointers to non-static C++ member functions. The basic difference is that all pointers to non-static member functions need a hidden argument: The this-pointer to an instance of the class. Always keep in mind: These two types of function pointers are incompatible with each other.

Since a function pointer is nothing else than a variable, it must be defined as usual. In the following example we define three function pointers named pt2Function, pt2Member and pt2ConstMember. They point to functions, which take one float and two char and return an int. In the C++ example it is assumed, that the functions, our pointers point to, are (non-static) member functions of TMyClass.

int (*pt2Function)(float, char, char) = NULL;                        // C
int (TMyClass::*pt2Member)(float, char, char) = NULL;                // C++
int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;     // C++
Calling Convention

Normally you don’t have to think about a function’s calling convention: The compiler assumes __cdecl as default if you don’t specify another convention. However if you want to know more, keep on reading … The calling convention tells the compiler things like how to pass the arguments or how to generate the name of a function. Some examples for other calling conventions are __stdcall, __pascal and __fastcall. The calling convention belongs to a function’s signature: Thus functions and function pointers with different calling convention are incompatible with each other! For Borland and Microsoft compilers you specify a specific calling convention between the return type and the function’s or function pointer’s name. For the GNU GCC you use the __attribute__ keyword: Write the function definition followed by the keyword __attribute__ and then state the calling convention in double parentheses. If someone knows more: Let me know😉 And if you want to know how function calls work under the hood you should take a look at the chapter Subprograms in Paul Carter’s PC Assembly Tutorial.

void __cdecl DoIt(float a, char b, char c);                             // Borland and Microsoft
void         DoIt(float a, char b, char c)  __attribute__((cdecl));     // GNU GCC
Assign an address to a Function Pointer

It’s quite easy to assign the address of a function to a function pointer. You simply take the name of a suitable and known function or member function. Although it’s optional for most compilers you should use the address operator & infront of the function’s name in order to write portable code. You may have got to use the complete name of the member function including class-name and scope-operator (::). Also you have got to ensure, that you are allowed to access the function right in scope where your assignment stands.


//assign an address to the function pointer
//     Note: Although you may ommit the address operator on most compilers
//     you should always use the correct way in order to write portable code.

// C
int DoIt  (float a, char b, char c){ printf("DoIt\n");   return a+b+c; }
int DoMore(float a, char b, char c)const{ printf("DoMore\n"); return a-b+c; }

pt2Function = DoIt;      // short form
pt2Function = &DoMore;   // correct assignment using address operator
// C++
class TMyClass
{
public:
   int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
   int DoMore(float a, char b, char c) const
         { cout << "TMyClass::DoMore" << endl; return a-b+c; };

   /* more of TMyClass */
};

pt2ConstMember = &TMyClass::DoMore; // correct assignment using address operator
pt2Member = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore
Comparing Function Pointers

You can use the comparison-operators (==, !=) the same way as usual. In the following example it is checked, whether pt2Function and pt2Member actually contain the address of the functions DoIt and TMyClass::DoMore. A text is shown in case of equality.

//  comparing function pointers

// C
if(pt2Function >0){                           // check if initialized
   if(pt2Function == &DoIt)
      printf("Pointer points to DoIt\n"); }
else
   printf("Pointer not initialized!!\n");


// C++
if(pt2ConstMember == &TMyClass::DoMore)
   cout << "Pointer points to TMyClass::DoMore" << endl;
Calling a Function using a Function Pointer

In C you call a function using a function pointer by explicitly dereferencing it using the * operator. Alternatively you may also just use the function pointer’s instead of the funtion’s name. In C++ the two operators .* resp. ->* are used together with an instance of a class in order to call one of their (non-static) member functions. If the call takes place within another member function you may use the this-pointer.

//------------------------------------------------------------------------------------
//  How to Return a Function Pointer
//     'Plus' and 'Minus' are defined above. They return a float and take two float


// Direct solution: Function takes a char and returns a pointer to a
// function which is taking two floats and returns a float. <opCode>
// specifies which function to return
float (*GetPtr1(const char opCode))(float, float)
{
   if(opCode == '+')
      return &Plus;
   else
      return &Minus; // default if invalid operator was passed
}


// Solution using a typedef: Define a pointer to a function which is taking
// two floats and returns a float
typedef float(*pt2Func)(float, float);

// Function takes a char and returns a function pointer which is defined
// with the typedef above. <opCode> specifies which function to return
pt2Func GetPtr2(const char opCode)
{
   if(opCode == '+')
      return &Plus;
   else
      return &Minus; // default if invalid operator was passed
}


// Execute example code
void Return_A_Function_Pointer()
{
   cout << endl << "Executing 'Return_A_Function_Pointer'" << endl;

   // define a function pointer and initialize it to NULL
   float (*pt2Function)(float, float) = NULL;

   pt2Function=GetPtr1('+');   // get function pointer from function 'GetPtr1'
   cout << (*pt2Function)(2, 4) << endl;   // call function using the pointer


   pt2Function=GetPtr2('-');   // get function pointer from function 'GetPtr2'
   cout << (*pt2Function)(2, 4) << endl;   // call function using the pointer
}
How to Use Arrays of Function Pointers ?

Operating with arrays of function pointers is very interesting. This offers the possibility to select a function using an index. The syntax appears difficult, which frequently leads to confusion. Below you find two ways of how to define and use an array of function pointers in C and C++. The first way uses a typedef, the second way directly defines the array. It’s up to you which way you prefer.

//------------------------------------------------------------------------------------
// 2.8 How to Use Arrays of Function Pointers

// C ---------------------------------------------------------------------------------

// type-definition: 'pt2Function' now can be used as type
typedef int (*pt2Function)(float, char, char);

// illustrate how to work with an array of function pointers
void Array_Of_Function_Pointers()
{
   printf("\nExecuting 'Array_Of_Function_Pointers'\n");

   // define arrays and ini each element to NULL, <funcArr1> and <funcArr2> are arrays
   // with 10 pointers to functions which return an int and take a float and two char

   // first way using the typedef
   pt2Function funcArr1[10] = {NULL};

   // 2nd way directly defining the array
   int (*funcArr2[10])(float, char, char) = {NULL};


   // assign the function's address - 'DoIt' and 'DoMore' are suitable functions
   // like defined above in 2.1-4
   funcArr1[0] = funcArr2[1] = &DoIt;
   funcArr1[1] = funcArr2[0] = &DoMore;

   /* more assignments */

   // calling a function using an index to address the function pointer
   printf("%d\n", funcArr1[1](12, 'a', 'b'));         //  short form
   printf("%d\n", (*funcArr1[0])(12, 'a', 'b'));      // "correct" way of calling
   printf("%d\n", (*funcArr2[1])(56, 'a', 'b'));
   printf("%d\n", (*funcArr2[0])(34, 'a', 'b'));
}


// C++ -------------------------------------------------------------------------------

// type-definition: 'pt2Member' now can be used as type
typedef int (TMyClass::*pt2Member)(float, char, char);

// illustrate how to work with an array of member function pointers
void Array_Of_Member_Function_Pointers()
{
   cout << endl << "Executing 'Array_Of_Member_Function_Pointers'" << endl;

   // define arrays and ini each element to NULL, <funcArr1> and <funcArr2> are
   // arrays with 10 pointers to member functions which return an int and take
   // a float and two char

   // first way using the typedef
   pt2Member funcArr1[10] = {NULL};

   // 2nd way of directly defining the array
   int (TMyClass::*funcArr2[10])(float, char, char) = {NULL};


   // assign the function's address - 'DoIt' and 'DoMore' are suitable member
   //  functions of class TMyClass like defined above in 2.1-4
   funcArr1[0] = funcArr2nd use an array of function pointers in C and C++.
 The first way uses a typedef, the second way directly defines the array. It's up to you which way you prefer.
[1] = &TMyClass::DoIt;
   funcArr1[1] = funcArr2[0] = &TMyClass::DoMore;
   /* more assignments */

   // calling a function using an index to address the member function pointer
   // note: an instance of TMyClass is needed to call the member functions
   TMyClass instance;
   cout << (instance.*funcArr1[1])(12, 'a', 'b') << endl;
   cout << (instance.*funcArr1[0])(12, 'a', 'b') << endl;
   cout << (instance.*funcArr2[1])(34, 'a', 'b') << endl;
   cout << (instance.*funcArr2[0])(89, 'a', 'b') << endl;
}
Advertisements

Intro to File Input/Output in C


Redirection:

One way to get input into a program or to display output from a program is to use standard input and standard output, respectively. All that means is that to read in data, we use scanf() (or a few other functions) and to write out data, we use printf().

When we need to take input from a file (instead of having the user type data at the keyboard) we can use input redirection:

% a.out < inputfile

This allows us to use the same scanf() calls we use to read from the keyboard. With input redirection, the operating system causes input to come from the file (e.g., inputfile above) instead of the keyboard.

Similarly, there is output redirection:

% a.out > outputfile

that allows us to use printf() as before, but that causes the output of the program to go to a file (e.g., outputfile above) instead of the screen.

Of course, the 2 types of redirection can be used at the same time…

% a.out < inputfile > outputfile

C File I/O:

While redirection is very useful, it is really part of the operating system (not C). In fact, C has a general mechanism for reading and writing files, which is more flexible than redirection alone.

stdio.h

 

There are types and functions in the library stdio.h that are used for file I/O. Make sure you always include that header when you use files.

Type

For files you want to read or write, you need a file pointer, e.g.:

FILE *fp;

 

What is this type "FILE *"? Realistically, you don’t need to know. Just think of it as some abstract data structure, whose details are hidden from you. In other words, the only way you can use a FILE * is via the functions that C gives you.


Note: In reality, FILE is some kind of structure that holds information about the file. We must use a FILE * because certain functions will need to change that information, i.e., we need to pass the information around by reference.


Functions

Reading from or writing to a file in C requires 3 basic steps:

  1. Open the file.
  2. Do all the reading or writing.
  3. Close the file.

Following are described the functions needed to accomplish each step.

A complete program that includes the example described below, plus an input file to use with that program

Opening a file:

In order to open a file, use the function fopen(). Use it as:

fp = fopen(filename, mode);

 

where:

  • filename is a string that holds the name of the file on disk (including a path like /cs/course if necessary).
  • mode is a string representing how you want to open the file. Most often you’ll open a file for reading ("r") or writing ("w").

Note that fopen() returns a FILE * that can then be used to access the file. When the file cannot be opened (e.g., we don’t have permission or it doesn’t exist when opening for reading), fopen() will return NULL.

  • Here are examples of opening files:

    FILE *ifp, *ofp;
    char *mode = "r";
    char outputFilename[] = "out.list";
    
    ifp = fopen("in.list", mode);
    
    if (ifp == NULL) {
      fprintf(stderr, "Can't open input file in.list!\n");
      exit(1);
    }
    
    ofp = fopen(outputFilename, "w");
    
    if (ofp == NULL) {
      fprintf(stderr, "Can't open output file %s!\n",
              outputFilename);
      exit(1);
    }
  • Note that the input file that we are opening for reading ("r") must already exist. In contrast, the output file we are opening for writing ("w") does not have to exist. If it doesn’t, it will be created. If this output file does already exist, its previous contents will be thrown away (and will be lost).


    Note: There are other modes you can use when opening a file, such as append ("a") to append something to the end of a file without losing its contents…or modes that allow you to both read and write. You can look up these other modes in a good C reference on stdio.h.


  • Reading from or writing to a file:

    Once a file has been successfully opened, you can read from it using fscanf() or write to it using fprintf(). These functions work just like scanf() and printf(), except they require an extra first parameter, a FILE * for the file to be read/written.


    Note: There are other functions in stdio.h that can be used to read or write files. Look them up in a good C reference.


    Continuing our example from above, suppose the input file consists of lines with a username and an integer test score, e.g.:

    in.list
    ------
    foo 70
    bar 98
    ...

    and that each username is no more than 8 characters long.

    We might use the files we opened above by copying each username and score from the input file to the output file. In the process, we’ll increase each score by 10 points for the output file:

    char username[9];  /* One extra for nul char. */
    int score;
    
    ...
    
    while (fscanf(ifp, "%s %d", username, &score) != EOF) {
      fprintf(ofp, "%s %d\n", username, score+10);
    }
    
    ...

     

    The function fscanf(), like scanf(), normally returns the number of values it was able to read in. However, when it hits the end of the file, it returns the special value EOF. So, testing the return value against EOF is one way to stop the loop.

    The bad thing about testing against EOF is that if the file is not in the right format (e.g., a letter is found when a number is expected):

    in.list
    ------
    foo 70
    bar 98
    biz A+
    ...

    then fscanf() will not be able to read that line (since there is no integer to read) and it won’t advance to the next line in the file. For this error, fscanf() will not return EOF (it’s not at the end of the file)….

    Errors like that will at least mess up how the rest of the file is read. In some cases, they will cause an infinite loop.

    One solution is to test against the number of values we expect to be read by fscanf() each time. Since our format is "%s %d", we expect it to read in 2 values, so our condition could be:

    while (fscanf(ifp, "%s %d", username, &score) == 2) {
      ...

    Now, if we get 2 values, the loop continues. If we don’t get 2 values, either because we are at the end of the file or some other problem occurred (e.g., it sees a letter when it is trying to read in a number with %d), then the loop will end.

    Another way to test for end of file is with the library function feof(). It just takes a file pointer and returns a true/false value based on whether we are at the end of the file.

    To use it in the above example, you would do:

    while (!feof(ifp)) {
      if (fscanf(ifp, "%s %d", username, &score) != 2)
        break;
      fprintf(ofp, "%s %d", username, score+10);
    }

    Note that, like testing != EOF, it might cause an infinite loop if the format of the input file was not as expected. However, we can add code to make sure it reads in 2 values (as we’ve done above).


    Note: When you use fscanf(...) != EOF or feof(...), they will not detect the end of the file until they try to read past it. In other words, they won’t report end-of-file on the last valid read, only on the one after it.

    Closing a file:

    When done with a file, it must be closed using the function fclose().

    To finish our example, we’d want to close our input and output files:

    fclose(ifp);

    fclose(ofp);

    Closing a file is very important, especially with output files. The reason is that output is often buffered. This means that when you tell C to write something out, e.g.,

    fprintf(ofp, "Whatever!\n");

     

    it doesn’t necessary get written to disk right away, but may end up in a buffer in memory. This output buffer would hold the text temporarily:

    Sample output buffer:
    ----------------------------------------------
    | a | b  | c | W | h | a | t | e | v | e | r |
    ----------------------------------------------
    | ! | \n |   |   |   |   |   |   |   |   |   |
    ----------------------------------------------
    |   |    |   |   |   |   |   |   |   |   |   |
    ----------------------------------------------
    |   |    |   |   |   |   |   |   |   |   |   |
    ----------------------------------------------
    ...
  • The buffer is really just 1-dimensional despite this drawing.)

    When the buffer fills up (or when the file is closed), the data is finally written to disk.

    So, if you forget to close an output file then whatever is still in the buffer may not be written out.


    Note: There are other kinds of buffering than the one we describe here.


  • Special file pointers:

    There are 3 special FILE *‘s that are always defined for a program. They are stdin (standard input), stdout (standard output) and stderr (standard error).

    Standard Input

    Standard input is where things come from when you use scanf(). In other words,

    scanf("%d", &val);

    is equivalent to the following fscanf():

    fscanf(stdin, "%d", &val);
    Standard Output

    Similarly, standard output is exactly where things go when you use printf(). In other words,

    printf("Value = %d\n", val); 

    is equivalent to the following fprintf();

    fprintf(stdout, "Value = %d\n", val);

    Remember that standard input is normally associated with the keyboard and standard output with the screen, unless redirection is used.

    Standard Error

    Standard error is where you should display error messages. We’ve already done that above:

    fprintf(stderr, "Can't open input file in.list!\n");
  • Standard error is normally associated with the same place as standard output; however, redirecting standard output does not redirect standard error.

    For example,

    % a.out > outfile

    only redirects stuff going to standard output to the file outfile… anything written to standard error goes to the screen.

    Using the Special File Pointers

    We’ve already seen that stderr is useful for printing error messages, but you may be asking, "When would I ever use the special file pointers stdin and stdout?" Well, suppose you create a function that writes a bunch of data to an opened file that is specified as a parameter:

    void WriteData(FILE *fp)
    {
      fprintf(fp, "data1\n");
      fprintf(fp, "data2\n");
      ...
    }

    Certainly, you can use it to write the data to an output file (like the one above):

    WriteData(ofp);

    But, you can also write the data to standard output:

    WriteData(stdout);

    Without the special file pointer stdout, you’d have to write a second version of WriteData() that wrote stuff to standard output.

    C Pointer


    C pointer is a memory address. When you define a variable for example :

    int x = 10;

    You specify variable name (x), its data type (integer in this example) and its value is 10. The variable x resides in memory with a specified memory address. To get the memory address of variable x, you use operator & before it. This code snippet print memory address of x

    printf("memory address of x is %d\n",&x);

    and in my PC the output is

    memory address of x is 1310588

    Now you want to access memory address of variable x you have to use pointer. After that you can access and modify the content of memory address which pointer point to. In this case the memory address of x is 1310588 and its content is 10. To declare pointer you use asterisk notation (*) after pointer’s data type and before pointer name as follows:

     

    int *px;

    Now if you want pointer px to points to memory address of variable x, you can use address-of operator (&) as follows:

    int *px = &x;

    After that you can change the content of variable x for example you can increase, decrease x value :

    *px += 10;
    printf("value of x is %d\n",x);
    *px -= 5;
    printf("value of x is %d\n",x);

    and the output indicates that x variable has been change via pointer px.

    value of x is 20
    value of x is 15

    It is noted that the operator (*) is used to dereference and return content of memory address.

    In some programming contexts, you need a pointer which you can only change memory address of it but value or change the value of it but memory address. In this cases, you can use const keyword to define a pointer points to a constant integer or a constant pointer points to an integer as follows:

    int c = 10;
    int c2 = 20;
    
    /* define a pointer and points to an constant integer.
    pc can point to another integer but you cannot change the 
    content of it */
    
    const int *pc = &c;
    
    /* pc++; */ /* cause error */
    
    printf("value of pc is %d\n",pc);
    
    pc = &c2;
    
    printf("value of pc is %d\n",pc);
    
    /* define a constant pointer and points to an integer. 
    py only can point to y and its memory address cannot be changed
    you can change its content */
    
    int y = 10;
    int y2 = 20;
    
    int const *py = &y;
    
    *py++;/* it is ok */
    printf("value of y is %d\n",y);
    
    /* py = &y2; */ /* cause error */

    Here is the output for code snippet

    value of pc is 1310580
    value of pc is 1310576
    value of y is 10