Is there a standard function in C99 to get minimum/maximum element in a given array using a given compare function. Similar to that:
void* get_min(void* start,size_t size,size_t elementSize,int (*compare)(const void *, const void*))
So it seems there is not such standard function, so here is my solution:
For minimum:
void* get_min(void* start,size_t size,size_t elementSize,int (*compare)(const void *, const void*))
{
char* minObject = start;
for(int i = elementSize;i<size*elementSize;i+=elementSize){
char* object = start+i;
if(compare(object,minObject)<0){
minObject = object;
}
}
return minObject;
}
and for maximum:
void* get_max(void* start,size_t size,size_t elementSize,int (*compare)(const void *, const void*))
{
char* maxObject = start;
for(int i = elementSize;i<elementSize*size;i+=elementSize){
char* object = start+i;
if(compare(object,maxObject)>0){
maxObject = object;
}
}
return maxObject;
}
Related
I have a structs array which contains structs that have the following definition:
typedef struct
{
void *data;
void (*print)(void *);
status_ty (*add)(void *, int);
void (*free_element)(void *);
} element_ty;
Each element can be either an "int" element, a "float" element or a "string" element.
I want to be able to add int values to each element.
For example:
add (3, array, size_of_array);
will loop through the array and the value of 3 will be added to each one of the elements.
Add is always adding an int value, For int and float elements this is normal addition, and for a string it should do concatenation.
For example:
if the array contains the following elements: 4.2, 6, "welcome" - then if 3 is added to each element, the result would be: 7.2, 9, "welcome3"
My questions are:
How should I pass the element itself to the add function when add gets a void * and I'm passing a pointer type of element_ty (the struct), which will point to this specific element in the array?
See my written code below, let me know if there are any mistakes there
This is my pseudo code for the AddToStr function:
Receive the int value that should be added
Cast the existing string that is located in element -> data to string (?) to be able to concatenate it later? The current data is stored as type of void *.
malloc the string to be able to receive the int value?
cast it again to void * and store it in element -> data?
free() the malloc?
I'm so confused.
This is what I have wrote so far:
void FreeStrElement(void *(element_ty *element))
{
free(element -> data);
}
/*------------------------------------------------------------------*/
void AddToInt(void *(element_ty *element), int IncrementValue)
{
int data = (int) element -> data;
int sum = data + IncrementValue;
element -> data = (void *) sum;
}
/*------------------------------------------------------------------*/
void AddToFlt(void *(element_ty *element), int IncrementValue)
{
float data = (float *) element -> data;
float sum = data + IncrementValue;
element -> data = (void *) *(float *)∑
}
/*------------------------------------------------------------------*/
void AddToStr(void *(element_ty *element), int IncrementValue)
{
??
}
/*------------------------------------------------------------------*/
void PrintStr(void *num)
{
printf("String in the element: %s\n", (char **) &num);
}
/*------------------------------------------------------------------*/
status_ty InitStr(const char *value, element_ty *element)
{
element -> data = (void *)value;
element -> print = PrintStr;
element -> add = AddtoStr;
element -> free_element = FreeStrElement;
}
The functions that are assigned to each element need to take an element* as input, as they need to be able to modify the data member as needed. This is especially important for "string" elements, since you need to be able to reallocate the string memory when adding more characters, which means assigning a new char* pointer to the data.
You can pass in the element* pointers as void* parameters (which you said is required), but you will have to type-cast the void* back to element* inside the function bodies.
Try something like this:
typedef struct
{
void *data;
void (*print)(void *);
status_ty (*add)(void *, int);
void (*free_element)(void *);
} element_ty;
/*------------------------------------------------------------------*/
void FreeStrElement(void *element)
{
element_ty *p_element = (element_ty *) element;
free(p_element->data);
}
/*------------------------------------------------------------------*/
status_ty AddToInt(void *element, int IncrementValue)
{
element_ty *p_element = (element_ty *) element;
int *p_value = (int*) &(p_element->data);
*p_value += IncrementValue;
return ...;
}
/*------------------------------------------------------------------*/
status_ty AddToFlt(void *element, int IncrementValue)
{
element_ty *p_element = (element_ty *) element;
float *p_value = (float*) &(p_element->data);
*p_value += IncrementValue;
return ...;
}
/*------------------------------------------------------------------*/
status_ty AddToStr(void *element, int IncrementValue)
{
element_ty *p_element = (element_ty *) element;
char *p_str = (char*) p_element->data;
char *new_str = realloc(p_str, strlen(p_str) + 13);
if (!new_str) return ...;
sprintf(new_str, "%s%d", p_str, IncrementValue);
p_element->data = new_str;
return ...;
}
/*------------------------------------------------------------------*/
void PrintInt(void *element)
{
element_ty *p_element = (element_ty *) element;
int *p_value = (int*) &(p_element->data);
printf("Integer in the element: %d\n", *p_value);
}
/*------------------------------------------------------------------*/
void PrintFlt(void *element)
{
element_ty *p_element = (element_ty *) element;
float *p_value = (float*) &(p_element->data);
printf("Float in the element: %f\n", *p_value);
}
/*------------------------------------------------------------------*/
void PrintStr(void *element)
{
element_ty *p_element = (element_ty *) element;
char *p_str = (char*) p_element->data;
printf("String in the element: %s\n", p_str);
}
/*------------------------------------------------------------------*/
status_ty InitInt(int value, element_ty *element)
{
int *p_value = (int*) &(element->data);
*p_value = value;
element->print = &PrintInt;
element->add = &AddToInt;
element->free_element = NULL;
return ...;
}
/*------------------------------------------------------------------*/
status_ty InitFlt(float value, element_ty *element)
{
float *p_value = (float*) &(element->data);
*p_value = value;
element->print = &PrintFlt;
element->add = &AddToFlt;
element->free_element = NULL;
return ...;
}
/*------------------------------------------------------------------*/
status_ty InitStr(const char *value, element_ty *element)
{
element->data = strdup(value);
element->print = &PrintStr;
element->add = &AddToStr;
element->free_element = &FreeStrElement;
return ...;
}
/*------------------------------------------------------------------*/
Then you can do things like this:
void add (int value, element_ty *elements, int n) {
for(int i = 0 i < n; ++i) {
element_ty *elem = &elements[i];
elem->add(elem, value);
}
}
void print (element_ty *elements, int n) {
for(int i = 0 i < n; ++i) {
element_ty *elem = &elements[i];
elem->print(elem);
}
}
void free_elements (element_ty *elements, int n) {
for(int i = 0 i < n; ++i) {
element_ty *elem = &elements[i];
if (elem->free_element) elem->free_element(elem);
}
}
That being said, this approach assumes sizeof(int) and sizeof(float) are <= sizeof(void*), which is usually the case, but not guaranteed.
This approach also violates Strict Aliasing rules. You can use memcpy() to avoid that, but using a union instead would be easier and cleaner (it also avoids the sizeof issue, too), eg:
typedef struct
{
union {
int i;
float f;
char *s;
} data;
void (*print)(void *);
status_ty (*add)(void *, int);
void (*free_element)(void *);
} element_ty;
/*------------------------------------------------------------------*/
void FreeStrElement(void *element)
{
element_ty *p_element = (element_ty *) element;
free(p_element->data.s);
}
/*------------------------------------------------------------------*/
status_ty AddToInt(void *element, int IncrementValue)
{
element_ty *p_element = (element_ty *) element;
p_element->data.i += IncrementValue;
return ...;
}
/*------------------------------------------------------------------*/
status_ty AddToFlt(void *element, int IncrementValue)
{
element_ty *p_element = (element_ty *) element;
p_element->data.f += IncrementValue;
return ...;
}
/*------------------------------------------------------------------*/
status_ty AddToStr(void *element, int IncrementValue)
{
element_ty *p_element = (element_ty *) element;
char *p_str = p_element->data.s;
char *new_str = realloc(p_str, strlen(p_str) + 13);
if (!new_str) return ...;
sprintf(new_str, "%s%d", p_str, IncrementValue);
p_element->data.s = new_str;
return ...;
}
/*------------------------------------------------------------------*/
void PrintInt(void *element)
{
element_ty *p_element = (element_ty *) element;
printf("Integer in the element: %d\n", p_element->data.i);
}
/*------------------------------------------------------------------*/
void PrintFlt(void *element)
{
element_ty *p_element = (element_ty *) element;
printf("Float in the element: %f\n", p_element->data.f);
}
/*------------------------------------------------------------------*/
void PrintStr(void *element)
{
element_ty *p_element = (element_ty *) element;
printf("String in the element: %s\n", p_element->data.s);
}
/*------------------------------------------------------------------*/
status_ty InitInt(int value, element_ty *element)
{
element->data.i = value;
element->print = &PrintInt;
element->add = &AddToInt;
element->free_element = NULL;
return ...;
}
/*------------------------------------------------------------------*/
status_ty InitFlt(float value, element_ty *element)
{
element->data.f = value;
element->print = &PrintFlt;
element->add = &AddToFlt;
element->free_element = NULL;
return ...;
}
/*------------------------------------------------------------------*/
status_ty InitStr(const char *value, element_ty *element)
{
element->data.s = strdup(value);
element->print = &PrintStr;
element->add = &AddToStr;
element->free_element = &FreeStrElement;
return ...;
}
/*------------------------------------------------------------------*/
I'm trying to store a function pointer in a struct and can't make it works. Here's the code.
typedef enum { POUSSOIR, INTERRUPTEUR } Button_Type;
typedef struct Button {
char name[20];
Button_Type type;
void(*action)(struct Button*);
char input[20];
char output[20];
} Button;
static Button buttons[7];
Button Button_Create(char *name, Button_Type type, void (*action), char input[20], char output[20]) {
Button this;
strcpy(this.name, name);
this.type = type;
this.action = (*action)(&this);
strcpy(this.input, input);
strcpy(this.output, output);
return this;
}
void dimmer(Button *button) {
LOG("dim!!!");
}
int init_Buttons() {
buttons[0] = Button_Create("Salon", POUSSOIR, &dimmer, "DI04", "DMX_2");
return 1;
}
What I want is to have many buttons with differents callbacks for on-off case or dimmable case and more. So I wan't to init each button with a callback function. Also I can't pass the Button reference to Button_Create function as it doesn't exit yet.
How can I acheive this ?
EDIT : SOLUTION
Button Button_Create(char *name, Button_Type type, void (*action)(Button*), char input[20], char output[20]) {
Button this;
strcpy(this.name, name);
this.type = type;
this.action = action;
strcpy(this.input, input);
strcpy(this.output, output);
return this;
}
//as example
void *fn_ButtonThread(void *p_Data) {
printf("Starting Button Thread.\r\n"); fflush(stdout);
while(!exitFlag) {
if (....) {
// Call the function with parameters here
buttons[0].action(&buttons[0]);
}
}
printf("Stopping Button Thread.\r\n"); fflush(stdout);
}
The declaration of the action parameter in Button_Create and the setting of this.action is wrong. Here is a corrected version:
Button Button_Create(char *name, Button_Type type, void (*action)(Button *), char input[20], char output[20]) {
Button this;
strcpy(this.name, name);
this.type = type;
this.action = action;
strcpy(this.input, input);
strcpy(this.output, output);
return this;
}
In the call to Button_Create you can change &dimmer to dimmer. It will work either way because dimmer is already considered to be a pointer to the function defined as dimmer and the & is ignored in this case. (Function pointers behave differently to object pointers in that regard.)
You could call a function defined as follows to invoke the action:
void Button_Press(Button *button) {
button->action(button);
}
Aren't the buttons created automatically by their declaration: static Button buttons[7];
They are not pointers, so that struct of 7 elements would be created. Also there are no system calls to CreateWindow etc.
Thus you can send &button[0] etc. as parameters to set their values. The code below compiles and prints "DI04" and "DMX_2", VS2019. (I haven't tested the function pointers).
typedef enum { POUSSOIR, INTERRUPTEUR } Button_Type;
typedef struct Button {
char name[20];
Button_Type type;
void(*action)(Button*);
char input[20];
char output[20];
} Button;
static Button buttons[7];
void LOG(const char* s) {
printf_s(s);
}
void Button_Create(Button &b, const char* name, Button_Type type, void(*action)(Button*), const char input[20], const char output[20]) {
//Button this;
strcpy_s(b.name, name);
b.type = type;
b.action = action; // (*action)(&b);
strcpy_s(b.input, input);
strcpy_s(b.output, output);
}
void dimmer(Button* button) {
LOG("dim!!!");
}
int init_Buttons() {
//buttons[0] = Button_Create("Salon", POUSSOIR, &dimmer, "DI04", "DMX_2");
Button_Create(buttons[0], "Salon", POUSSOIR, &dimmer, "DI04", "DMX_2");
printf_s(buttons[0].input);
printf_s("\n");
printf_s(buttons[0].output);
return 1;
}
int main()
{
init_Buttons();
return 0; //or whatever
}
enter code here
EDIT: (Button this; Ah plain C?... It's confusing with C++ this.
Without references &:
void Button_Create_Ptr(Button *b, const char* name, Button_Type type, void(*action)(Button*), const char input[20], const char output[20]) {
//Button this;
strcpy_s(b->name, name);
b->type = type;
b->action = action; // (*action)(&b);
strcpy_s(b->input, input);
strcpy_s(b->output, output);
}
Then:
Button_Create_Ptr(&buttons[1], "Baloon", POUSSOIR, &dimmer, "GYZ1", "BTS2");
can't read data from void pointer:
#include <windows.h>
typedef enum {
ADDRESS,
PERSON,
} DataType;
typedef struct {
DataType type;
void* data;
} Data;
Data* create_data(DataType type, void* data);
typedef struct {
char* number;
char* street;
char* city;
char* state;
char* postalCode;
} Address;
typedef struct {
int age;
char* name;
} Person;
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
) {
// WRITE
Address* home = malloc(sizeof(Address));
home->number = "123";
home->street = "Main";
home->city = "New York";
home->state = "NY";
home->postalCode = "10001";
Data* addressdata = create_data(ADDRESS, &home);
// READ
char* addressstreet = ((Address*)addressdata->data)->street;
}
Data* create_data(DataType type, void* data)
{
Data* d = (Data*)malloc(sizeof(Data));
d->type = type;
d->data = data;
return d;
}
After reading your question, the first thing popped in my head is that how can you dereference a void pointer since it has no object type.
There's parameter mismatch in
Data* create_data(DataType type, void* data); & Data* addressdata = create_data(ADDRESS, &home);
and instead of sending address of home, i.e. create_data(ADDRESS, &home); send create_data(ADDRESS, home);
I read this article but it doesn't answer my question.
file: hero.h
typedef struct {
int id;
void (*setId)();
int (*getId)();
} Hero, *HeroPtr;
file: hero.c
#include "hero.h"
static void setId(int id);
Hero obj = {
.setId = setId,
.getId = getId,
};
void setId(int id) {
HeroPtr hero_obj = 0x0; //TODO how get address: hero_obj1 (1 > ) OR
// hero_obj2 (2 > )
hero_obj->id = id;
}
void getId() {
HeroPtr hero_obj = 0x0; //TODO how get address: hero_obj1 (1 > ) OR
// hero_obj2 (2 > )
return hero_obj->id;
}
file: main.c
#include "hero.h"
int main() {
Hero hero_obj1, hero_obj2;
//1 >
hero_obj1->setId(1);
//2 >
hero_obj2->setId(2);
return 0;
}
You could do the equivalent of what C++ does behind the scenes.
file: hero.h
typedef struct hero {
int id;
void (*setId)(struct hero*, int);
int (*getId)(struct hero*);
} Hero, *HeroPtr;
void constructHero(HeroPtr this);
file: hero.c
#include "hero.h"
static void setId(HeroPtr this, int id);
static int getId(HeroPtr this);
Hero initObj = {
.setId = &setId,
.getId = &getId,
};
void constructHero(HeroPtr this)
{
*this = initObj;
}
void setId(HeroPtr this, int id) {
HeroPtr hero_obj = this;
hero_obj->id = id;
}
int getId(HeroPtr this) {
HeroPtr hero_obj = this;
return hero_obj->id;
}
file: main.c
#include "hero.h"
#include "stdio.h"
int main() {
Hero hero1;
Hero hero2;
HeroPtr hero_obj1=&hero1;
HeroPtr hero_obj2=&hero2;
constructHero(hero_obj1);
constructHero(hero_obj2);
hero_obj1->setId(hero_obj1, 1);
hero_obj2->setId(hero_obj2, 2);
printf("hero_obj1 id = %d\n", hero_obj1->getId(hero_obj1));
printf("hero_obj2 id = %d\n", hero_obj2->getId(hero_obj2));
return 0;
}
It looks like you are trying to implement virtual functions in C, by using function pointers. In object-oriented programming languages like C++ or Java such functions or methods inside classes have an implicit this pointer as argument, which is hidden. That means that the int getId() function actually has the signature int getId(Hero* this) and the void setId(int id) function actually has the form void setId(Hero* this, int id). As I have already said, in object-oriented programming languages you don't see or add the this pointer and you also don't pass the argument when you invoke the function. The compiler does this for you. It always automatically passes the pointer to the instance as this pointer, on which the function was invoked. In C, however, these features don't exist. So you have to add the this argument and pass it when invoking the function by yourself.
When I run add cards using add_card, on the 7th card it is supposed to sort all of the cards. But when I run this I get a semi-ordered result.
>> require 'ext/straight_count' #=> true >> s = EV::StraightCount.new; s.add_card(5,0); s.add_card(8,1); s.add_card(12,2); s.add_card(14,3); s.add_card(12,4); s.add_card(3,5); s.add_card(5,6)
card: 12
card: 5
card: 12
card: 14
card: 8
card: 5
card: 3
I don't think there is a problem with NUM2INT, because when I print the array back unordered, it comes out as expected.
straight.h
int *pCards, *pSortedCards;
int cCards[NUM_CARDS], cSortedCards[NUM_CARDS];
straight.c
void Init_straight()
{
pCards = &cCards[0];
}
static VALUE
add_card(VALUE self, int rCardValue, int rCardIndex)
{
*(pCards + NUM2INT(rCardIndex)) = NUM2INT(rCardValue);
if (NUM2INT(rCardIndex) == 6)
check_for_straight();
return Qnil;
}
check_for_straight()
{
sort_by_value(pCards);
}
card_sort.c
int compare_card_values (const void *a, const void *b)
{
const double *da = (const double *) a;
const double *db = (const double *) b;
return (*da > *db) - (*da < *db);
}
void sort_by_value(int *pCards)
{
qsort(pCards, NUM_CARDS, sizeof(pCards[0]), compare_card_values);
}
You're casting the card values to double in compare_card_values even though the array contains int. Try this instead:
int compare_card_values (const void *a, const void *b)
{
const int *da = (const int *) a;
const int *db = (const int *) b;
return (*da > *db) - (*da < *db);
}