qsort an array of structs in a struct - c

I'm attempting to sort an array of structs in a struct based on an int value. I've successfully sorted an array of structs but I'm guessing I'm passing a wrong value somewhere for the nested structs.
I just need the structs in the array sorted the value of a.
The structs are set up as:
struct s2{
int a;
int b;
};
struct s1{
int c;
struct s2 arr[10];
}
I have a compare function:
int comp(const void *a, const void *b){
struct s1 *q1 = (struct s1 *)a;
struct s1 *q2 = (struct s1 *)b;
return(q1->arr->a - q2->arr->a);
}
And I call qsort:
struct s1 myStruct;
size_t theLen = sizeof(myStruct.arr) / sizeof(struct s2);
qsort(myStruct.arr, 10, theLen, comp);
For the input:
10, 5, 7, 20, 17, 9, 3, 11, 15, 1
I get output:
2147451181, 589824, 327680, 65536, 131072, 4, 5, 11, 15, 8
I'm guessing it may be something to do with how I declare the length?
Thanks!
The file line is:
10 5 7 20 17 9 3 11 15 1
myStruct.arr[i].a is filled from file input using fgets and sscanf:
fgets(t, sizeof(t), fp);
sscanf(t, "%d,...,%d", &myStruct.arr[0].a,...,&myStruct.arr[9].a);
myStruct.arr[i].b is filled with a for loop:
for(int i = 0; i < 10; i++){
myStruct.arr[i].b = i+1;
}

There are two mistakes with your code
You are using q1->arr->a to compare where you should use q1->a (where q1 is of type const struct s2). This has also been explained by #GauravSehgal in his answer
If you look at the third argument to qsort, it is acutally the size of each element to compare in bytes. But you have passed the number of elements. Change your call to -
qsort(myStruct.arr, 10, sizeof(struct s2), comp);
and you should get the desired result.
There are some other points you need to take care of (pointed out by #Stargateur) -
Declare q1 and q2 to be of type const struct s2*, because you do not want to discard the const qualifier.
Do not cast a and b explicitly while assigning to q1 and q2 because they are of type const void* which auto-promotes to pointer of any const type.

qsort(myStruct.arr, 10, theLen, comp);
You are sorting myStruct.arr here where each element is of type struct s2.So your compare should be
int comp(const void *a, const void *b){
struct s2 *q1 = (struct s2 *)a;
struct s2 *q2 = (struct s2 *)b;
return(q1->a - q2->a);
}
EDIT: the third parameter to qsort is the size of each element of array to be sorted.So it should be
qsort(myStruct.arr, theLen, sizeof(struct s2), comp);

Related

Invalid use of flexible array member error

typedef struct {
void *end;
void *start;
int size;
int arrs [];
} st;
void *doStuff(void *starter, void *ender) {
st *s = (st *) malloc(sizeof(st));
s->end = ender;
s->start = starter;
int sayz = 1;
s->size = (int) (ender - starter);
int a [s->size];
memset(a, 0, sizeof a);
s->arrs = a; // This line gives error
return s;
}
the line "st->arrs = a;" gives me the "Invalid use of flexible array member" error. Does anybody know how I can save an array inside a structure? The language is C
This is what you want, assuming starter and ender point to char objects. I've also cleaned up your indenting and formatting.
typedef struct {
void *end;
void *start;
ptrdiff_t size; // Note that a diff of pointers should be a ptrdiff_t
int arrs[];
} st;
st *doStuff(void *starter, void *ender) {
ptrdiff_t size = (char*)ender - (char*)starter; // Calculate size first so it's available to use in malloc
st *s = malloc(size + sizeof st);
s->end = ender;
s->start = starter;
s->size = size;
memset(s->arrs, 0, size * sizeof s->arrs[0]); // since array is allocated, no need to create a redundant array
return s;
}
A flexible array member is not a pointer; you do not assign an address or an array to it. You allocate space for it as part of the space you allocate for the structure, and then you use it like an array. Change st *s = (st *) malloc(sizeof(st)); to st *s = malloc(sizeof *s + N * sizeof *s->arrs);, where N is the number of elements you want for the array.
Then you can initialize the array to zero with memset(s->arrs, 0, N * sizeof *s->arrs);.
Note that ender - starter is not proper C code. The type of ender and starter is void *, and the C standard does not define the behavior of subtracting pointers to void. GCC does, but this gives you a number of bytes, not, in general, a number of array elements. To subtract ender and starter properly, use (T *) ender - (T *) starter, where T is the type of object they point to.

without passing arguments how compare funcation work

I want to sort struct array but while understand the logic of compare function i stuck my confusion is how compare function is work when it call in qsort() function without passing argument
Using GCC on Code Block on windows:
Code
int compare(const void * a, const void * b);
struct cricketers
{
int avrun;
char name[30];
int age;
int notm;
}india[Max] = {
122, "Sachin Tendulkar", 30, 67,
97, "Virendra Sehwag", 35, 56,
66, "Irfan Pathan", 32, 45,
153, "Yusuf Pathan", 36, 21,
101, "Yuvaraj Singh", 32, 45,
};
int main()
{
int i;
qsort(india, 5, sizeof(struct cricketers), compare);
for (i = 0; i < 5; i++)
{
printf("Name : %s", india[i].name);
printf("\nAge : %d", india[i].age);
printf("\nTotal Test Matches played : %d", india[i].notm);
printf("\nAverage Run : %d\n\n\n", india[i].avrun);
}
_getch();
return 0;
}
int compare(const void * a, const void * b)
{
return (*(int*)a - *(int*)b);
}
It is the function qsort that internally calls the comparison function passing to it void pointers to two elements of the array.
According to the C Standard (6.7.2.1 Structure and union specifiers) the address of the first member of a structure is equal to the address of the whole object of the structure type.
15 Within a structure object, the non-bit-field members and the units
in which bit-fields reside have addresses that increase in the order
in which they are declared. A pointer to a structure object,
suitably converted, points to its initial member (or if that member is
a bit-field, then to the unit in which it resides), and vice versa.
There may be unnamed padding within a structure object, but not at its
beginning.
So the value for example of the parameter a casted to the type int * yields the address of the data member int avrun of the structure.
Nevertheless this expression (*(int*)a - *(int*)b) can invoke undefined behavior due to overfloating of signed integers.
I would write the comparison function the following way.
int compare( const void *a, const void *b )
{
const struct cricketers *left = ( const struct cricketers * )a;
const struct cricketers *right = ( const struct cricketers * )b;
return ( right->avrun < left->avrun ) - ( left->avrun < right->avrun );
}

struct intitialization notation not working with heap allocated storage

With gcc (GCC) 4.4.6 , I try to compile this program -
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc, char *argv[])
5 {
6
7 struct B {
8 int i;
9 char ch;
10 };
11
12 struct B *ptr;
13
14 ptr = (struct B*) calloc(1, sizeof(struct B));
15
16 *ptr = {
17 .i = 10,
18 .ch = 'c',
19 };
20
21 printf("%d,%c\n", ptr->i, ptr->ch);
22
23 return 0;
24 }
25
$ make
gcc -g -Wall -o test test.c
test.c: In function ‘main’:
test.c:16: error: expected expression before ‘{’ token
make: *** [test] Error 1
"Struct initialization notation" you are talking about uses the term "initialization" for a reason: it is intended to be used in initialization contexts. What you are trying to do is not initialization at all. It is assignment. This syntax will not immediately work in assignment contexts.
In order to still make use of this convenient syntax you have to create another struct of the same type, initialize it using this syntax, and then copy that struct to your struct by using assignment. For example
ptr = calloc(1, sizeof *ptr);
const struct B INIT = {
.i = 10,
.ch = 'c',
};
*ptr = INIT;
This already achieves what you are trying to do, but you can make the above more compact by using the compound literal feature of C language
ptr = calloc(1, sizeof *ptr);
*ptr = (struct B) {
.i = 10,
.ch = 'c',
};
Basically, the latter code sample is probably what you are looking for. However, note that conceptually this is still not initialization. It is an assignment, which creates a temporary object of type struct B and then assigns it to your *ptr object.
*ptr = {
.i = 10,
.ch = 'c',
};
This usage is called designated initializer, as the name implies, it's only used to initialize struct or arrays, but what you are trying to do is assigning.
The correct usage of designated initializer:
strcut B foo = {.i = 10, .ch = 'c'};
To assign the struct, you still need to use:
ptr->i = 10;
ptr->ch = 'c';
EDIT: Or you can use a compound literal like in #Andrey T's answer:
*ptr = (struct B) {
.i = 10,
.ch = 'c',
};
If you want to initialize (allocate a value to) a dynamically allocated structure, you will need to use a C99 compound literal on the RHS of the assignment:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
struct B { int i; char ch; };
struct B *ptr = (struct B*) calloc(1, sizeof(struct B));
*ptr = (struct B){ .i = 10, .ch = 'c', };
printf("%d,%c\n", ptr->i, ptr->ch);
return 0;
}
The notation uses a cast and an initializer instead of just an initializer.
In a structure initializer, specify the name of a field to initialize with ‘.fieldname =’ before the element value. For example, given the following structure,
struct point { int x, y; };
the following initialization
struct point p = { .y = value1, .x = value2};
is equivalent to
struct point p = { value1, value2};
Another syntax that has the same meaning,‘fieldname:’, as shown here:
struct point p = { y: value2, x: value1};
The ‘[index]’ or ‘.fieldname’ is known as a designator. Below code will work. For pointer YU Hao has told..
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
struct B {
int i;
char ch;
} ;
struct B name = {
.i = 10,
.ch = 'c',
};
printf("%d,%c\n", name.i, name.ch);
return 0;
}
*ptr = {
.i = 10,
.ch = 'c',
};
This usage is called designated initializer and is used only while initialisation not for assignment. As far as i know its not for a pointer, as only 4 bytes are allocated for any pointer.

How do C functions like qsort work with different datatypes?

In stdlib.h, there is a declaration of the function qsort() with prototype:
void qsort( void *ptr, size_t count, size_t size,
int (*comp)(const void *, const void *) );
Obviously it is a generic programming.
I wonder how it implement, how to get the element from the void * type?
void * pointers are casted according to the size_t size (the 3rd argument in qsort)
First we typecast the void* to char* and then do pointer arithmetic according to the size (because char takes 1 byte so adding the size will give correct pointer arithmetic )
EDIT : (for in built data types)
char *ptr = (char*)vp; //here vp is void *p
*(ptr + (n-1)*size); //will give you nth element
e.g.
size =1 and want 3rd element it means it will give you 3rd char
size =4 and want 3rd element it means it will give you 3rd int or float
size =2 and want 3rd element it means it will give you 3rd short int
size =8 and want 3rd element it means it will give you 3rd double
NOTE : size is implementation defined so it may vary to compilers
#include <stdio.h>
void compare_first_to_rest(void *ptr, size_t nelem,
size_t size, int (*cmp)(const void*, const void*)) {
unsigned i;
for(i = 1; i < nelem; ++i)
{
int res = cmp(ptr, (char*)ptr + i * size);
if(res < 0)
printf("First element is less than element at %u\n", i);
else if(res > 0)
printf("First element is greater than element at %u\n", i);
else
printf("First element is equal to element at %u\n", i);
}
}
int icmp(const void *x, const void *y) {
return *(int*)x - *(int*)y;
}
int main()
{
int x[] = { 5, 3, 6, 2, 4, 8, -1, 10 };
compare_first_to_rest(x, 8, sizeof(int), icmp);
}
As you can see, `compare_first_to_rest' doesn't know about the type of the elements it receives in its first argument. But knowing the size of each one, it can get a pointer to every one of them, and let the function pointer do the job.
The last parameter is a function pointer. As you implicitly mentioned You must have implemented this function somewhere.
But as you implement it, you do know what king of pointer is actually your void* element.
In your comp function, you have to cast your 2 parameters into the pointer type you want to work with, as below:
int myCompFn(const void * e1, const void * e2)
{
MyType *elem1=(MyType*)e1;
MyType *elem2=(MyType*)e2;
... /* then compare elem1 and elem2 regarding to there definition */
}

Ansi C - function expecting pointer to array

im writting program in ANSI C, and and have one function, where im passing pointer to semaphores array struct sembuf semb[5].
Now header of that function looks like:
void setOperations(struct sembuf * op[5], int nr, int oper)
But im getting warning:
safe.c:20: note: expected ‘struct sembuf **’ but argument is of type ‘struct sembuf (*)[5]’
How to solve that problem?
Edit
Calling:
setOperations(&semb, prawa, -1);
This is how the function should be declared if you want to pass a pointer to an array and not an array of pointers:
void setOperations(struct sembuf (*op)[5], int nr, int oper);
Your current declaration (struct sembuf * op[5]) means an array of 5 pointers to struct sembuf.
Arrays are passed as pointer anyway, so in the header you need: struct sembuf op[5].
A pointer to the array will be passed anyway. No array will be copied.
Alternative way of declaring this argument would be struct sembuf *op, which is a pointer to struct sembuf.
You maybe over complicating this...
If you want to pass an array of structures, it's really no different than passing any array of anythings. Once you have the array, getting the address is simple, let me give you a quick example:
Let's say you have this struct:
typedef struct s {
int a;
int b;
} mys;
If you want to declare it statically in your main() you can do:
int main(int argc, char *argv[])
{
mys local[3];
memset(local, 0, sizeof(mys)*3); // Now we have an array of structs, values are
// initialized to zero.
// as a sanity check let's print the address of our array:
printf("my array is at address: %#x\n", local);
changeit(local, 3); // now we'll pass the array to our function to change it
Now we can have our function that accepts the array and changes the values:
void changeit(mys remote[], int size)
{
int count;
printf("my remote array is at address: %#x\n", remote); //sanity check
for(count = 0; count < size; count++) {
remote[count].a = count;
remote[count].b = count + size;
}
}
Once that returns we can print the values from main() with some other loop like:
for(int count = 0; count < 3; count ++)
printf("struct[%d].a = %d\n struct[%d].b = %d\n",
count, local[count].a, count, local[count].b);
And we'll get some output that looks like:
>> ./a.out
my array is at address: 0xbf913ac4
my remote array is at address: 0xbf913ac4
struct[0].a = 0
struct[0].b = 3
struct[1].a = 1
struct[1].b = 4
struct[2].a = 2
struct[2].b = 5
So you can see it's the same array (same address) and that's how you get the array of structs to the other function. Did that clear it up?

Resources