C Typecasting, Void Pointers, Function Pointers

C Typecasting, Void Pointers, and Function Pointers

This code demonstrates typecasting, void pointers, and function pointers in C.

Typecasting


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void typecasts()
{
    int i = 107;
    float f = 3.14159;
    int *iptr = &i;
    float *fptr = &f;

    printf("No cast, correct deref: int = %d, float = %f\n", *iptr, *fptr);
    printf("Wrong cast: deref int as float = %f, float as int = %d\n", *(float *)iptr, *(int *)fptr);
    printf("Wrong cast: deref int as string = '%s', float as string = '%s' \n\n", (char *)iptr, (char *)fptr);
}

The typecasts function shows the effects of correct and incorrect typecasting when dereferencing pointers. Casting a pointer to a different type and then dereferencing it can lead to unexpected results, as the underlying data is interpreted differently.

Generic Count Functions

The following functions count occurrences of a key in arrays of different types:

  • count_int: Counts integers.
  • count_float: Counts floats.
  • count_char: Counts characters.
  • count_string: Counts strings (char*).

int count_int(int arr[], int n, int key)
{
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (arr[i] == key) count++;
    }
    return count;
}

int count_float(float arr[], int n, float key)
{
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (arr[i] == key) count++;
    }
    return count;
}

int count_char(char arr[], int n, char key)
{
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (arr[i] == key) count++;
    }
    return count;
}

int count_string(char *arr[], int n, char *key)
{
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (strcmp(arr[i],key)==0) count++;
    }
    return count;
}

A generic gcount function is introduced to handle different data types using void*:


int gcount(void *arr, int n, size_t elemsz, void *key)
{
    int count = 0;
    for (int i = 0; i < n; i++) {
        void *ith = (char *)arr + i*elemsz;  // Cast to char* for pointer arithmetic
        if (memcmp(ith, key, elemsz) == 0) count++;
    }
    return count;
}

gcount uses void* to accept any type of array. It calculates the address of each element using pointer arithmetic (casting to char* is essential for correct byte-level manipulation) and compares elements using memcmp.

Testing Count Functions


void test_contains(int nwords, char *words[])
{
    int scores[] = {88, 94, 70, 92, 83, 92, 1, 92};
    int nscores = sizeof(scores)/sizeof(scores[0]);
    int score_key = 92;

    float prices[5] = {3.99, 195, 181.50};
    int nprices = sizeof(prices)/sizeof(prices[0]);
    float float_key = 3.5f; //Added f to make it a float literal

    char letters[] = "CS107 rocks my world!";
    int nletters = strlen(letters);
    int letter_key = 'o';

    char *word_key = words[0];

    printf("Count %d = %d\n", score_key, count_int(scores, nscores, score_key));
    printf("Count %d = %d\n", score_key, gcount(scores, nscores, sizeof(scores[0]), &score_key));
    printf("Count %g = %d\n", float_key, count_float(prices, nprices, float_key));
    printf("Count %c = %d\n", letter_key, count_char(letters, nletters, letter_key));
    printf("Count %s = %d\n", word_key, count_string(words, nwords, word_key));
}

test_contains demonstrates both the type-specific count functions and the generic gcount function.

Function Pointers and qsort


int cmp_int(const void *a, const void *b)
{
    int one = *(int *)a, two = *(int *)b;
    if (one < two) return -1;
    if (one > two) return 1;
    return 0;
}

void test_fnptr(int argc, char *argv[])
{
    int nums[] = {40, 19, 23, 45, 12, 45, 23, 99, 53, 12, 78};
    int count = sizeof(nums)/sizeof(nums[0]);

    qsort(nums, count, sizeof(nums[0]), cmp_int);
    printf("\nArray of numbers: ");
    for (int i = 0; i < count; i++) {
        printf("%d ", nums[i]);
    }
    printf("\n");

    printf("\nArray of strings: ");
    for (int i = 0; i < argc; i++) {
        printf("%s ", argv[i]);
    }
    printf("\n");
}

cmp_int is a comparison function suitable for use with qsort. It takes two const void* arguments, casts them to int*, and compares the underlying integer values. test_fnptr demonstrates using qsort to sort an array of integers and prints the sorted array. It also prints the command-line arguments.

Main Function


int main(int argc, char *argv[])
{
    typecasts();
    test_contains(argc-1, argv+1);
    test_fnptr(argc-1, argv+1);
    return 0;
}

The main function calls the demonstration functions.