Pages

Friday, November 30, 2018

Programming in C: Few Tidbits #8

1) Function Pointers

Declaring Function Pointers

Similar to a variable declared as pointer to some data type, a variable can also be declared to be a pointer to a function. Such a variable stores the address of a function that can later be called using that function pointer. In other words, function pointers point to the executable code rather than data like typical pointers.

eg.,
void (*func_ptr)();

In the above declaration, func_ptr is a variable that can point to a function that takes no arguments and returns nothing (void).

The parentheses around the function pointer cannot be removed. Doing so makes the declaration a function that returns a void pointer.

The declaration itself won't point to anything so a value has to be assigned to the function pointer which is typically the address of the target function to be executed.


Assigning Function Pointers

If a function by name dummy was already defined, the following assignment makes func_ptr variable to point to the function dummy.

eg.,
void dummy() { ; }
func_ptr = dummy;

In the above example, function's name was used to assign that function's address to the function pointer. Using address-of / address operator (&) is another way.

eg.,
void dummy() { ; }
func_ptr = &dummy;

Above two sample assignments highlight the fact that similar to arrays, a function's address can be obtained either by using address operator (&) or by simply specifying the function name - hence the use of address operator is optional. Here's an example proving that.

% cat funcaddr.c

#include <stdio.h>

void foo() { ; }

void main()
{
        printf("Address of function foo without using & operator = %p\n", foo);
        printf("Address of function foo         using & operator = %p\n", &foo);
}

% cc -o funcaddr funcaddr.c

% ./funcaddr
Address of function foo without using & operator = 10b6c
Address of function foo         using & operator = 10b6c

Using Function Pointers

Once we have a function pointer variable pointing to a function, we can call the function that it points to using that function pointer variable as if it is the actual function name. Dereferencing the function pointer is optional similar to using & operator during function pointer assignment. The dereferencing happens automatically if not done explicitly.

eg.,

The following two function calls are equivalent, and exhibit the same behavior.

func_ptr();
(*func_ptr)();

Complete Example

Here is one final example for the sake of completeness. This example demonstrate the execution of couple of arithmetic functions using function pointers. Same example also highlights the optional use of & operator and pointer dereferencing.

% cat funcptr.c
#include <stdio.h>

int add(int first, int second) {
        return (first + second);
}

int multiply(int first, int second) {
        return (first * second);
}

void main()
{
        int (*func_ptr)(int, int);                      /* declaration */
        func_ptr = add;                                 /* assignment (auto func address) */
        printf("100+200 = %d\n", (*func_ptr)(100,200)); /* execution  (dereferencing) */
        func_ptr = &multiply;                           /* assignment (func address using &) */
        printf("100*200 = %d\n", func_ptr(100,200));    /* execution  (auto dereferencing) */
}

% cc -o funcptr funcptr.c

% ./funcptr
100+200 = 300
100*200 = 20000

Few Practical Uses of Function Pointers

Function pointers are convenient and useful while writing functions that sort data. Standard C Library includes qsort() function to sort data of any type (integers, floats, strings). The last argument to qsort() is a function pointer pointing to the comparison function.

Function pointers are useful to write callback functions where a function (executable code) is passed as an argument to another function that is expected to execute the argument (call back the function sent as argument) at some point.

In both examples above function pointers are used to pass functions as arguments to other functions.

In some cases function pointers may make the code cleaner and readable. For example, array of function pointers may simplify a large switch statement.

2) Printing Unicode Characters

Here's one possible way.

  • Make use of wide characters. Wide character strings can represent Unicode character value (code point).
  • The standard C library provides wide-character functions. Include the header file wchar.h
  • Set proper locale to support wide characters
  • Print the wide character(s) using standard printf and "%ls" format specifier -or- using wprintf to output formatted wide characters

Following rudimentary code sample prints random currency symbols and a name in Telugu script using both printf and wprintf function calls.

% cat -n unicode.c
     1  #include <wchar.h>
     2  #include <locale.h>
     3  #include <stdio.h>
     4
     5  int main()
     6  {
     7          setlocale(LC_ALL,"en_US.UTF-8");
     8          wprintf(L"\u20AC\t\u00A5\t\u00A3\t\u00A2\t\u20A3\t\u20A4");
     9          wchar_t wide[4]={ 0x0C38, 0x0C30, 0x0C33, 0 };
    10          printf("\n%ls", wide);
    11          wprintf(L"\n%ls", wide);
    12          return 0;
    13  }

% cc -o unicode unicode.c

% ./unicode
€      ¥      £      ¢      ₣      ₤
సరళ
సరళ

Here is one website where numerical values for various Unicode characters can be found.

No comments:

Post a Comment