Function pointers and callbacks in c/c++ - c

I was trying to remind how pointers worked in c and c++ and I found this very interesting video (Pointers in C/C++). In minute 3:14:00, he begins to talk about pointer functions and callbacks, and I ended a bit confused about the real application of them.
The example case he provides consists of a sorting algorithm that takes a function pointer as argument, which defines the comparison "rule" to follow (order from geater to smaller, order from smaller to greater, from greater to smaller given the absolute values...). He eventually ends with something like this:
#include<stdio.h>
int compare(int a, int b){
if(a > b) return -1;
return 1;
}
void MyBubbleSort(int A[], int n, int (*compare)(int,int)){
int i,j,temp;
for(i=0; i<n; i++){
for(j=0; j<n-1; j++){
if(compare(A[j], A[j+1]) > 0{
temp = A[j];
A[j] = A[j+1];
A[j+1] = temp;
}
}
}
}
int main(){
int i, A[] = {3,2,1,5,6,4};
MyBubbleSort(A,6,compare);
for(i=0; i<6; i++) printf("%d ",A[i]);
}
When he wants to change the comparison rule, he changes the compare(int, int) content and that's all. My question is, why would he do that, instead of just having a separate function called compare(int, int) that just does the same as the one showed in the code snippet, and just call that function from within MyBubbleSort(int[], int). Wouldn't it just have the same behaviour? What are the benefits then? Are there any other interesting use cases?
Thank you very much for answers!

If I understand your question correctly, the main point is something that he mentions in the narration but does not include in the sample code: you could have several different comparison functions in your program, and use them at different times as appropriate, while still having just one MyBubbleSort function.
An example might look like:
int compare_increasing(int a, int b){
if(a > b) return -1;
return 1;
}
int compare_decreasing(int a, int b){
if(a < b) return -1;
return 1;
}
void MyBubbleSort(int A[], int n, int (*compare)(int,int));
}
int main(){
// ...
// sort in increasing order
MyBubbleSort(A,6,compare_increasing);
// sort in decreasing order
MyBubbleSort(A,6,compare_decreasing);
}

Calling a function by a pointer in this case makes the sorting function universal.
If you hardcode the comparison in that function it will work only for that condition.
C does not have lambda expressions and anonymous functions so the compare function has to be written separately and the pointer passed.

Related

How to pass each value of an array as parameters to a function?

I have the following function that accepts a varying number of integer parameters and returns the sum.
int sum(int a, ...){
va_list nums;
va_start(nums, a);
int res=0;
for(int i=0; i<a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
I need to pass each value of the array as a parameter to the function rather than passing the array itself. The array can be of varying length leading to a varying length of arguments to pass too.
printf("The sum is: %d", sum(size, args[0], args[1], ```need all elements of args[] array here```));
To put forth some perspective, I'm using this sum function to understand how I can go about doing this. It would be helpful to know how to achieve this in a more general setting rather than this exact function.
Please let me know if you need any more information.
Please do look at this question, which is similar, however, I require a solution in C.
The short answer is that there's no way to do exactly this in the C language. There is no ES6-like spread operator in C, nor similar functionality. I don't think there's any particular reason why they couldn't (you would just have to push more arguments onto the stack); they just never made one.
However, there are various other things you can do:
If variadic arguments were already passed into the function calling your function, you can pass along the va_list to a function declared to take a va_list. See Passing variable arguments to another function that accepts a variable argument list
As #JonathanLeffer suggests, the most natural way to write this code in C is by constructing an array of what "would be" your variadic arguments, and passing that into a function that expects an array (well, technically, a pointer, because arrays decay to pointers). For example:
int sum_array(int a, int nums[]){
int res=0;
for(int i=0; i<a; i++) {
res += nums[i];
}
return res;
}
In certain circumstances, it may be more convenient for a function like sum_array to take only the nums array/pointer, which would itself indicate the end of the array with a 0 or -1 value in the last slot. This is just another convention for indicating the end, which the caller has to set up.
You could then, if you really wanted to, write a variadic function that collects its arguments into an array and calls sum_array, if you want a variadic version as well. (Of course, you could also just implement the variadic and array versions separately, but for nontrivial functions it may be a pain to implement them twice.)
int sum_variadic(int a, ...){
va_list nums;
va_start(nums, a);
int arr[a];
for(int i=0; i<a; i++) {
arr[i] = va_arg(nums, int);
}
va_end(nums);
return sum_array(a, arr);
}
you could also use a variadic macro for the same purpose:
#define sum_macro(size, ...) sum_array(size, (int[]){__VA_ARGS__})
In summary: going from variadic to array in C is trivial, going from array to variadic is impossible.
You can also use extensions to the C language to do it anyway, as described in Passing a dynamic set of variadic arguments to a C function and In C, given a variable list of arguments, how to build a function call using them?, which #KamilCuk linked to.
You can avoid passing the number of arguments explicitly by using a variadic macro that constructs a compound literal array instead of a vararg function:
#include <stdio.h>
#define sum_int(...) (sum_int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int), (int[]){__VA_ARGS__})
int (sum_int)(size_t count, const int *a) {
int sum = 0;
for (size_t i = 0; i < count; i++) {
sum += a[i];
}
return sum;
}
int main() {
printf("sum = %d\n", sum_int(1, 2, 3));
return 0;
}
This approach can be used for any purpose, as long as the types of the variable arguments are converted implicitly to the array type.
If you want to pass just the arguments to your sum function without changing its definition, you can use a variation of the macro:
#include <stdio.h>
int sum(int a, ...) {
va_list nums;
va_start(nums, a);
int res = 0;
for (int i = 0; i < a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
#define sum(...) (sum)((int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int)), __VA_ARGS__)
int main() {
printf("sum = %d\n", sum(1, 2, 3));
return 0;
}
Note however that there is no type checking with this approach and sum(1, 2.0, 3) would have undefined behavior.

Finding the maximum of an array recursively

I am learning recursion. As an exercise I am trying to find the maximum of an array recursively.
int recursive (int *arr, int n, int largest) {
if(n==0)
return largest;
else {
if (*(arr+n)>largest) {
largest = *(arr+n);
recursive(arr, n-1, largest);
}
}
}
int main() {
int length = n-1;
int largest = v[0];
int z = recursive(arr, length, largest);
printf("\n%d", z);
}
I followed your suggestions, using pointers instead of arrays, and probably the program looks way better. But still it is not doing it's not showing the maximum correctly. I think the logic is correct.
First thing pay attention to compiler warnings, your recursive function doesn't return value when you enter the else part.
Now the second thing is please don't use things like *(arr+n) which is hard to read instead use arr[n], also while just a preference when using arrays as function arguments use int arr[] to call the function instead of int *arr (in the first version it's clear you should pass an array).
Third thing is to name your things instead of int recursive describe what the function is doing for example int maxElemRecursive
So your recursive function should be something like
int maxElemRecursive(int arr[],int n,int largest)
{
if(n==0) return largest;
if(arr[n] > largest) // No need for else because return largest; would've returned value;
{
largest = arr[n];
}
return maxElemRecursive(arr,n-1,largest); // You have to return the value of the function.
// You still pass the array with just arr.
}
In C usually you can't declare an array whose size is unknown at compile-time, hence int v[n] is dangerous code.
Depending on your compiler and the compiler's settings this could be a compile error or it could be a bug.
For such problems you need to learn about pointers and dynamic memory allocation.
Side-note: After C99 there are stuff like Variable Length Arrays but the rules are a little advanced.
Also to pass an array to a function you give the array a pointer as an argument:
int z = recursion(v, n, v[0]);
instead of:
int z = recursion(v[n], n, v[0]);

Sort three pointers without using selection sort

I'm new to C and am having a lot of trouble understanding how to utilize pointers in my code. I need to sort the addresses of three user-input integers in ascending order, using a separate sort function. I can't include any sort of selection sort or general-purpose sort, however.
EDIT: When I run the program, it gives me the addresses in descending order for some reason. I need to fix that.
Here's my code thus far:
#include <stdio.h>
#include <stdlib.h>
void sortThree(int * a, int * b, int * c);
int main(void)
{
int x, y, z;
printf("Please enter three variables: ");
scanf("%i %i %i",&x,&y,&z);
void sortThree(int * x, int * y, int * z);
printf("%u %u %u",&x, &y, &z);
return 0;
}
void sortThree(int * a, int * b, int * c)
{
int min, mid, max;
if (*a <= *b)
{
if (*a <= *c)
{
min = *a;
}
if (*b <= *c)
{
mid = *b;
max = *c;
}
else
{
mid = *c;
max = *b;
}
}
}
I'm sure it's something I'm overlooking or something but my brain just doesn't see it. Thanks in advance!
There are so many errors in this code it is hard to comment without re-writing it for you, and I won't. In addition to those mentioned above, you are using printf() to show integers by address instead of by value. You can't want to sort the addresses, or you would not have bothered to input any values. Also, why do you switch the format specifier bewteen int and unsigned int? It might not cause an error but it's plain sloppy.
In the sort function, you aren't even changing anything, you are throwing away the results on return. The reason it has given you the addresses in descending order, is because you haven't even sorted them, they are the order they were declared and pushed onto the stack. You are passing the pointers to printf() but telling it they are unsigned integers. The actual variable values are ignored.

Pass arrays to function

Apologies for this re-post as I do not know how to phrase my question as it is my first time using stack overflow. I hope someone could help me out in this quiz for my studies.
I had research on this program but I do not know if it relates to the quiz question on arraySize.
Question is below:
we pass array ai to function fillArray. What exactly is passed to the function? The answer is a single memory address, not the 10 integers! This is why we can use the function to fill the array ai with 10 numbers.
Complete the above function fillArray so that it reads arraySize number of integers from the user and fill the array with those numbers.
Write a driver program to test the function with integer arrays of different sizes.
Note the formal parameter int array[] in function fillArray can be changed to int *array. Verify this by modifying and testing your code.
My code is below:
#include <stdio.h>
#define MAX 10
int fillArray(int array[], int arraySize);
void print_intaray(int array[], int arraySize);
main()
{
int ai, exam_scores[MAX];
printf("***List of Array***\n\n");
ai = fillArray(exam_scores, MAX);
print_intaray(exam_scores, ai);
}
int fillArray(int array[], int arraySize)
{
int ai, count = 0;
printf("Type array, EOF to quit\n");
while ((count < arraySize) && (scanf("%d", &ai) !=EOF))
{
array[count] = ai;
count++;
}
return count;
}
void print_intaray(int array [], int arraySize)
{
int i;
printf("\n***Your Arrary***\n\n");
for (i = 0; i<arraySize; i++)
printf("%d\n", array[i]);
}
I'm new to programming and I hope my question could somehow be resolve.
Thanks for viewing :)
Assuming the question is "Why are int array[] and int *array equivalent in the function argument":
I'm not much of a C expert, but AFAIK arrays (in C) are largely just pointers to which you append a certain offset. Telling C you expect an int myarray[] means pretty much the same as expecting a pointer to an integer (int *array). If you increment the pointer, you can access the next element in the array. This is also known as pointer arithmetic.
The C compiler translates array syntax like foo[3] in the background to something like *(*foo+3), but you can also do that yourself by just dealing with the pointers.

Passing pointers to an array as arguments to a function

I am trying to implement INSERTION SORT here in C, which I think I've done successfully. However, I am having problems in passing arrays as arguments.
I want in place sorting, which means that the original array passed into the insertion_sort function should contain the elements in the sorted array itself.
#include<stdio.h>
int * insertion_sort(int *a,int length)
{
int j;
for(j=1;j<length;j++)
{
int i,key=a[j];
for(i=j-1;j>=0;j--)
{
if(a[i]<=key)
break;
a[i+1]=a[i];
}
a[i+1]=key;
}
return *a;
}
int main(void)
{
int a[]={10,12,7,6,9,8};
insertion_sort(a,6);
int i;
for(i=0; i<6; i++)
printf("%d\n", a[i]);
return 0;
}
EDIT
Nothing gets printed in the output screen.
Help me find the bug here. Thanks !!
1.You probably meant to use i in the inner loop:
Change:
for(i=j-1;j>=0;j--)
^^ ^^
to:
for(i=j-1;i>=0;i--)
2.You don't have to return anything as the original array gets modified (which is just as well since you ignore the returned value).
3.Array index starts from 0. Change outer loop to: for(j=0;j<length;j++)

Resources