I'm following LCTHW tutorial and I have a task to do.
This is the data structure:
typedef struct DArray {
int end;
int max;
size_t element_size;
size_t expand_rate;
void **contents;
} DArray;
I have declared a typedef:
typedef int (*DArray_compare) (const void *a, const void *b);
When I create a sorting function, I pass to it a DArray_compare, the problem is that I can't figure out how to do an example of this comparator.
I tried to do something like this:
int compare(const void *a, const void *b)
{
int i = (int)*a;
int k = (int)*b;
printf("%d %d\n", i, k);
return i - k;
}
But I get an error:
error: operand of type 'void' where arithmetic or pointer type is required int i = (int)*a;
The question is: without changing the struct and the typedef of the comparator, I want to create a comparator that compares int, how can I do it?
int i = *(int*)a;
// This one has more parens to make it really obvious what your intent is.
int k = *((int*)b);
The second line (k=) is easiest to explain cos of all the brackets. You can rewrite it as follows:
// Cast b from a pointer to a void into a pointer to an int.
int *X = (int*)b;
// k = "what X is pointing to" or "the contents of X"
int k = *X;
edit:
I think ralu's comment is suggesting you change all the void* to int* which is a much safer solution if you have that power.
typedef int (*DArray_compare) (const int *a, const int *b);
int compare(const int *a, const int *b)
{
int i = *a;
int k = *b;
...
A comparison function for use with bsearch() or qsort() from the standard C library for arrays of DArray structures might look like:
int compare(const void *a, const void *b)
{
const DArray *d1 = a;
const DArray *d2 = b;
if (d1->end < d2->end)
return -1;
else if (d1->end > d2->end)
return +1;
else if (d1->max < d2->max)
return -1;
else if (d2->max > d2->max)
return +1;
else
return 0;
}
Clearly, if you need to compare other fields, you can add those comparisons into the framework above quite easily. The general structure of the function is my recommended way of writing such comparators. You can add explicit casts to the assignment lines if you wish; C++ would require them, but C does not.
Note that your typedef is of minimal relevance to the comparator itself (though the comparator as a function pointer should match that typedef). It is the type that a comparator should have, but you can't use that typedef name when writing the function. You could use the typedef in the implementation of the sort function and in its declaration.
I observed in a couple of places that returning the difference of two signed int values as the result of the comparator leads to undefined behaviour.
In a comment to a now deleted answer, AR89 asked:
Instead of the subtraction an if statement would be safer?
Yes. Consider what happens if you have 16-bit int values and you compare -30,000 and +30,000; you've got signed overflow, and you might get a positive value back from your comparator, even though the first value is less than the second. Analogous situations can occur with 32-bit or 64-bit integers. They're relatively unlikely; if you know that your values are well within range, you'd be OK. But for general purpose code, you should do the piecewise comparison:
if (i < k)
return -1;
else if (i > k)
return +1;
else
return 0;
as it works regardless of the values of i and k. Also note that the if comparison works reliably for unsigned int types too, whereas subtraction really doesn't work then (the result is always zero or positive).
Related
I searched for the implementation of suffix array in C, but all the programs I saw were in C++ which used sort. I am not sure how can I use the built-in function of C, qsort() in place of sort() function of C.
Can we implement suffix arrays without using qsort()?
or
how to use qsort() to implement suffix arrays in C?
here is the code that I got from geeksforgeeks.com:
int cmp(struct suffix a, struct suffix b)
{
return strcmp(a.suff, b.suff) < 0? 1 : 0;
}
int *buildSuffixArray(char *txt, int n)
{
// A structure to store suffixes and their indexes
struct suffix suffixes[n];
// Store suffixes and their indexes in an array of structures.
// The structure is needed to sort the suffixes alphabatically
// and maintain their old indexes while sorting
for (int i = 0; i < n; i++)
{
suffixes[i].index = i;
suffixes[i].suff = (txt+i);
}
// Sort the suffixes using the comparison function
// defined above.
sort(suffixes, suffixes+n, cmp);
// Store indexes of all sorted suffixes in the suffix array
int *suffixArr = new int[n];
for (int i = 0; i < n; i++)
suffixArr[i] = suffixes[i].index;
// Return the suffix array
return suffixArr;
}
the cmp function is comparing structure data type while I am getting an error when using qsort(), which says that only void input is allowed.
The declaration of the qsort function is as follows:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
You'll notice that the comparison function it accepts must be defined to take a const void * for each of its two parameters, but you're instead passing in a struct suffix for each one.
You need to change your comparison function to use the parameter types that qsort expects. Then you can convert those parameters inside of the function to the proper pointer type and use those.
int cmp(const void *p1, const void *p2)
{
const struct suffix *a = p1;
const struct suffix *b = p2;
return strcmp(a->suff, b->suff) < 0? 1 : 0;
}
I'm writing some Code that does some basic analysis on data.
The data collected is in an array of structs. It takes the approximate form:
struct page {
int width;
int length;
char name[50];
// etc...
}
struct page pages[100];
I need to write code that finds the smallest width, largest width, smallest length, largest length, etc. So I write code that looks something like this:
int smallestWidth(struct page pages[]){
unsigned int smallest = -1;
(for loop){
if (smallest > pages[i].width) smallest = pages[i].width;
}
return smallest;
}
And then I find that I'm copy-pasting this function and changing tiny details for the other requirements like largest width. And whenever I'm copy-pasting chunks of code, that raises alarm bells for me, and I'm thinking I'm doing it wrong.
But, I'm kind of new to C, so I'm not sure what the right way to approach this is.
How would you write this in C properly (if there is a proper way) that minimizes the amount of code that I'm copy-pasting?
C++ language has overrides and pointer to members that C has not. So the C way would be to use auxilliary functions to extract the correct data and compare them:
int getLength(struct page *page) {
return page->length;
}
int getWidth(struct page *page) {
return page->width;
}
int lesser(int a, int b) {
return a<b;
}
int greater(int a, int b) {
return a>b;
}
typedef int(*extractor)(struct page *p);
typedef int (*comparator)(int a, int b);
int process(struct page * p, int size, extractor ext, comparator cmp) {
// code here the generic part
...
}
int lesserWidth = process(pages, 100, &getWidth, &lesser);
...
But it includes a good deal of boiler plate code, so it may be interesting or not depending on the complexity of the generic part...
I think the following will be classified as a Horrible Hack, however, it satisfies your request. It only works for integers because of the compare.
struct page {
int width;
int length;
// etc...
} pages[100] = {{1,2},{3,4},{5,6}};
int smallestX(struct page pages[], size_t offset)
{
unsigned int smallest = -1, k;
for (int i=0; i<3; i++){
k= *((int *)((char *)(&pages[i])+offset));
if (smallest > k) smallest = k;
}
return smallest;
}
void example(void)
{
printf ("smallest width= %d\n", smallestX(pages, offsetof(struct page, width)));
printf ("smallest length= %d\n", smallestX(pages, offsetof(struct page, length)));
}
Clarification:
It uses the offsetof macro to get the offset of the member from the beginning of the struct. In the function, it now takes the address of the ith element of the array, interprets that as a byte address, adds the offset (which is in bytes), interprets that as a pointer to an int, dereferences that int and uses it in the compare.
Note: it is possible to extend this method to compare any item by providing a compare function as parameter.
im trying to make a procedure to find a maximum numbers out of 3, which i will assign later to another variable pointer in main program
int Maximum (int *a, int *b, int *c)
{
if (*a>=*b)
{
if (*a<*c)
{*a=*c;}
}
else
{
*a=*b;
if (*a<*c)
{*a=*c;}
}
return a;
}
compiler giving me error that "expected 'int*' but argument is of type 'int' "
so i changes that part to
int * Maximum (int *a, int *b, int *c)
but error sentence still same ?
First off, your original function is designed to return an int and you're returning a, which is an int pointer. Either return the int (*a), or change the function so it returns an int *.
However, based on your actual message:
expected 'int*' but argument is of type 'int'
and the fact you state you've made that change and still have the problem (note the word "argument" in the message), this indicates that the problem lies not with the return value but with the way you're passing the arguments to it.
You are actually passing int where the function expects int * and that's probably caused by you using something like:
int one = 3;
int two = 7;
int three = 42;
int maxOfThree = Maximum (one, two, three);
If you wanted to pass pointers to the function, you would need:
Maximum (&one, &two, &three);
(passing the pointers to the variables, not the values of them).
A better solution (more readable and with correct data types both going in to, and coming out of, the function) to your problem would probably be:
int Maximum (int a, int b, int c) {
if ((a > b) && (a > c))
return a;
if (b > c)
return b;
return c;
}
When I try to compile the following line
int* x[](), (*y)();
I get the error "x declared as an array of functions of type int()"
You cannot really declare an array of functions, but you can have an array of function pointers, which will probably give you the same effect, because you can invoke them without explicit dereferencing.
The following will declare an array of 5 function pointers which return int*.
int* (*x[5])();
The website cdecl will let you play with various pointer declarations to see what they mean in English.
Here is the golden rule for reading C declarations, stolen from this old article.
Start at the variable name (or innermost construct if no identifier is
present. Look right without jumping over a right parenthesis; say what
you see. Look left again without jumping over a parenthesis; say what
you see. Jump out a level of parentheses if any. Look right; say what
you see. Look left; say what you see. Continue in this manner until
you say the variable type or return type.
When applied to the declaration above, we say:
x is an array of 5 pointers to functions returning pointer to int.
As SteveCox correctly commented below, we note that if we run into a type qualifier on the left hand side when following the above rule, it will describe the type to its left rather than its right. For example, the following declaration declares an array of 5 pointers to functions returning const pointer to int, not pointer to const int.
int* const (*x[5])();
Try this for an array of 2 function pointers.
#include <stdio.h>
int *first(void) { return NULL; }
int *second(void) { return NULL; }
int main(void) {
int *(*fx[2])(void);
fx[0] = first;
fx[1] = second;
/* ... */
if (fx[0]() == fx[1]()) {
printf("Calling both functions returns the same value.\n");
}
return 0;
}
A practical application might look like:
#include <ansi_c.h>
int add_(int, int);
int sub_(int, int);
int mul_(int, int);
int div_(int, int);
enum {
ADD,
SUB,
MUL,
DIV
};
int (*mathOps[4])(int, int);
int main(void)
{
int i;
mathOps[ADD]=add_;
mathOps[SUB]=sub_;
mathOps[MUL]=mul_;
mathOps[DIV]=div_;
for(i=ADD;i<=DIV;i++)
{
printf("results are: %d\n", mathOps[i](3, 3));
}
getchar();
return 0;
}
int add_(int a, int b)
{
return a + b;
}
int sub_(int a, int b)
{
return a - b;
}
int mul_(int a, int b)
{
return a * b;
}
int div_(int a, int b)
{
return a / b;
}
I am trying to use the inbuilt qsort function in C to sort a structure
typedef struct abc{
long long int fir;
long long int sec;
}abc;
In the compare function I used the below code so that if the variable "fir" is same between any two elements in the array of structure abc then the sorting condition will depend on the variable "sec".
long long int cmp(const abc* e1, const abc* e2)
{
if(e1->fir==e2->fir)
return e1->sec-e2->sec;
else
return e1->fir-e2->fir;
}
The code doesn't seem to work properly.
What is the correct method to do it?
long long int cmp(const abc* e1, const abc* e2)
does not have the correct signature for a qsort comparison function, so your program has undefined behavior. You should set your compiler warning flags high, and it will warn you of such things.
Your actual test is fine as long as the subtraction can't overflow, which is probably not a problem for long long. Edit The subtraction is not fine here, precisely because the return value of cmp must be an int. The result of the subtraction long long, so if you have large values the result is too big to fit into an int and qsort is sure to produce the wrong order.
More generally, though, this is more accurate:
int cmp(const void* v1, const void* v2)
{
const struct abc* p1 = v1;
const struct abc* p2 = v2;
if (p1->fir < p2->fir)
return -1;
else if (p1->fir > p2->fir)
return 1;
else
return p1->sec < p2->sec? -1 : p1->sec > p2->sec? 1 : 0;
}
The built-in qsort you're using probably expects a "lower-than" (operator<) predicate, which is the normal terminology for C++. And yours returns true in both cases as long as the arguments aren't equal.
You have to return true IFF (if and only if) e1<e2.