About my code searching a element using function pointer - arrays

I was doing a question about finding an element in an array using function pointer concept. But I am facing some issues regarding this.
Here is my code.
#include <stdio.h>
#include <stdbool.h>
bool compare( const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(const void * arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = *(char**)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
The code is compile fine but not giving any output?
What is wrong with this code?

No need to de-reference arr, just alter its type to do the pointer math.
// char *ptr = *(char**) arr;
const char *ptr = arr;
Minor: Best practice to use const here.

Related

Why can't a pointer's value be accessed with square bracket syntax when returned from a function?

I am learning basic C, and I am still trying to understand arrays and pointers. I am trying to write a push function to mimic the behavior of an array in Javascript, but with a workaround, since arrays cannot be returned in C.
When I access the returned pointer with (*p+3), it yields the correct value, but p[3] does not. However, I can still access the correct value within push() with p[3]. Why is this?
#include <stdio.h>
#include <stdlib.h>
void br() {
putchar('\n');
}
int *push(int *arr, size_t size, int val) {
int *arr2 = calloc(size + 1, sizeof(int));
for (int i = 0; i < size; i++) {
arr2[i] = arr[i];
}
arr2[size] = val;
return arr2;
}
int main(int argc, char *argv[]) {
int myNums[] = { 1, 2, 3 };
int *p = push(myNums, sizeof(myNums), 4);
printf("%i", (*p + 3));
br();
printf("%i", p[3]);
br();
return 0;
}
EDIT: I think there is a better solution using structs.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int*values;
int length;
} intArray;
void printInts(intArray * arr){
for(int i = 0; i < arr->length; i++){
printf("Value %i: %i\n",i,arr->values[i]);
}
}
intArray push(intArray * arr, int value){
arr->length++;
arr->values = realloc(arr->values, sizeof(int)*arr->length);
arr->values[arr->length-1] = value;
return *arr;
}
intArray pop(intArray * arr){
arr->length--;
arr->values = realloc(arr->values, sizeof(int)*arr->length);
return *arr;
}
int main(int argc, char *argv[]) {
intArray myNums;
myNums = push(&myNums,15);
myNums = push(&myNums,30);
myNums = push(&myNums,45);
myNums = push(&myNums,60);
myNums = pop(&myNums);
printInts(&myNums);
/* expected output:
Value 0: 15
Value 1: 30
Value 2: 45
*/
return 0;
}
There are two mistakes in the code:
int *p = push(myNums, sizeof(myNums), 4);
sizeof(myNums) is not the length of the array (ie: the number of elements), but its size in bytes.
You can use sizeof(myNums) / sizeof(myNums[0]) to compute the number of elements at compile time.
printf("%i", (*p + 3));
You first print *p + 3, which is not the same as *(p + 3): you get the expected output only by coincidence because *p, which is equivalent to p[0] happens to have the value 1. Conversely, p[3] accesses the fourth element of the reallocated array, whose value is undefined as it was copied from data beyond the end of the original array passed to push().
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int *push(int *arr, size_t count, int val) {
int *arr2 = calloc(count + 1, sizeof(int));
for (int i = 0; i < count; i++) {
arr2[i] = arr[i];
}
arr2[count] = val;
return arr2;
}
int main(int argc, char *argv[]) {
int myNums[] = { 1, 2, 3 };
int *p = push(myNums, sizeof(myNums) / sizeof(myNums[0]), 4);
printf("%i\n", *(p + 3));
printf("%i\n", p[3]);
free(p);
return 0;
}

Segmentation fault while passing integer pointer into function [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 2 years ago.
Background context:
I was doing leetcode twoSum and trying to understand one of the solutions. So, I decided to implement the solutions in the code block and use the debugger.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 50000
int hash(int key);
void insert(int *keys, int *values, int key, int value);
int search(int *keys, int *values, int key);
int* twoSum(int* nums, int numsSize, int target, int* returnSize);
int main()
{
int ar[4]={2,7,11,15};
int *ans;
int *returnSize;
ans=malloc(2*sizeof(int));
ans=twoSum(ar,4,9,returnSize);
printf("d d ",ans[0],ans[1]);
free(ans);
return 0;
}
int hash(int key) {
int r = key % SIZE;
return r < 0 ? r + SIZE : r;
}
void insert(int *keys, int *values, int key, int value) {
int index = hash(key);
while (values[index]) {
index = (index + 1) % SIZE;
}
keys[index] = key;
values[index] = value;
}
int search(int *keys, int *values, int key) {
int index = hash(key);
while (values[index]) {
if (keys[index] == key) {
return values[index];
}
index = (index + 1) % SIZE;
}
return 0;
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
*returnSize = 2;
int keys[SIZE]; //new array
int values[SIZE] = {0}; //new array
for (int i = 0; i < numsSize; i++) {
int complements = target - nums[i];
// check for complements in the hash table
int value = search(keys, values, complements);
if (value) {
//return an array
int *indices = (int *) malloc(sizeof(int) * 2);
indices[0] = value - 1;
indices[1] = i;
return indices;
}
//if not insert the current values
insert(keys, values, nums[i], i +1);
}
return NULL;
}
When I use the debugger, the error SEGMENTATION fault appears at line *returnSize=2?
What is the problem?
I was trying to understand why i+1 in insert(keys, values, nums[i], i +1) instead of i?
You need to initialize returnSize before you can dereference it. You've got UB because you dereference a pointer that is not initialized. But I suspect what you really wanted was to have returnSize as an output parameter, which would look like this:
int main()
{
int ar[4]={2,7,11,15};
int *ans;
int returnSize;
ans=malloc(2*sizeof(int));
ans=twoSum(ar,4,9, &returnSize);
printf("d d ",ans[0],ans[1]);
free(ans);
return 0;
}
Note that returnSize in main() is now of type int (not int*). Its address is passed to the function twoSum. The difference is that the pointer passed to the function points to an existing variable.

How to properly use qsort()?

I am trying to write a simple program to find the median of an array. To do that first I tried to use qsort to put my values in order but I can't quite get it to work. I believe it has something to do with my function parameter and pointers.
#include <stdio.h>
#include <stdlib.h>
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int median(const int* array)
{
double median;
int length =0;
while(array[length])
length++;
qsort(*array, length, sizeof(int), cmpfunc);
if(length %2 ==0)
{
median=(array[length/2] + array[(length/2)+1])/2;
}
else
{
median = array[(length +1/2)];
}
return median;
}
int main ()
{
int array [] = {5, 3, 2, 7, 9};
printf( "%f", median(array));
}
Beside that you are getting wrong value for length with snippet
while(array[length]) // Array is not ended with zero
length++; // Length would get some unexpected value
you need to return double from function median and it also need one more parameter for length.
double median(int* array, const int length){...}
// ^Removed const qualifier and added an extra parameter for array size
Call median as
double result = median(array, sizeof(array)/sizeof(array[0]))
From the qsort documentation:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
The qsort() function sorts an array with nmemb elements of size size.
The base argument points to the start of the array.
First you need to get the length right; second, in your original call to qsort you used qsort(*array...) which is not what you want. Just use qsort(array...).
It is also useful when writing these small tests to view the actual data; you can either use a debugger, or just print out the contents of your array.
#include <stdio.h>
#include <stdlib.h>
int cmpfunc(const void *a, const void *b)
{
return (*(int *) a - *(int *) b);
}
void printArray(int *array, int length)
{
int i;
for (i = 0; i < length; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
int median(int *array, int length)
{
double median;
printArray(array, length);
qsort(array, length, sizeof(int), cmpfunc);
printArray(array, length);
if (length % 2 == 0) {
median = (array[length / 2] + array[(length / 2) + 1]) / 2;
} else {
median = array[(length + 1 / 2)];
}
return median;
}
int main()
{
int array[] = { 5, 3, 2, 7, 9 };
printf("%d\n", median(array, sizeof(array) / sizeof(array[0])));
return 0;
}

pointer arithmetic and "generic" in c

I tried to put program a generic method in C to identify the biggest element of an array.
At first, I programmed this:
int compare(const void* a, const void* b) {
if(a < b)
return 0;
return 1;
}
int main(void) {
int (*prt)(const void*, const void*);
prt=compare;
printf("%i",(*prt)(1,1));
return EXIT_SUCCESS;
}
This works fine, but if I try to put the function pointer prt
in a new method, I do not know how to handle it.
Addionally i dont know how to handle void* types.
void* maximum(int len, void* array, size_t size, int (*cmp)(const void*, const void*));
int compare(const void* a, const void* b) {
if(a < b)
return 0;
return 1;
}
int main(void) {
int (*prt)(const void*, const void*);
prt=compare;
printf("%i",(*prt)(1,1));
int array[6] = {3, 1, 0 , 4 , 3, 9};
maximum(len,array,0,prt);
return EXIT_SUCCESS;
}
void* maximum(int len, void* array, size_t size, int (*cmp)(const void*, const void*)) {
void* temp;
temp = array[0];
printf("%i",a);
int i;
for(i = 1; i < len; i++) {
if((*cmp)(temp,array[i]) == 0) {
temp = array[i];
}
}
return 0;
}
There are many errors... e.g. the variable temp or if((*cmp)(temp,array[i]) == 0).
Do you have an idea how to use not defined datatypes?
You are comparing addresses instead of values:
int compare(const void* a, const void* b) {
if(a < b)
return 0;
return 1;
}
Should be:
int compare(const void* a, const void* b) {
if(*(int *)a < *(int *)b)
return 0;
return 1;
}
Here is an example that can be taken as a base code.
#include <stdio.h>
int cmp( const void *a, const void *b )
{
return *( const int * )a < *( const int * )b;
}
void * maximum( const void *array, size_t size, size_t len,
int cmp( const void *, const void *) )
{
const void *max = array;
size_t i = 1;
for ( ; i < size; i++ )
{
if ( cmp( ( const char * )max, ( const char * )array + i * len ) )
{
max = ( const char * )array + i * len;
}
}
return ( void * )max;
}
int main(void)
{
int array[] = { 3, 1, 0 , 4 , 3, 9 };
int *max =
maximum( array, sizeof( array )/ sizeof( *array ), sizeof( int ), cmp );
printf( "Maximum = %d\n", *max );
return 0;
}
The output is
Maximum = 9
#include <stdio.h>
#include <stdlib.h>
void *maximum(int len, void* array, size_t size, int (*cmp)(const void*, const void*));
//comparison function must know about type.
//Because it is not known for functions like memcmp that type what is the layout.
int intcmp(const int *x, const int *y){
return *x < *y ? -1 : *x > *y;
}
int main(void) {
int array[6] = {3, 1, 0 , 4 , 3, 9};
int *p = maximum(sizeof(array)/sizeof(*array), array, sizeof(*array), (int (*)(const void*,const void*))intcmp);
printf("%d\n", *p);//9
return EXIT_SUCCESS;
}
void *maximum(int len, void *array, size_t size, int (*cmp)(const void*, const void*)) {
int i;
void *temp = array;
for(i = 1; i < len; i++) {
if(cmp((char*)array + size*i, temp)>0) {
temp = (char*)array + size*i;
}
}
return temp;
}

C linear search error

My lsearch function should find the value 11 in my array. It does not, and I don't know where the error is. Why does this code not find the value 11?
#include <stdio.h>
#include <string.h>
#define PF printf
int main() {
int intcmp(void *ip1, void * ip2);
void * lsearch(void *key, void *base, int n, int elemSize,
int(* cmpfun)(void *, void *));
int arr[] = {4, 6, 2, 3, 11, 22, 15};
int n = sizeof(arr) / sizeof(int);
int key = 11;
int *found = lsearch(&key, &arr, n, sizeof(int), intcmp);
PF("found=%p", found);
return 1;
}
int intcmp(void *ip1, void * ip2) {
int *p1 = ip1;
int *p2 = ip2;
return *p1 - *p2 == 0;
}
void * lsearch(void *key, void *base, int n, int elemSize,
int(* cmpfun)(void *, void *)) {
int i;
for(i = 0; i < n; i ++) {
void *elemArr = (char *)base + i * elemSize;
if(cmpfun(key, elemArr) == 0)
return elemArr;
}
return NULL;
}
There's a few oddities in your code (PF and the way the functions is declared in main yet defined globally), however, the problem is that your logic if inverted in a two places.
if(cmpfun(key, elemArr) == 0)
return elemArr;
And:
return *p1 - *p2 == 0;
Mentally run through that when the two elements are equal. The == expression will return 1 when the number does actually equal the other. 1 != 0 thus it's not considered found.
Either through a negation in there or just return *p1 - *p2; directly.
I have annotated the code below:
#include <stdio.h>
#include <string.h>
// This is bad practice. It makes your code less readable.
// I won't use it below.
#define PF printf
// Declare this first so a prototype is not needed.
// You violated a C pattern by using `cmp` in the name.
// Comparison functions in C return <0, 0, >0, not a binary value.
// To wit, later you used the comparison correctly. I've fixed the
// inconsistency.
int intcmp(void *vp1, void *vp2)
{ // Most C styles have the brace on its own line, unlike Java. Roll with it.
int *p1 = vp1, *p2 = vp2;
return *p1 - *p2;
}
// Search n elements of size elemSize in the array at
// base in sequence using cmpfun on key,
// to test for equality (cmpfun == 0). Return a pointer
// to the found element or NULL if none.
void *lsearch(void *key, void *base, int n,
int elemSize, int(* cmpfun)(void *, void *))
{
int i;
for (i = 0; i < n; i++) {
void *elemArr = (char*)base + i * elemSize;
if (cmpfun(key, elemArr) == 0)
return elemArr;
}
return NULL;
}
int main()
{
int arr[] = {4, 6, 2, 3, 11, 22, 15};
int n = sizeof(arr) / sizeof(int);
int key = 11;
int *found = lsearch(&key, &arr, n, sizeof(int), intcmp);
printf("found=%p (%d)", found, *(int*)found);
return 0; // By convention zero corresponds to no error.
}

Resources