I have a struct in C like this:
typedef struct proces {
char ime[60];
char pid[60];
char ppid[60];
char stanje;
int stdat;
char niti[60];
char poraba[60];
} proces ;
I create about 100 of them and put them into an array
proces** procesi = malloc(sizeof(proces));
int x;
for(x=0; x<st; x++){
procesi[x] = (struct proces*)malloc(sizeof(proces));
}
Now I would like to sort them with qsort. But the qsort sorts it wrong.
The function looks like this:
int compar_ppid(const void *v1, const void *v2){
const proces *p1 = (proces*)v1;
const proces *p2 = (proces*)v2;
return(strcmp(p1->ppid, p2->ppid));
}
I checked the values that the compar_ppid is comparing and they seem to be something like �#d, when they should be numbers.
I guess I'm accessing the pointer and not the value, but I cant figure out what to change to get the right values.
Qsort call:
qsort(procesi, st, sizeof(proces*), compar_name);
The array you sort contains pointers to process, so your compare function should look like:
int compar_ppid(const void * v1, const void * v2)
{
process *const*p1 = v1, *const*p2 = v2;
return strcmp((*p1)->ppid, (*p2)->ppid);
}
and as BLUEPIXY points out the allocation of the array is not using the pointer size, but the struct size.
Related
How can I find out the number of comparison operations for a qsort?
I have an array of pointers that should be sorted.
This array of pointers points to an array of structures.
struct oristru {
char string1[TITLE_FIELDLENGTH];
char string2[AUTHORS_FIELDLENGTH];
short int 1;
};
const struct oristru oristrukts[] = { ...}
const struct oristru *temp_oristru[ARRAYLEN(oristrukts)];
struct oristru *p_sortst[ARRAYLEN(oristrukts)];
qsort(*p_sortst, ..);
Supposing you're sorting with function fx()
qsort(..., fx);
just tweak fx()
// global var to count comparisons
unsigned long ncomp = 0;
int fx(const void *a, const void *b) {
ncomp++;
/* return ...; */
}
I have a struct and want to sort an array of the struct using merge sort.
I need to pass the sorting parameter to the merge function and access the struct members.
Can this be done in C?
example:
struct movie_imdb_data {
char color[15];
char director_name[100];
int num_critic_for_reviews;
int duration; /// in min not date and time
int director_facebook_likes;
int actor_3_facebook_likes;
char actor_2_name[100];
int actor_1_facebook_likes;
int gross;
};
in the main function, I have:
if (argc > 2) {
column_sort = argv[2];
}
now I want to call merge_sort(<array of struct>, <column_sort *>)
can I access the member in the array as array[0]->column_sort to compare?
now I want to call merge sort and pass the
I want to pass the array and the sorting parameter (that I need the array sorted by) can I use a variable in place of a members name ie..
arr[1].column_sort
instead of
arr[1].color
Sounds like you want to take a command line argument specifying the name of the field to sort on and then sort on that field.
For that, try code like:
#include <stdlib.h>
#include <string.h>
/* compare function for field 3: "num_critic_for_reviews" */
int compField3(const void *a, const void *b)
{
struct movie_imdb_data* aStruct = (struct movie_imdb_data*)a;
struct movie_imdb_data* bStruct = (struct movie_imdb_data*)b;
return (aStruct->num_critic_for_reviews < bStruct->num_critic_for_reviews)?
-1: (aStruct->num_critic_for_reviews > bStruct->num_critic_for_reviews)?
+1: 0;
}
/* also define other compare functions for each field */
int main()
{
const char* columnName = argv[2];
struct movie_imdb_data* parray;
parray = your-array;
int (*comp)(const void *, const void *, void *) = 0;
/* map the column name to compare function for that column */
if (strcmp(columnName, "num_critic_for_reviews") == 0)
{
comp = compField3;
}
/* map other names to compare function for column */
else if (...) {...}
else { exit(1); /* if not recognized column name */ }
qsort(parray, numElementsOfArray, sizeof(struct movie_imdb_data), comp);
...
}
Hope this helps!
There are different approaches to your problem:
you can write separate functions to compare structures on specific fields. In main, you would select the appropriate comparison function by testing the name of the field (or possibly generic names that are not field names). You would then pass this comparison function to mergesort (or qsort...).
if all members have the same type, you could determine the offset of the field from the beginning of the structure with macros offsetof(type, member). There is no generic way to compute these offsets, you need to write a series of tests or use a table. The comparison function would use casts to access the members:
size_t member_offset = offsetof(struct movie_imdb_data, duration);
int comp_int_member(const void *a1, const void *a2) {
const int *p1 = (const int *)((const unsigned char*)a1 + member_offset);
const int *p2 = (const int *)((const unsigned char*)a2 + member_offset);
return (*p1 > *p2) - (*p1 < *p2);
}
The downside of this latter approach is it can only handle fields with a given type.
I am trying to sort an array of pointers to structs (definition below) based on the value stored in the void* of the "bucket" struct that I know are ints. It compiles and prints out my array of buckets and their values just fine with no errors or warnings but it isn't actually sorting the array. I have used asserts to try to find anywhere that could cause an error with qsort.
Struct definitions:
typedef struct _bucket{
void* val;
char *word;
}bucket;
typedef struct _root{
bucket **list;
int hashTableLength;
}root;
Sort Function to be passed to the qsort function:
int sortFunc(const void *a, const void *b){
bucket *bucketA=(bucket*)a;
bucket *bucketB=(bucket*)b;
int bucketAVal = *((int*)bucketA->val);
int bucketBVal = *((int*)bucketB->val);
assert((bucketAVal&&bucketBVal)!=0);
return bucketAVal-bucketBVal;
}
Sort the array and print:
void sort(root* inRoot, int(*sortFunc)(const void *a, const void *b)){
int length = inRoot->hashTableLength;
assert(length==11); //known length of hash array
for (int i = 0; i<length; i++)
assert(inRoot->list[i] != NULL);
qsort(inRoot->list, length, sizeof(bucket*), sortFunc);
for(int i =0; i<length; i++)
printf("%s was found %d times\n", inRoot->list[i]->word, *((int*)(inRoot->list[i]->val)));
return;
}
The compare function sortFunc() receives a pointer to each object. The array inRoot->list is an array of bucket * so sortFunc() is receiving pointers to bucket *: bucket **.
Also the int subtraction is subject to possible overflow. Use the idiomatic 2 compares to solved that.
int sortFunc(const void *a, const void *b) {
bucket **bucketA = (bucket**) a;
bucket **bucketB = (bucket**) b;
void *vA = (*bucketA)->val;
void *vB = (*bucketB)->val;
int iA = *((int*) vA);
int iB = *((int*) vB);
return (iA > iB) - (iA < iB);
}
I'm a newbie with C language and I need to make a function to sort an array of struct Student data types (after the element Student.ime alphabetically). I am not really sure where to put the pointers so I can return the new array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
int id;
char ime[20];
char prezime[20];
char brindexa[20];
struct Datum datum_rodjenja;
};
struct Student sortiraj(struct Student niz[], int vel)
{
int i, j;
struct Student tempo;
tempo = niz[0];
for(j=0 ; j<vel ; j++)
{
for(i=j ; i<vel ; i++)
{
if(strcmp(tempo.ime,niz[i].ime)>0)
{
tempo = niz[i];
}
i++;
}
niz[j] = tempo;
j++;
}
return niz;
}
The array is stored in a .txt file but that is not the problem. One more thing, how do I call the function in the main(). I thought maybe like this?
niz=sortiraj(niz, vel);
Can someone give me any tips please. Thank you.
You seem to be sorting the array in-place, so you don't really need to return it at all. Also, use the standard library function qsort():
int cmp(const void *ap, const void *bp)
{
const struct Student *a = ap, *b = bp;
return strcmp(a->ime, b->ime);
}
struct Student students[] = { /* whatever */ };
qsort(
students,
sizeof(students) / sizeof(studends[0]),
sizeof(students[0]),
cmp
);
Also, please use English function and variable names.
Have you considered using the qsort() function? Example:
If you have an array of strings say strings, (Note: not an array of structs), with the number of strings being say, cnt then:
qsort(strings, cnt, sizeof(char*), sortstring);
With the function sortstring defined as:
static int sortstring( const void *str1, const void *str2 )
{
const char *rec1 = *(const char**)str1;
const char *rec2 = *(const char**)str2;
int val = strcmp(rec1, rec2);
return val;
}
//for a simple test, run this main with the code above:
int main(void)
{
char *strings[]={"this", "is", "a", "test", "of", "the", "qsort", "function", "to", "try"};
int strlen = sizeof(strings)/sizeof(char *);
qsort(strings, strlen, sizeof(char *), sortstring);
return 0;
}
//Note my environment required #include <ansi_c.h>
First of all, your function signature is not marked return type as an Array of Students. Second of all, I don't know which sorting algorithm you're trying to use, but your implementation isn't right.
If you correct your function signature, you shouldn't get any error by the way you're calling the:
struct Student* sortiraj(struct Student niz[], int vel)
tips about your sortiraj: Check either selection sort or bubble sort for your sort algorithm. And for further study, you can check some recursive algorithms like merge sort and quick sort which are more advance and you need more programming knowledge to implement them.
Change the return type of function sortiraj to void.
Create and fill the struct Student niz[] array in function main.
From function main, pass the array and its length (vel) to function sortiraj.
And of course, no need to return anything from function sortiraj (as implied in section 1).
Since you are passing in a pointer, namely niz, you are changing the memory that niz points to. This means that you don't have to return niz.
However if you want to return niz your function's return type must be the same type as niz. Currently you have a return type of just struct Student so you should be getting a compilation error.
I am trying to sort a struct run array called results by a char, but when I print the array, nothing is sorted. Have a look at this:
struct run {
char name[20], weekday[4], month[10];
(And some more...)
};
typedef struct run run;
int name_compare(const void *a, const void *b)
{
run *run1 = *(run **)a;
run *run2 = *(run **)b;
return strcmp(run1->name, run2->name);
}
int count_number_of_different_persons(run results[])
{
int i = 0;
qsort(results, sizeof(results) / sizeof(run), sizeof(run), name_compare);
for(i = 0; i <= 999; i++)
{
printf("%s\n", results[i].name);
}
// not done with this function yet, just return 0
return 0;
}
The output from the above is just a list of names in the order they were originally placed
int count_number_of_different_persons(run results[])
This doesn't really let you use sizeof on the array, because array is decayed to pointer.
This
run *run1 = *(run **)a;
also looks weird, shouldn't it be
run *run1 = (run*)a;
?
One problem is in name_compare. Try this instead:
int name_compare(const void *a, const void *b)
{
run *run1 = (run *)a;
run *run2 = (run *)b;
return strcmp(run1->name, run2->name);
}
Check the following code:
As #michel mentioned, sizeof(array) provides size of the pointer, not the size of the array itself, as while passing array it is treated as a pointer. Hence either send the number of elements to the function count_number_of_different_persons or define a MACRO of number of elements. Hope this helps. :).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NOE 3
struct run
{
char name[20];
};
typedef struct run run;
int name_compare (const void *a, const void *b )
{
return strcmp (((run *)a)->name, ((run *)b)->name);
}
int count_number_of_different_persons(run results[], int noOfElements)
{
int i=0;
qsort(results, noOfElements, sizeof (run), name_compare);
for (i=0; i<noOfElements; i++)
printf ("%s\n",results[i].name);
}
int main ( int argc, char * argv[])
{
run a, b, c;
run arg[NOE];
strcpy (a.name, "love");
strcpy (b.name, "you");
strcpy (c.name, "i");
arg[0] = a;
arg[1] = b;
arg[2] = c;
count_number_of_different_persons(arg, sizeof(arg)/sizeof(run));
};