This is the data type that I declared:
struct Element{
char name[21], symbol[4];
double atomicMass;
int valence;
};
typedef struct Element myElements;
myElements data[20];
If I just want to pass the name members of
data[20]
to qsort(), how to do that?
Not sure if this would be the correct way to pass to the function:
qsort(data->name, 20, sizeof(myElements), compare);
You don't pass just member. Right way is to write a helper compare function which compares 2 elements by their name and use it.
static int
cmpElement(const void *p1, const void *p2)
{
return strcmp(((const Element *) p1)->name, ((const Element *) p2)->name);
}
qsort(data, 20, sizeof data[0], cmpElement);
Related
I am trying to pass pointer to an array of structures to another function
#include<stdio.h>
#include<string.h>
typedef struct CovidData{
char region[7];
char towns[12];
char race[12];
int yearlyIncome;
int members;
int testedMembers;
int testedPositive;
} CovidData;
void RandomDataGenerator(CovidData *data[] ,int count)
{
for(int i=0;i<count;i++){
memcpy(data[i]->region,"david",sizeof("david"));
memcpy(data[i]->towns,"david",sizeof("david"));
memcpy(data[i]->race,"david",sizeof("david"));
data[i]->yearlyIncome=1000;
data[i]->members=99;
data[i]->testedMembers=88;
data[i]->testedPositive=656;
}
}
int main() {
struct CovidData data[100];
RandomDataGenerator(&data,2);
for(int i=0;i<5;i++){
printf("%s",data[i].region);
}
}
But it throws an error while compiling in terminal with gcc
incompatible pointer types passing 'CovidData (*)[100]' to
parameter of type 'CovidData
CovidData *data[] is grouped as CovidData *(data[]), so it declares an array of pointers to CovidData. For a pointer to an array, you would use CovidData (*data)[].
However, we rarely pass a pointer to an array. Usually, it is sufficient and convenient merely to pass a pointer to the first element. Thus, you would declare the parameter as CovidData *data and pass it as RandomDataGenerator(data, 2).
If you did declare the parameter as a pointer to an array, you would not use it with data[i]->region. You would need *data to get the array before applying the subscript, and again you would need parentheses for correct grouping: (*data)[i]->region.
Change your function to void RandomDataGenerator(CovidData *data ,int count); and pass only the pointer to the first array element, like this RandomDataGenerator(data,2);
#include<stdio.h>
#include<string.h>
typedef struct CovidData{
char region[7];
char towns[12];
char race[12];
int yearlyIncome;
int members;
int testedMembers;
int testedPositive;
} CovidData;
void RandomDataGenerator(CovidData *data ,int count)
{
for(int i=0;i<count;i++){
memcpy(data[i].region,"david",sizeof("david"));
memcpy(data[i].towns,"david",sizeof("david"));
memcpy(data[i].race,"david",sizeof("david"));
(data+i)->yearlyIncome=1000;
data[i].members=99;
data[i].testedMembers=88;
data[i].testedPositive=656;
}
}
int main() {
struct CovidData data[100];
RandomDataGenerator(data,2);
for(int i=0;i<5;i++){
printf("%s\n",data[i].region);
}
}
I want to use sizeof operator after passing an array to a function but C language is considering it as pointer not an array.
Can we implement a functionality to solve this purpose ?
void foo(char array[])
{
printf("sizeof array = %u\n", sizeof(array)); /* I know array is pointer here */
}
int main(void)
{
int array[5];
foo(array);
}
Not possible and using an array subscript [] can be confusing to people not knowing that it will behave as a pointer. The approach that I take is to pass length as another argument or create a struct with pointer and length:
struct {
char * buffer;
size_t length;
} buffer_t;
I don't like the array in the struct or typedef approach as it restricts the data to a fixed size.
You can't ask the compiler for that. It is not polite to do what you ask it to.
Instead you can add another parameter to your function definition to recieve the size of the array.
void foo(char array[], size_t array_size)
{
printf("sizeof array = %zu\n", array_size);
}
int main(void)
{
int array[5];
foo(array, sizeof(array)) ;
}
Note: to print size_t use %zu in printf.
Note: to print number of elements, use: sizeof(array) / sizeof(*array)
You can use a dedicated typedef, or as said in a remark an embedding struct :
#include <stdio.h>
typedef char A5[5];
typedef struct S {
char a[5];
} S;
void foo(A5 a) /* of course can be "void foo(char a[])" but less clear */
{
printf("%zu %zu\n", sizeof(A5), sizeof(a));
}
void bar(S s)
{
printf("%zu\n", sizeof(s.a));
}
int main()
{
A5 a;
S s;
foo(a);
bar(s);
}
Of course in case of the typedef you need to use typeof on it rather than on the var being a char*
But all of that is a kind of hack, C is C ...
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 have the following structs. A tDiscountsShop contains, let's say 5 tDiscount structs.
#define MAXDISCOUNTS 50
typedef enum {FALSE, TRUE} bool;
typedef struct {
int dni;
float discount;
bool changed;
} tDiscount;
typedef struct {
tDiscount discounts[MAXDISCOUNTS];
int numDiscounts;
} tDiscountsShop;
I would like to sort by dni using qsort. I'm trying using the following code:
int compare(const void *s1, const void *s2)
{
tDiscount *e1 = (tDiscount *)s1;
tDiscount *e2 = (tDiscount *)s2;
return e1->dni - e2->dni;
}
qsort (discountsShop->discounts, discountsShop->numDiscounts, sizeof(discountsShop->discounts), compare);
I'll appreciate if I could have an explanation of what I'm doing wrong and how I could solve this issue. Thanks in advance.
This
sizeof(discountsShop->discounts)
gives you the size of the whole array.
What you need/want is the size of one element.
To get this do
sizeof(*discountsShop->discounts)
or
sizeof(discountsShop->discounts[0])
From qsort()'s documentation:
void qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *, const void *));
[...]
The size of each object, in bytes, is specified by the width argument.
You are passing the size of the whole array instead of the size of each element.
sizeof(discountsShop->discounts)
should be
sizeof(discountsShop->discounts[0])
I need to know if i want to make an array that every element of the array is a pointer to a linked list and pass the array to a function, the function is void because I need to change the array
typedef struct n{
char *S;
int num;
}list;
int (main){
list *Array[50];
return 0;
}
should the function be void changeArray(list A[]); or void changeArray(list *A[]); or void changeArray(list **A[]);
The function could be either void changeArray(list *A[]) or void changeArray(list **A). Both signatures would accept an array of pointers, and let you change elements of that array:
void changeArray(list *A[]) {
...
A[0] = malloc(list);
}
The array is defined like
list *Array[50];
So if you want to pass this array to a function then it should be declared like
void changeArray( list *Array[50], size_t n );
or
void changeArray( list *Array[], size_t n );
or
void changeArray( list **Array, size_t n );
and called like
changeArray( Array, 50 );
In any case a declaration of an array as a function parameter is adjusted to a pointer to object of the type of elements of the array.