Generic minimum function using function pointers in C - c

I am trying to write a generic C function, that returns minimum of an array using function pointers.
The code is :
#include <stdio.h>
int min_index(void *arr, int size, int (*compare)(void *, void *))
{
int i;
int min = 0;
for (i = 1; i < size; i++)
{
if (((*compare)(&arr[i], &arr[min])) < 0)
min = i;
}
return min;
}
int comp_int(int *arr1, int *arr2)
{
if (*arr1 < *arr2)
return -1;
else
return 1;
}
int comp_char(char *arr1, char *arr2)
{
if (*arr1 < *arr2)
return -1;
else
return 1;
}
int main()
{
int arr1[5] = {45, 56, 34, 23, 19};
int index = min_index(arr1, 5, comp_int); // calling min_index with integer array
printf("Minimum value in the array is %d\n", arr1[index]);
char arr2[5] = {'a', 'b', 'c', 'd', 'e'};
int index2 = min_index(arr2, 5, comp_char); // calling min_index with char array
printf("Minimum value in the array is %c\n", arr2[index2]);
return 0;
}
This code worked for only char arrays. It did not work for int arrays.
I debugged the code. I found that, when I call min_index function with the integer array, only first value of arr is correct number, but remaining are some garbage values.
But, when I call min_index function with character array, all the values are correct. There are no garbage values in this case. I got correct output.
Question : Why does the code work for char arrays not for int arrays ?

It doesn't work because you need to cast the array itself on the original type and then access by index. Because C does not have template or a type check you will need to access the min_of() like functions by the size and the sign to get the correct conversion and sorting.
#include <stdio.h>
#define INVALID_VAL_TYPE (int)(~0)
int new_umin_index(void * arr, int arr_len, int vsize){
int i, index = 0;
switch (vsize) {
case sizeof(unsigned char):
for (i = 0; i < arr_len; i++) {
if ( ((unsigned char *)arr)[i] < ((unsigned char *)arr)[index] ){
index = i;
}
}
break;
case sizeof(unsigned):
for (i = 0; i < arr_len; i++) {
if ( ((unsigned *)arr)[i] < ((unsigned *)arr)[index] ){
index = i;
}
}
break;
default:
index = INVALID_VAL_TYPE;
break;
}
return index;
}
int new_imin_index(void * arr, int arr_len, int vsize){
int i, index = 0;
switch (vsize) {
case sizeof(signed char):
for (i = 0; i < arr_len; i++) {
if ( ((signed char *)arr)[i] < ((signed char *)arr)[index] ){
index = i;
}
}
break;
case sizeof(int):
for (i = 0; i < arr_len; i++) {
if ( ((int *)arr)[i] < ((int *)arr)[index] ){
index = i;
}
}
break;
default:
index = INVALID_VAL_TYPE;
break;
}
return index;
}
int main(void) {
int arr1[5] = {45, 56, 34, 23, 19};
int i_min_index = new_imin_index(&arr1, 5, sizeof(int));
printf("Minimum value in array<int> is %i \n", arr1[i_min_index]);
char arr2[5] = {'b', 'a', 'c', 'd', 'e'};
int c_min_index = new_umin_index(&arr2, 5, sizeof(char));
printf("Minimum value in array<char> is %c \n", arr2[c_min_index]);
return 0;
}

I came up with a solution, based on the comments of several users. This time I enabled all the warnings, and took care of every warning. The code is :
#include <stdio.h>
void* minimum(void *arr, int arr_count, size_t size, int (*compare)(const void *, const void *))
{
void* pmin = arr;
for(int i=1; i<arr_count; i++)
{
void* value = (char*)arr + i*size; // size is the sizeof the type.
if(((*compare)(value, pmin))<0)
pmin = value;
}
return pmin;
}
int compare_ints(const void* a, const void* b)
{
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;
if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;
}
int compare_chars(const void* a, const void* b)
{
char arg1 = *(const char*)a;
char arg2 = *(const char*)b;
if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;
}
int main()
{
int arr1[5] = {45, 56, 34, 23, 19};
int *pmin = minimum(arr1, 5,4, compare_ints); // In my system sizeof(int) is 4
printf("Minimum value in the array is %d\n", *pmin);
char arr2[5] = {'a', 'b', 'c', 'd', 'e'};
char* pmin2 = minimum(arr2, 5,1, compare_chars); // sizeof(char) is 1
printf("Minimum value in the array is %c\n",*pmin2 );
return 0;
}
The output is (without any warnings) :
Minimum value in the array is 19
Minimum value in the array is a

Related

Split array into dynamic array and return ptr

I have a problem. I have to divide array into dynamic array and return pointer with parameter.
When I try to run this code, I get (interrupted by signal 11: SIGSEGV) this message. I think it is something with my pointers. But I don't even get any warnings, I don't know where to look else.
#include <stdio.h>
#include <stdlib.h>
int splitData(int data[], int size, int splitPlace, int **firstArray);
int main() {
int data[6] = {1, 2, 3, 4, 5, 6};
int size = 6;
int *ptr = NULL;
int n = splitData(data, size, 3, &ptr);
printf("%d", n);
for(int i = 0; i < 3; ++i)
{
printf("[%d]", ptr[i]);
}
return 0;
}
int splitData(int data[], int size, int splitPlace, int **firstArray)
{
*firstArray = (int *)malloc(splitPlace * sizeof(int));
for(int i = 0; i < splitPlace; ++i)
{
*firstArray[i] = data[i];
}
return 0;
}
You have the precedence wrong with *firstArray[i]. You need (*firstArray)[i].
Clearer might be to allocate
int *new_array = malloc(...);
*firstArray = new_array.
Then use new_array in your loop body.

void pointer array parameter passing

i am trying to pass an int array as argument of a function who receives a void * array
The function is:
void foo(void *A[], unsigned int array_length)
{
for (unsigned int i = 0; i < array_length; i++) {
printf("%d ", (u32)(long)A[i]);
}
}
Then i call like this:
int A[5] = {11, 12, 13, 14, 11};
foo((void *)A, 5);
but the printed array is: 11 13 11 -2015754187 -274447056 and i dont understand why this numbers are printed.
Reading between the lines, Question 4.13: What's the total generic pointer type? in the C FAQ seems tangentially related:
There is no "total generic pointer type.".
The declaration void *A[] indicates that the function is expecting a list of void pointers, not a generic pointer to data elements. The kind of interface you seem to be seeking to implement can be found in the standard qsort function.
void qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *, const void *));
Note base points to the first element of the array to be sorted. Note also that the second and third arguments are essential for qsort to be able to to different elements of the array when invoking the comparison function compar. We assume compar knows what data type its arguments are supposed to be pointing to.
I recommend studying both the prototype of qsort and compar so that you can better frame the design you are after.
While the example below probably does not correspond directly to what you are trying to do, it should be decent starting point for brainstorming:
#include <stdio.h>
#include <stdlib.h>
enum item_type {
INTARR,
INTARRLIST,
DOUBLEARR,
DOUBLEARRLIST,
};
struct item;
struct item {
enum item_type type;
size_t nelem;
void *item;
};
void
print_int_arr(const int *x, size_t nelem)
{
for (size_t i = 0; i < nelem; ++i)
{
printf("%d\n", x[i]);
}
}
void
print_int_arr_list(const struct item *x[], size_t nelem)
{
for (size_t i = 0; i < nelem; ++i)
{
const struct item *y = x[i];
print_int_arr(y->item, y->nelem);
}
}
void
print_item(struct item *x)
{
switch(x->type)
{
case INTARR:
print_int_arr(x->item, x->nelem);
break;
case INTARRLIST:
print_int_arr_list(x->item, x->nelem);
break;
default:
fprintf(stderr, "Unknown item type '%d'\n", x->type);
exit(EXIT_FAILURE);
}
}
int
main(void)
{
int x[] = {1, 3, 5, 7, 9};
struct item a = { INTARR, 5, x };
struct item b = { INTARR, 3, x };
struct item c = { INTARR, 1, x };
struct item *d[] = { &a, &b, &c };
struct item e = { INTARRLIST, 3, d };
print_item(&a);
print_item(&e);
return EXIT_SUCCESS;
}
Actually i need to be able to receive an array of any type because my intention is not to print them but to enqueue them in a queue.
What your foo function lacking is determining the type of data that should be passed as an argument, without it we cannot extract values properly from void*
Below is one of the ways to achieve what you are asking. Here I am passing the type of data and manipulating.
NOTE: This is not a generic function, it is just made to to handle some known types.
you can add more types (pointers and structs etc.) and experiment.
I am printing the data just to be sure we are extracting what we passed, but you can use them as per your need.
#include <stdio.h>
typedef enum { CHAR = 0, INT, FLOAT, STRING} DataType;
const char* getType(DataType t)
{
if(t == CHAR)
return "CHAR";
else if(t == INT)
return "INT";
else if(t == FLOAT)
return "FLOAT";
else
return "STRING";
}
void foo(void *A, unsigned int array_length, DataType type )
{
printf("type is %s and len = %d\n", getType(type), array_length);
switch(type)
{
case CHAR:
{
char *list = (char *) A;
for (unsigned int i = 0; i < array_length; i++) {
printf("%c ", list[i]);
}
}
break;
case INT:
{
int *list = (int *) A;
for (unsigned int i = 0; i < array_length; i++) {
printf("%d ", list[i]);
}
}
break;
case FLOAT:
{
float *list = (float *) A;
for (unsigned int i = 0; i < array_length; i++) {
printf("%.2f ", list[i]);
}
}
break;
case STRING:
{
char**list = (char**) A;
for (unsigned int i = 0; i < array_length; i++) {
printf("%s ", list[i]);
}
}
break;
default:
printf("Invalid type");
break;
}
putchar('\n');
}
int main()
{
int arr_int[] = {11, 12, 13, 14, 11};
//char arr_char[] = {"abcde"}; better way we have '\0' at the end
char arr_char[] = {'a','b','c','d','e'};
float arr_float[] = {11.20, 12.25, 13.70, 14.80, 11.15};
char* arr_strings[] = {"abc","def","ghi","jkl","mno"};
foo(arr_int, sizeof(arr_int) / sizeof(arr_int[0]), INT);
foo(arr_char, sizeof(arr_char) / sizeof(arr_char[0]), CHAR);
foo(arr_float, sizeof(arr_float) / sizeof(arr_float[0]), FLOAT);
foo(arr_strings, sizeof(arr_strings) / sizeof(arr_strings[0]), STRING);
return 0;
}
I think for foo you want an array of integers and not an array of void pointers.
Instead try?
void foo(int A[], unsigned int array_length)
{
for (unsigned int i = 0; i < array_length; i++) {
printf("%d ", A[i]);
}
}
Or if you can't change foo's signature.
void foo(void *A[], unsigned int array_length)
{
int* p = (int*) A;
for (unsigned int i = 0; i < array_length; ++i) {
// printf("%d ", *p++);
printf("%d ", p[i]);
}
}

recursive find number in between in C

I want to find the number within a range in an array and must be in a recursive way. The function variables couldn't be modified.
Let's say in the range of 2 and 3
The input is : int a[] = {4, 1, 3, 1, 3, 2};
and the output will be = {3,3,2} , 3 found
Not sure how to code the recursive function in this case. The below I have tried not working.
int within(int a[], int N, int lower, int upper, int result[])
{
if(N == 1 && N <= upper && N>= lower)
return a[0];
return within(&a[1], N-1, lower, upper, result);
}
int main()
{
int a[] = {4, 1, 3, 1, 3, 2};
int result[6] = {0};
int i, nResult;
nResult = within(a, 6, 2, 3, result);
printf("%d data passed the bounds\n", nResult);
for (i = 0; i < nResult; i++){
printf("%d ", result[i]);
}
printf("\n");
return 0;
}
I want to find the number within a range in an array
Let's say in the range of 2 and 3
Normally a for loop or similar would be so much easier here
If it has to be recursive....
// need to have another number - r - number in range
// r starts at zero
//
// normally lower case for variable and capitals for things you #define
// N starts at the number of elements of a less one
//
int within(int a[], int N, int lower, int upper, int r, int result[])
{
if(a[0] <= upper && a[0]>= lower) {
result[r]= a[0];
r++;
}
if(N==0) {
return r;
} else {
r = within(&a[1], N-1, lower, upper, r, result);
return r;
}
}
the function will give a return value of the number of values found within the range.
The code above is recursive, but so much more complicated and fragile than a simple loop... such as the fragment below
for (i=0;i<N;i++) {
if(a[i] <= upper && a[i]>= lower) {
result[r]= a[i];
r++;
}
}
If it has to be recursive wihtout r...
// need to have another number - result[0] - number in range
// result[0] starts at zero
//
// normally lower case for variable and capitals for things you #define
// N starts at the number of elements of a less one
//
int within(int a[], int N, int lower, int upper, int result[])
{
if(a[0] <= upper && a[0]>= lower) {
result[0]++;
result[result[0]]= a[0];
}
if(N==0) {
return result[0];
} else {
result[0] = within(&a[1], N-1, lower, upper, result);
return result[0];
}
}
now result conatins
{number in range, first number in range, second number in range....}
Something like this. If you want to implement a recursive function, try to do it in the way that the recursive call happens at the end.
#include <stdio.h>
int find_in_range(int* out, int const *in, int length, int from, int to)
{
if (length == 0)
{
return 0;
}
int addon;
if (*in >= from && *in <= to)
{
*out = *in;
++out;
addon = 1;
}
else
{
addon = 0;
}
return find_in_range(out, in + 1, length - 1, from, to) + addon;
}
#define N 6
int main()
{
int in[N] = {4, 1, 3, 1, 3, 2};
int out[N] = {0};
int num_found = find_in_range(out, in, N, 2, 3);
for (int i = 0; i < num_found; ++i)
{
printf("%d ", out[i]);
}
printf("\n");
return 0;
}
You can modify the following code as per your requirements. This is just a proof of concept code:
#include <stdio.h>
#include <stdlib.h>
static int result[4];
static int ctr1 = 0;
static int ctr2 = 0;
void recFind(int* arr, int* key){
if(ctr2 == 8)
return;
if(*arr >= key[0] && *arr <= key[1])
result[ctr1++] = *arr;
arr++;
ctr2++;
recFind(arr, key);
}
int main(){
int arr[] = {1,3,3,6,4,6,7,8};
int key[] = {1,4};
recFind(arr, key);
printf(" { ");
for(int i = 0; i < 4; i++){
printf("%d ", result[i]);
}
printf("}\n");
}
As it follows from the description of the assignment the function should provide two values: the number of elements that satisfy the condition and an array that contains the elements themselves.
It is evident that the array should be allocated dynamically. And it is logically consistent when the function itself returns the number of elements while the pointer to the generated array is passed by reference as an argument.
The recursive function can look the following way
#include <stdio.h>
#include <stdlib.h>
size_t get_range( const int a[], size_t n, int lower, int upper, int **out )
{
size_t m;
if ( n )
{
m = get_range( a, n - 1, lower, upper, out );
if ( lower <= a[n-1] && a[n-1] <= upper )
{
int *tmp = realloc( *out, ( m + 1 ) * sizeof( int ) );
if ( tmp )
{
tmp[m] = a[n-1];
*out = tmp;
++m;
}
}
}
else
{
*out = NULL;
m = 0;
}
return m;
}
int main(void)
{
int a[] = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };
const size_t N = sizeof( a ) / sizeof( *a );
int lower = 2, high = 3;
int *out;
size_t n = get_range( a, N, lower, high, &out );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", out[i] );
}
putchar( '\n' );
free( out );
return 0;
}
The program output is
2 3 3 2
Below codes will work for you in recursive way. If you don't want to print the numbers just comment out printf statement inside function printfRange. Hope you can understand the logic :-
int within(int *a, int rngH, int rngL, int length)
{
int len = length;
static int i = 0;
static int found = 0;
if(len <=0 )
{
return i;
}
if (*a == rngH)
{
printf("%d,",*a);
i++;
found = 1;
within(++a,rngH, rngL,--len);
}
else if(*a == rngL && found > 0)
{
printf("%d,",*a);
i++;
within(++a,rngH, rngL,--len);
}
else
{
within(++a,rngH, rngL,--len);
}
return i;
}
int main() {
int a[] = {4, 1, 3, 1, 3, 2};
int total = within(a,3,2,6);
printf("\n");
printf("Total :%d\n",total);
return 0;
}

Double Pointer Using Error

I am having a trouble while practicing double pointer
The Error is "EXE_BAD_ACCESS" in Xcode
#include <stdio.h>
/* Program to Get Min and Max Value
in Array */
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
**maxPtr=arr[0]; // Error Line
**minPtr=arr[0]; // Error Line
for(i=1; i<5; i++)
{
if(arr[i]>**maxPtr)
**maxPtr=arr[i];
else if(arr[i]<**minPtr)
**minPtr=arr[i];
}
}
int main()
{
int arr[5]={4, 5, 7, 2, 6};
int *maxptr;
int *minptr;
SaveValue(&maxptr, &minptr, arr);
printf("%d, %d \n", *maxptr, *minptr);
}
I've thought that *dptr of **dptr = &ptr is *ptr
and **dptr means variable which *ptr pointing.
so I assume that **dptr = arr[0] means save first num of arr by reference at variable which *ptr pointing!
but I experiencing access error now.. I will thank for your help!
void SaveValue(int **maxPtr, int **minPtr, int arr[]); provides pointers to pointers to int so use them as such.
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
*maxPtr=arr + 0; /* same as *maxPtr = &arr[0]; */
*minPtr=arr + 0; /* same as *maxPtr = &arr[0]; */
for(i = 1; i < 5; i++)
{
if(arr[i] > **maxPtr)
*maxPtr = arr + i; /* same as *maxPtr = &arr[i]; */
else if(arr[i] < **minPtr)
*minPtr = arr + i; /* same as *minPtr = &arr[i]; */
}
}
Also this interface is a bit dangerous and unflexible; so why not pass the size of the array as well:
void SaveValue(int **maxPtr, int **minPtr, int arr[], ssize_t s)
{
*maxPtr=arr + 0;
*minPtr=arr + 0;
for(--s; s >= 0; --s)
{
if(arr[s] > **maxPtr)
{
*maxPtr = arr + s;
}
else if(arr[i] < **minPtr)
{
*minPtr = arr + s;
}
}
}
Call the fcuntion like this:
SaveValue(&maxptr, &minptr, arr, sizeof arr/sizeof *arr);
As the return value of the function is unused we could utlize it to apply some error inidication to allow the user of the function to write more stable code:
int SaveValue(int ** maxPtr, int ** minPtr, int arr[], ssize_t s)
{
int result = 0;
if ((NULL == arr) || (NULL == maxPtr) || (NULL == minPtr) || (0 > s))
{
result = -1;
errno = EINVAL;
}
else
{
*maxPtr=arr + 0;
*minPtr=arr + 0;
for(--s; s >= 0; --s)
{
if(arr[s] > **maxPtr)
{
*maxPtr = arr + s;
}
else if(arr[i] < **minPtr)
{
*minPtr = arr + s;
}
}
}
return result;
}
Use it like this:
#include <stdio.h>
int SaveValue(int ** maxPtr, int ** minPtr, int arr[], ssize_t s);
int main(void)
{
int arr[5]={4, 5, 7, 2, 6};
int *maxPtr;
int *minPtr;
int result = SaveValue(&maxPtr, &minPtr, arr, sizeof arr/sizeof *arr);
if (-1 == result)
{
perror("SaveValue() failed")
}
else
{
printf("%d, %d \n", *maxPtr, *minPtr);
}
}
The pointer should be pointing to valid memory location before dereferencing it else it will lead to undefined behavior. Below changes will fix your error.
int max;
int min;
int *maxptr = &max;
int *minptr = &min;
There is no need of double pointer here change your function prototype to
void SaveValue(int *maxPtr, int *minPtr, int arr[])
Have
int max;
int min;
in main() and call this API accordingly
SaveValue(&max,&min,arr);
I'll assume your code is purely for pointer learning purposes and not an attempt to implement this operation in a practical situation. So if you want to have maxptr and minptr in main() pointing to the maximum and minimum values in arr[], I think you should change your double pointer assignments from **maxPtr=arr[0] to *maxPtr=&arr[0], so your code would become:
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
*maxPtr = &arr[0]; // Error Line
*minPtr = &arr[0]; // Error Line
for (i = 1; i < 5; i++) {
if (arr[i] > **maxPtr)
*maxPtr = &arr[i];
else if (arr[i] < **minPtr)
*minPtr = &arr[i];
}
}
In this case, when you make the assignments, you don't want to dereference the double pointers. Instead, you should assign it with the address of the element you want to show when you dereference them in main().
You don't need to use the double asterisk when initialize the maxPtr and minPtr pointers in the function SaveValue, neither in the for loop body. MaxPtr and minPtr both are double pointers, but is still the memory direction of maxptr in main(). So you only need to dereference them with a single asterisk, to acces the memory direction them points to.
The source correct source code is this:
#include <stdio.h>
/* Correct program to Get Min and Max Value in Array */
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
*maxPtr=arr[0];
*minPtr=arr[0];
for(i=1; i<5; i++)
{
if(arr[i]>*maxPtr)
*maxPtr=arr[i];
else if(arr[i]<*minPtr)
*minPtr=arr[i];
}
}
int main(void)
{
int arr[5]={4, 5, 7, 2, 6};
int *maxptr;
int *minptr;
SaveValue(&maxptr, &minptr, arr);
printf("%d, %d \n", maxptr, minptr);
return 0;
}
When I compile it with GCC and execute it, i get the next output:
7, 2.
Remember that depending of the environment (Operating System, version, compiler, standards) that you use the program results may vary.

C: Best way to index the digits in an integer

If I have an
int i = 11110001
How would I be able to convert this int into an int array where
int array[8] = {1, 1, 1, 1, 0, 0, 0, 1}
Using a little different approach and snprintf:
#include <stdio.h>
int main (void) {
int i = 11110001;
char arr[9]; //8 digits + \0
int array[8];
if ((snprintf(arr,9,"%d", i) == 8) { //return the 8 characters that were printed
int c;
for(c = 0; c < 8; c++)
array[c] = arr[c] - '0';
}
return 0;
}
P.S: I'm assuming positive values only
You may try like this:
#include <math.h>
char * convertNumber(unsigned int i) {
/* unsigned int length = (int)(log10((float)i)) + 1; */
/* char * arr = (char *) malloc(length * sizeof(char)), * x = arr; */
char * arr = malloc(8);
char * x = arr;
do
{
*x++ = i% 10;
i/= 10;
} while (i != 0);
return arr;
}
Try this :
#include<stdio.h>
void convert_int_to_array(unsigned int);
int main()
{
unsigned int a = 12345678;
convert_int_to_array(a);
return 0;
}
void convert_int_to_array(unsigned int a)
{
int array[25]; // array large enough for an integer
int i = 0, count = 0;
unsigned int num = a;
memset(array, '\0', 20); // I've not included the header file for this.
// gives a warning on compilation.
while(num > 0)
{
array[i] = num % 10;
num = num / 10;
++i;
++count;
}
for(i = count; i>=0;--i)
{
printf("array[%d] = %d\n",i, array[i]);
// or
printf("%d", array[i]);
// dont use both the printf statements, else you will see a
// messed up output.
}
}
BINARY REPRESENTATION :
#include<stdio.h>
struct bit
{
int a : 1;
};
int main()
{
struct bit b;
int d ,f,i;
d=f=256; // take any number of your choice
printf("binary representation of 256:\n");
for(i = 15; i>=0 ; i--) //assuming that the number wont have more than
// 15 DIGITS
{
f=f>>i;
b.a = f;
//d= d>>1;
f=d;
printf("%d",b.a);
}
return 0;
}

Resources