So I've been trying to make a generic function that calculates the (mathematical) mode of some type.
I've got part of it down but am missing other parts, so it won't compile. I need help on how to fill in those missing parts.
The mode function for integers uses a struct count to determine the element and frequency. Its definition is:
struct count {
int value; // the value of the number
unsigned int freq; // how many times the number has been seen
}
The integer version of mode outputs an array that contains all the ties for the most frequent number along with how many ties there are.
unsigned int mode(int* tiebuf, int* list, size_t listsize)
{
struct count modelist[listsize];
size_t modesize = 0;
// initialize modelist[]
for(int i = 0; i < listsize; i++)
{
int* found = search(list[i], modelist, modesize); // signature: search(key, list, listsize)
if(found == NULL)
{
(modelist[i]).num = &list[i];
(modelist[i]).freq = 0;
modesize++;
}
else
{
(*found).freq++;
}
}
// take the most frequent element (last in modelist)
qsort(modelist, listsize, sizeof(struct count), cmpfreq);
int mode_element = listsize-1;
// see if there are any ties for frequency
size_t tiecount = 1;
for(int i = mode_element-1; i > 0; i--)
{
if((modelist[i]).freq < (modelist[mode_element]).freq)
{
tiecount++; // overshot by 1
break;
}
}
// output the tie as an array
for(int i = 0; i < tiecount; i++)
{
tiebuf[i] = (modelist[mode_element-1-i].number);
}
return tiecount; // returns how many elements are in tiebuf
}
int cmpfreq(const void* obj1, const void* obj2)
{
struct count **t1 = (struct count**)obj1;
struct count **t2 = (struct count**)obj2;
return ( ((*t1)->freq) - ((*t2)->freq) );
}
int cmpnum(const void* obj1, const void* obj2)
{
struct count **t1 = (struct count**)obj1;
struct count **t2 = (struct count**)obj2;
return ( ((*t1)->number) - ((*t2)->number) );
}
int* tiedmode( int* list, size_t listsize, int (*cmp)(const void*, const void*) )
{
// takes the median of all ties in the mode
int ties[listsize];
int tiescount = mode(ties, list, listsize);
qsort(ties, tiescount, cmpnum); // this call doesn't work
// want to call cmpnum with cmp as an argument
// this is why we needed cmpnum
int middle = tiescount/2;
return ties[middle];
}
Now I plan on converting this to a generic notation. The first thing to do is change the definition of
struct count
struct count {
void* object; // some object
unsigned int freq; // how many times that object has appeared
}
The signature for mode must also change to
unsigned int mode(void* tiebuf, size_t tienum, void* list, size_t listsize, size_t objsize, int (*cmp)(const void*, const void*))
The big problem is with the auxiliary function cmpnum and this is where I have trouble. Since qsort requires a function pointer with the signature int (*fnptr)(const void*, const void*), cmpnum also requires that signature. However to compare objects, cmpnum probably also needs another function pointer given by the user on how to compare them. Ideally, the cmpnum function would look like
int cmpnum(const void* obj1, const void* obj2, int (*compare)(const void*, const void*))
{
struct count** t1 = (struct count**)obj1;
struct count** t2 = (struct count**)obj2;
return ( compare(t1->object, t2->object) );
}
So how would I cast a function pointer with 3 arguments to a function pointer with only 2 arguments? Or better yet, how would I solve the problem with the discrepancy between* qsort and cmpnum ?
EDIT: The reason why I need cmpnum in the first place is because of tiedmode. This function takes the mode and outputs the median of the ties. In order to find the median, I have to sort by number. But since this will be made generic, I need the user to let the library know how to sort the object inside struct count.
The comparison function you pass to qsort can only take two arguments.
This is what you do in your top code block.
To do what you want as in your second code block, you'd need to create as many variants of cmpnum as you would have *compare pointers. (e.g. cmpnum_type1, cmpnum_type2, etc.) That's the "clean" way.
Another way [which is slightly messy], is to use your original cmpnum, but have the compare sub-function pointer be a global:
int (*compare) (const void *, const void *);
int
cmpnum(const void *obj1, const void *obj2)
{
struct count **t1 = (struct count **) obj1;
struct count **t2 = (struct count **) obj2;
return (compare(t1->object, t2->object));
}
void
dosort(void)
{
compare = foocmp;
qsort(modelist, listsize, sizeof(struct count), cmpnum);
compare = barcmp;
qsort(modelist, listsize, sizeof(struct count), cmpnum);
}
Related
I have a main function that declares an integer array. I want to pass this array to a function whose parameter is of type char *. I cannot alter the signature of the called function.
My aim is to copy the contents of main's integer array data1 into disp's integer array data2, but when I try the following code, I get incorrect values.
data2[0]= 10,data2[1]= 0,data2[2]= 0,data2[3]= 0,data2[4]= 20.
How can I correct it to yield data2[0]= 10,data2[1]= 20,data2[2]= 30,data2[3]= 40,data2[4]= 50 ?
Note: It is not mandatory that data2 be the same size as data1. It could be the same size or larger. I expect the first five elements of data2 to end up the same as the corresponding elements of data1.
#include<stdio.h>
void disp(char *buffer)
{
int itr, data2[5];
for(itr=0;itr<5;itr++)
{
data2[itr]=(int*)buffer[itr];
printf("data2[%d]= %d\n",itr,data2[itr]);
}
}
int main(void)
{
int data1[5]={10,20,30,40,50};
disp((char*)data1);
return 0;
}
The function call seems not to be the problem. You are permitted to cast data1 to type char * as you do, and as is needful for matching the type of the function parameter. This is in fact a special case in that it is even allowed to access the pointed-to data via the resulting char *.
The problem is in reading the data back out inside disp(). This statement:
data2[itr]=(int*)buffer[itr];
is broken because the indexing operator, [], has higher precedence than the cast operator. As a result, you are reading the itrth byte of the data to which buffer points, converting that to type int *, converting the result implicitly to int (turn up your compiler's warning level if it's not already warning about that) and storing the final result in data2. Probably passing through type int * as an intermediate form is effectively a no-op.
The simplest change you could make would be to insert parentheses to override the default operator precedence:
data2[itr] = ((int*)buffer)[itr];
That converts buffer back to an int * first, and access the itrth int to which it points, which is what you want.
Personally, however, if I were relying on the argument to actually be an int * but could not update the parameter type formally (but somehow could nevertheless modify the function implementation) then I would create a correctly-typed copy as the very first thing I did:
void disp(char *buffer) {
int *int_buffer = (int *) buffer;
Then I could later just do
// ...
data2[itr] = int_buffer[itr];
// ...
and generally conduct business almost as if I had been able to set the parameter type appropriately.
Alternatively, for this particular use, you have the option of simply performing a bulk copy:
memcpy(data2, buffer, 5 * sizeof(*data2));
Done, except for printing out the result.
Use for example this statement in the function
data2[itr] = *(int*)( buffer + itr * sizeof( int ) );
Otherwise as the buffer has the type char * then in general the expression buffer[itr] does not point to a correctly aligned object of the type int.
Or as #n. 'pronouns' m pointed in a comment you can use this statement
data2[itr] = ((int*)buffer )[itr];
that in fact is the same.
That is you need to apply correctly the pointer arithmetic.
As you know you are sending int array to the function, you can safely cast it to int *
void disp(char *buffer)
{
int *intBuffer = (int *) buffer;
int itr, data2[5];
for ( itr=0; itr < 5; itr++)
{
data2[itr] = intBuffer[itr];
printf("data2[%d]= %d\n", itr, data2[itr]);
}
}
In your code data1 is int[5], an array of five int. You can declare a pointer to it as int (*)[5].
See this code, changed from your disp() code
void _disp(char* buffer)
{
int(*original)[5] = (int(*)[5])(buffer);
int data2[50];
for (int itr = 0; itr < 5; itr += 1)
{
data2[itr] = (*original)[itr];
printf("data2[%d]= %d\n", itr, data2[itr]);
};
};
It shows
Using (*)[5]
data2[0]= 10
data2[1]= 20
data2[2]= 30
data2[3]= 40
data2[4]= 50
for this code
#include <stdio.h>
void _disp(char*);
int main(void)
{
int data1[5] = { 10,20,30,40,50 };
printf("\nUsing (*)[5]\n\n");
_disp((char*)data1);
return 0;
}
void _disp(char* buffer)
{
int(*original)[5] = (int(*)[5])(buffer);
int data2[50];
for (int itr = 0; itr < 5; itr += 1)
{
data2[itr] = (*original)[itr];
printf("data2[%d]= %d\n", itr, data2[itr]);
};
};
[Compiled just under MSVC 19.27]
An arguably cleaner and more flexible way
This code works too
void _disp2(char* buffer)
{
int* pInt = (int*)buffer;
int data2[50];
for (int itr = 0; itr < 5; itr += 1)
{
data2[itr] = *(pInt + itr);
printf("data2[%d]= %d\n", itr, data2[itr]);
};
};
Here we just cast buffer to an (int*) and use arithmetic to copy the values, as it will be one after another in memory anyway.
Short answer. Use a union and a pointer, rather than type casting.
void disp(char *buffer)
{
int itr, data2[5];
for(itr=0;itr<5;itr++)
{
data2[itr]=(int*)buffer[itr];
printf("data2[%d]= %d\n",itr,data2[itr]);
}
}
/* Becomes */
void disp(char *buffer)
{
union tag1 {
char * cptr;
int * iptr;
} u;
int * itrp = NULL; /* or null or even nil depending
on compiler headers...*/
int itr, data2[5];
u.cptr = buffer; /*in as char* */
itrp = u.iptr; /*out as int* */
for(itr=0;itr<5;itr++)
{
data2[itr]= itrp++;
printf("data2[%d]= %d\n",itr,data2[itr]);
}
}
My problem is that qsort seems to be sending weird pointers to the comparator function. The comparator function itself seems to be working fine if I create 2 gaps and send their pointers as arguements. However, when debugging I'm getting wrong values, even though the gap array is initialized correctly.
I am running the code on Windows 10 if that matters.
Gap definition and comparator function:
typedef struct open_space_t{
ssize_t size;
off_t start;
}Gap;
int GapComparator(const void * aa, const void * bb){
ssize_t a = ((Gap*) aa)->size;
ssize_t b = ((Gap*) bb)->size;
if(a>b){
return 1;
}
if(b>a){
return -1;
}
else{
return 0;
}
}
Running qsort:
Gap** allGaps = malloc((2) * sizeof(*allGaps));
allGaps[0] = malloc(sizeof(*allGaps[0]));
allGaps[0]->size = 20;
allGaps[0]->start = 30044;
allGaps[1] = malloc(sizeof(*allGaps[0]));
allGaps[1]->size = 20;
allGaps[1]->start = 30064;
qsort(allGaps, 2, sizeof(*allGaps), GapComparator);
The comparator receives pointers to the elements it should compare. Your array elements are pointers (Gap *). Therefore the comparator receives Gap **.
Fix:
int GapComparator(const void * aa, const void * bb){
ssize_t a = (*(Gap**) aa)->size;
ssize_t b = (*(Gap**) bb)->size;
Or alternatively:
int GapComparator(const void *aa, const void *bb) {
const Gap **pa = aa, **pb = bb;
ssize_t a = (*pa)->size;
ssize_t b = (*pb)->size;
i am fairly new to c and struggling to properly use the C stdlib qsort() function.
This is relevant to education and as such i am only allowed to use C99 and standard libraries if this is important.
I have a list of items taken from a HashTable and put into a HashItem **array but then when sorting this i am struggling with the compare function, i cannot get the correct value out of the struct. I have looked around and seen a few solutions but they all seem to lead to a
[Error] dereferencing pointer to incomplete type
Here is the struct :
typedef struct {
char *word;
int occurences;
} HashItem;
And i am interested in comparing and sorting by the occurences value.
Here is the bit of code which calls the qsort:
int n = array->number_of_values;
HashItem **standard_array = array_getarray(array);
qsort(standard_array, n, sizeof(HashItem*), compare_func);
Here is the compare function:
int compare_func(const void *a, const void *b){
const struct HashItem* aa = (HashItem*)a;
const struct HashItem* bb = (HashItem*)b;
int val_1 = aa->occurencies;
int val_2 = bb->occurencies;
if(val_1 == val_2){
return 0;
}else if(val_1 > val_2){
return 1;
}else{
return -1;
}
}
Sorry for the formatting, i am new to asking questions here.
I hope you can help thankyou.
Array code :
/*DynArray is a dynamically resizing array that is used to hold values and retain size data throughout*/
typedef struct{
int number_of_values;
int capacity;
HashItem **items;
}DynArray;
/*Method to create a new dynamic array and return it */
DynArray* array_new(int file_size){
DynArray *array = malloc(sizeof(DynArray));
array->number_of_values = 0;
array->capacity = file_size / 10;
printf("capacity is %d " , array->capacity);
array->items = malloc(sizeof(HashItem*)* array->capacity);
}
/*Method used to increase the size of the array and reallocate memory*/
void array_increase_if_full(DynArray *array){
if (array->number_of_values >= array->capacity){
array->capacity *= 1.25;
array->items = realloc(array->items, sizeof(HashItem)*array->capacity);
}
}
/*Method to add a string to the dynamic array specified */
void array_append(DynArray *array, HashItem *item){
array_increase_if_full(array);
array->items[array->number_of_values] = item;
//printf("item %s added \n at position %d ", array->items[array->number_of_values]->word, array->number_of_values);
array->number_of_values++;
}
/*Method used to get value at specified position for given array*/
HashItem *array_get(DynArray *array, int position){
if(position >= array->number_of_values || position <0){
printf("Index specified out of range");
exit(1);
}
//printf("item %s at position %d retrieved", array->items[position]->word, position);
return array->items[position];
}
HashItem **array_getarray(DynArray *array){
HashItem **toreturn[array->number_of_values];
int i;
for(i = 0; i < array->number_of_values; i++){
toreturn[i] = array_get(array, i);
}
return toreturn;
}
Printing the array from the main gives the correct unsorted values of word:occurences
Edit:
Thanks to everyone that took their time to help, it is now in a working state with Michaels suggestion, i no longer use the array_getarray() method and instead use:
int n = array->number_of_values;
int i;
HashItem **standard_array = malloc(n*sizeof(HashItem*));
for(i = 0; i < n; i++){
standard_array[i] = array_get(array, i);
printf("%s : %d \n" , standard_array[i]->word, standard_array[i]->occurences);
}
You structure declaration:
typedef struct {
char *word;
int occurences;
} HashItem;
declares a typedef name for an anonymous struct. There is a HashItem type that's a structure, but there is no struct HashItem type.
So when your compare_func() has the following declarations:
const struct HashItem* aa = (HashItem*)a;
const struct HashItem* bb = (HashItem*)b;
those struct HashItem* variables are pointers to a forward declared struct HashItem that has nothign to do with the HashItem strucuture above.
Just change those variable declarations to:
const HashItem* aa = (HashItem*)a;
const HashItem* bb = (HashItem*)b;
and/or change the declaration of the structure to:
typedef struct HashItem {
char *word;
int occurences;
} HashItem;
However, there's another issue (as mentioned in other answers): you are apparently sorting an array of pointers to HashItem objects, but your compare_function() is being written as if you're sorting an array of the objects (not pointers).
To address this:
int compare_func(const void *a, const void *b)
{
// get HashItem*'s from the HashItem**'s
const HashItem* aa = *((HashItem**)a);
const HashItem* bb = *((HashItem**)b);
int val_1 = aa->occurencies;
int val_2 = bb->occurencies;
if (val_1 == val_2) {
return 0;
} else if (val_1 > val_2) {
return 1;
} else {
return -1;
}
}
Finally (for now anyway), this function is returning the address to a local array, so the data it points to is no longer valid:
HashItem **array_getarray(DynArray *array){
HashItem **toreturn[array->number_of_values];
int i;
for(i = 0; i < array->number_of_values; i++){
toreturn[i] = array_get(array, i);
}
return toreturn;
}
I think you'll need to allocate the array you're retuning using malloc() or calloc() or something. But what I really think you need to do is step back and create some drawing of your data structures and think about the lifetime of the various objects contained in them and how those lifetimes can be tracked an managed so that you don't have leaks, double frees, or pointer dereferences to no longer valid objects.
Change qsort(standard_array, n, sizeof(HashItem), compare_func); to
qsort(standard_array, n, sizeof(HashItem*), compare_func);
In function void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
the third parameter size_t size stands for:
Size in bytes of each element in the array.
It now looks to me like your problems are all springing from the first definition.
/*DynArray is a dynamically resizing array that is used to hold values and retain size data throughout*/
typedef struct{
int number_of_values;
int capacity;
HashItem **items;
}DynArray;
I see no reason for items to be a double-pointer. The comment says it should contain values, but a double-pointer pointing to an array would contain pointers, not the ultimate values. I think this initial misstep is causing you to trip everywhere else. Change it to
...
HashItem *items;
...
and the rest should flow more naturally.
I am trying to sort array of structs using qsort() but frustratingly, it's not working. I have read the manpage for qsort() and I think I have the comparator function that syntactically looks okay, but when I print the "sorted" array after calling qsort(), nothing is sorted in my array.
The code:
#include <stdlib.h>
#include <stdio.h>
#define ARRAY_SZ 5
typedef struct SingleChar
{
unsigned char Character;
unsigned int Weight;
} *SingleCharPtr;
int CompareWeights(const void *a, const void *b)
{
const SingleCharPtr p1 = (SingleCharPtr)a;
const SingleCharPtr p2 = (SingleCharPtr)b;
// printf("Weight1: %u\tWeight2: %u\n", p1->Weight, p2->Weight);
// return (p1->Weight - p2->Weight);
if (p1->Weight < p2->Weight)
return -1;
else if (p1->Weight > p2->Weight)
return 1;
else
return 0;
}
SingleCharPtr MakeChar(unsigned char c, unsigned int w)
{
SingleCharPtr scptr = malloc(sizeof(struct SingleChar));
if (!scptr)
{
fprintf(stderr, "[Error] Out of memory\n");
exit(1);
}
scptr->Character = c;
scptr->Weight = w;
return scptr;
}
int main(void)
{
SingleCharPtr *chars = malloc(ARRAY_SZ * sizeof(SingleCharPtr));
chars[0] = MakeChar('B', 3);
chars[1] = MakeChar('E', 7);
chars[2] = MakeChar('A', 4);
chars[3] = MakeChar('D', 6);
chars[4] = MakeChar('C', 2);
qsort(chars, ARRAY_SZ, sizeof(SingleCharPtr), &CompareWeights);
int i;
for (i = 0; i < ARRAY_SZ; i++)
{
printf("Character: %c\tWeight: %u\n", chars[i]->Character, chars[i]->Weight);
free(chars[i]);
}
free(chars);
return 0;
}
Also, in the comparator function (CompareWeights()), I found out that when I print the weight of the structs pointed by SingleCharPtr, I get 0s for all of them.
Any pointer to right direction would be highly appreciated.
The problem: qsort() passes in pointers to the elements to be compared to the comparator function, and not the elements themselves. So, the arguments to your CompareWeights() function are actually const SingleCharPtr *, disguised as const void *. What you should do in that function is:
const SingleCharPtr p1 = *(const SingleCharPtr *)a;
etc.
Sidenotes:
I. If your assumption had been valid, then you wouldn't have needed the cast:
const SingleCharPtr p1 = a;
is preferred over
const SingleCharPtr p1 = (SingleCharPtr)a;
because of this.
II. The comparison function need not return -1, 0 or 1. It should return an integer less than 0, 0 or greater than 0. Thus, all the huge if in CompareWeight() is completely superfluous, write
return p1->Weight - p2->Weight;
instead.
III. SingleCharPtr *chars = malloc(ARRAY_SZ * sizeof(SingleCharPtr)); - Why? You only use the chars array locally in the main() function, you don't need dynamic allocation for that. Why not write
SingleCharPtr chars[ARRAY_SZ];
instead?
If you see the example in e.g. this manual page, you will see that the when qsort is passed an array of pointer (just like you have) then the arguments to the sorting function are actually pointers to pointers. This is because qsort passes pointers to the elements, not the elements themselves.
To accomodate for that, change accordingly:
int CompareWeights(const void *a, const void *b)
{
const SingleCharPtr p1 = *(SingleCharPtr*)a;
const SingleCharPtr p2 = *(SingleCharPtr*)b;
return (p1->Weight - p2->Weight);
}
I'm currently attempting to use the built-in quicksort provided by C in order to sort an array of pointers to structs. I want to sort each element based on a name element within the struct.
Although my debug output of the entire array each time through the comparison function shows me that the function is indeed shifting elements, the end result is not the correct sorted order. Is there something I'm just not seeing here?
typedef struct // The custom data type.
{
char *name;
} Person;
----------------------------
Person **people; // A dynamically allocated array of Person pointers.
int numPeople; // The logical index of people.
int maxPeople; // The current maximum capacity of people.
int compare(const void *a, const void *b) // The comparison function for determining
{ // alphabetic ordering.
const Person *const *p1 = a;
const Person *const *p2 = b;
return strcmp((*p1)->name, (*p2)->name); // Compare alphabetically, return result.
}
void SomeFunction(void)
{
qsort(people, numPeople, sizeof(Person *), compare); // Perform the sort.
}
Thanks for help with this.
I have tested your code and it looks working OK. Here is the code I compiled with gcc 4.5.2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct // The custom data type.
{
char *name;
} Person;
Person **people; // A dynamically allocated array of Person pointers.
int numPeople; // The logical index of people.
int maxPeople; // The current maximum capacity of people.
int compare(const void *a, const void *b) // The comparison function for determining
{ // alphabetic ordering.
const Person *const *p1 = a;
const Person *const *p2 = b;
return strcmp((*p1)->name, (*p2)->name); // Compare alphabetically, return result.
}
void SomeFunction(void)
{
qsort(people, numPeople, sizeof(Person *), compare); // Perform the sort.
}
int main()
{
int iCnt;
maxPeople = 4;
numPeople = 4;
people = calloc(1, sizeof(Person *) * maxPeople);
people[0] = calloc(1, sizeof(Person));
people[1] = calloc(1, sizeof(Person));
people[2] = calloc(1, sizeof(Person));
people[3] = calloc(1, sizeof(Person));
people[0]->name = strdup("Tanya");
people[1]->name = strdup("Alfred");
people[2]->name = strdup("Harry");
people[3]->name = strdup("Oakley");
for(iCnt = 0; iCnt < numPeople; iCnt ++)
printf("[%d] %s\n", iCnt, people[iCnt]->name);
SomeFunction();
for(iCnt = 0; iCnt < numPeople; iCnt ++)
printf("[%d] %s\n", iCnt, people[iCnt]->name);
return 0;
}
The code looks legit and I'm not sure what's wrong. Could you try compiling the code I tested and see if it works?
Can you try with this
int compare(const void *a, const void *b) // The comparison function for determining
{ // alphabetic ordering.
const Person *p1 = *(const Person**)a;
const Person *p2 = *(const Person**)b;
return strcmp((p1)->name, (p2)->name); // Compare alphabetically, return result.
}