I am very new to c programming. I have written the fallowing code
float value; //golbal variable
unsigned int data; //golbal variable
void Maxphase(void)
{
float MAX = 0.0;
unsigned int i,index;
for (i=0;i<=360;i++)
{
phaseset(i);
data = readvalue();
value = voltage(data);
if(value>MAX) //find max value
{
MAX = value; //max voltage
index = i;
}
}
printf("Max Voltage Value:%f\r\n", MAX);
printf("Related index Value:%d\r\n", index);
}
the above code working perfectly and printing maximum voltage and index. I want return both values "Max" and "index" from this function and I have to save Max value in one variable and index value in other variable like.
void runCom(void){
c=getchar();
switch(c){
case '1':
Maxphase();
Vin= (I want to store MAX value of that function)
p1= ( I want to store Index of that function)
break;
default:
break;
}
}
Actually I want call that function and it has to return two variables MAX and index value, thus I want to store those two values in different variables.
I know function can't return two values.
I have searched, i found it is possible with a struct or make the function to handle the arguments with pointers. I tried with struct as shown below.
typedef struct {
float v;
unsigned int p;
}volphase;
I have declared this struct in header file. I am including this header file in all files where i am calling.
volphase Maxphase()
{
volphase vp;
float MAX = 0.0;
unsigned int i,index;
for (i=0;i<=360;i++)
{
phaseset(i);
data = readvalue();
value = voltage(data);
if(value>MAX) //find max value
{
MAX = value; //max voltage
index = i;
}
}
vp.v=MAX;
vp.p=index;
return vp;
}
This is written in "bvr.c" file.
But I am thinking how to call this "struct" in case'1'(main.c) and how to store vp.v in one variable and vp.p in another variable.
Please suggest me if any thing wrong in writing struct. or any other easiest way that will return two values.
please help me how to do this.
Returning a struct from the function is the least common of the two ways to return multiple values. Using pointers is more common:
void Maxphase(float *max, unsigned int *index)
{
*max = 0.0;
float value;
unsigned int i, data;
for (i=0;i<=360;i++)
{
phaseset(i);
data = readvalue();
value = voltage(mux1);
if(value > *max) //find max value
{
*max = value; //max voltage
*index = i;
}
}
printf("Max Voltage Value:%f\r\n", *max);
printf("Related index Value:%d\r\n", *index);
}
Here is how you call this function:
int main() {
float max;
unsigned idx;
Maxphase(&max, &idx);
printf("Max Voltage Value:%f\r\n", max);
printf("Related index Value:%d\r\n", idx);
return 0;
}
I would return the phase from the function - the function name is MaxPhase, which implies that it returns a value of maximum phase. The index at which it found the max can be returned using a pointer.
Note that the data value is unused and mux1 is undefined. Note also that I used idx instead of index as the latter is sometimes already defined in standard libraries (although perhaps not in yours).
float MaxPhase(int * maxindex)
{
float max = 0.0;
int idx = -1;
for (int i=0; i<=360; i++) {
phaseset(i);
unsigned int data = readvalue();
float value = voltage(mux1);
if (value > max) {
max = value;
idx = i;
}
}
*maxindex = idx;
return max;
}
void caller(void)
{
int idx = 0;
float phase = MaxPhase(&idx);
printf("Max Voltage Value:%f\n", phase);
printf("Related index Value:%d\n", idx);
...
}
#include <stdio.h>
struct lol
{
float val;
int ind;
};
void olol(struct lol *lol1)
{
lol1->val = 5;
lol1->ind = 3;
}
int main(void) {
struct lol mylol = {0,0};
olol(&mylol);
printf("lololol %f %d \n", mylol.val, mylol.ind);
printf("lol\n");
return 0;
}
You can solve this in several different ways:
1.define a struct containing the two values and returning that struct.
#include <stdlib.h>
struct Values {
int v1, v2;
};
struct Values *get2Values () {
struct Values *x=(struct Values*)malloc (sizeof (struct Values));
x->v1=1;
x->v2=1231;
return x;
}
and voila, you have a memory leak if you dont treat the returned value right...
2.use pointers as parameters where the values will go, e.g.
Pointers:
void get2Values (int *v1, int *v2) {
*v1=1;
*v2=131231;
}
int main () {
int a1, a2;
get2Values (&a1, &a2);
}
Good luck!
Related
I am trying to create two functions and put them outside the main{ }.
The question requires the user to enter a number that should be end_size > start_size > 9.
And if not just prompt it again.
I have two questions.
Here is the first problem, in function int get_start_size, the function should be stored the value in int start_size. Then, why I cannot call it from another function int get_end_size?
#include <cs50.h>
#include <stdio.h>
int get_start_size(void);
int get_end_size(void);
int main(void)
{
int i = get_start_size();
printf("%i\n", i);
int j = get_end_size();
printf("%i\n", j);
}
int get_start_size(void)
{
int start_size;
do
{
start_size = get_int("Start size is:");
}
while (start_size < 9);
return start_size;
}
int get_end_size(void)
{
int end_size;
do
{
end_size = get_int("End size is:");
}
while (end_size < start_size); //<<<<<<<<<<<<<this is the alert I got, use of undeclared identifier 'start_size'.
return end_size;
}
And the second problem is if I change it like this:
int get_end_size(void)
{
int end_size;
int k = get_start_size(); //<<<<<<<<<<<<< Should I call function like this?
do
{
end_size = get_int("End size is:");
}
while (end_size < k); //this is the problem I got, how to use value "int s" from other function "int get_start_size(void)"?
return end_size;
}
The result will be like this:
~/lab/ $ ./population
Start size is:10
10
Start size is:10 //duplicated prompt
End size is:22
22
~/lab/ $
The result quite meet my goal, but I think I called the function in the wrong way because it asks the user to enter two times the start size. How should I do it instead? Thanks.
Local Variables
Variables that are declared inside a function or block are called
local variables. They can be used only by statements that are inside
that function or block of code. Local variables are not known to
functions outside their own.
start_size is not visible inside get_end_size(), to make it visible, pass the value as a parameter to the function:
The prototype should be:
int get_end_size(int start_size);
For your second snippet, I understand that you want to return 2 values from the function, you can achieve that using a struct:
struct size
{
int start, end;
};
struct size get_size(void)
{
struct size size = {0, 0};
size.start = get_start_size();
do
{
size.end = get_int("End size is:");
}
while (size.end < size.start);
return size;
}
Or you can use pointers:
void get_size(int *start, int *end)
{
*start = get_start_size();
do
{
*end = get_int("End size is:");
}
while (*end < *start);
}
call it from main using:
int start, end;
get_size(&start, &end);
Or you can pass an array:
enum {START, END};
void get_size(int size[])
{
size[START] = get_start_size();
do
{
size[END] = get_int("End size is:");
}
while (size[END] < size[START]);
}
In this case, main should look like:
int size[2];
get_size(size);
I am currently trying to take a sum from two different subroutine and pass it back to the main function, but every time I do this, it just comes up with a zero value and I am unsure why. I have tried putting my print statements in the main function and just doing calculations in the subroutines and that still didn't work, so I know that my variables aren't returning right and my sum is an actual number. How do I pass my variable sum back to my main function correctly?
Here is my code:
#include<stdio.h>
int X[2000];
int Y[2000];
int main()
{
FILE*fpdata1= NULL;
FILE*fpdata2 = NULL;
fpdata1=fopen("DataSet1.txt","r");
fpdata2=fopen("DataSet2.txt","r");
if(fpdata1==NULL || fpdata2 == NULL)
{
printf("file couldn't be found");
}
int i=0;
while(i<2000)
{
fscanf(fpdata1,"%d!",&X[i]);
fscanf(fpdata2,"%d!",&Y[i]);
// printf("This is X: %d\n",X[i]);
// printf("This is Y: %d\n",Y[i]);
i++;
}
fclose(fpdata1);
fclose(fpdata2);
avgX(X);
avgY(Y);
float sum;
float sumY;
float totalsum;
float totalavg;
totalsum= sum + sumY;
totalavg= totalsum/4000;
printf("Sum X: %f\n\n",sum);
printf("Total sum: %f\n\n",totalsum);
printf("The total average is: %0.3f\n\n",totalavg);
return 0;
}
int avgX(int X[])
{
int i=0;
float averageX;
float sum;
sum = 0;
while (i<2000)
{
sum += X[i];
i++;
}
averageX = sum/2000;
printf("Sum of X: %f\n\n",sum);
printf("The sum of Data Set 1 is: %0.3f\n\n",averageX);
return(sum);
}
int avgY(int Y[])
{
int i=0;
float averageY;
float sumY;
sumY = 0;
while (i<2000)
{
sumY += Y[i];
i++;
}
averageY = sumY/2000;
printf("Sum of Y: %f\n\n",sumY);
printf("The sum of Data Set 2 is: %0.3f\n\n",averageY);
return (sumY);
}
Firstly, it would appear you are expecting the lines
avgX(X);
avgY(Y);
to somehow update the sum and sumY variables in the main function. This is a fundamental misunderstanding of how memory is accessed.
Local variable declarations with the same identifier are not shared between functions. They can be accessed only from within the function in which they are declared (and only for the duration of the function call).
In this example, the apples variables in each of the functions have absolutely no correlation to one another. Expecting this program to print 15 is wrong. This program has undefined behavior because foo and bar read values from uninitialized variables.
void foo(void) {
int apples;
/* This is undefined behaviour,
* as apples was never initialized. Do not do this. */
apples += 5;
}
void bar(void) {
int apples;
/* This is undefined behaviour,
* as apples was never initialized. Do not do this. */
printf("%d\n", apples);
}
int main(void) {
int apples = 10;
foo();
bar();
return 0;
}
Instead of this, you'll want to utilize the arguments and return values of your functions. In this example, in main we pass the value of apples as an argument to foo, which adds 5 to this value and returns the result. We assign this return value, overwriting our previous value.
int foo(int val) {
return value + 5;
}
void bar(int val) {
printf("%d\n", val);
}
int main(void) {
int apples = 10;
apples = foo(apples);
bar(apples);
return 0;
}
Again note that the val parameters do not refer some "shared variable", they are local to both foo and bar individually.
As for the specifics of your program:
The functions avgX and avgY do the exact same thing, just with different identifiers.
It would be better to write a more generic summation function with an additional length parameter so that you are not hard-coding data sizes everywhere.
int sum_ints(int *values, size_t length) {
int result = 0;
for (size_t i = 0; i < length; i++)
result += values[i];
return result;
}
You can then easily write averaging logic utilizing this function.
You do check that your file pointers are not invalid, which is good, but you don't halt the program or otherwise remedy the issue.
It is potentially naive to assume a file will always contain exactly 2000 entries. You can use the return value of fscanf, which is the number of conversions that took place, to test if you've failed to read data. Its also used to signify errors.
Though the fact that global variables are zeroed-out saves you from potentially operating on unpopulated data (in the event the files contain less than 2000 entries), it would be best to avoid global variables when there is an alternative option.
It might be better to separate the reading of files to its own function, so that failures can be handled per-file, and reading limits can be untethered.
int main(void) or int main(int argc, char **argv) are the correct, valid signatures for main.
With all that said, here is a substantially refactored version of your code. Note that an implicit conversion takes place when we assign the integer return value of sum_ints to our floating point variables.
#include <stdio.h>
#include <stdlib.h>
#define DATA_SIZE 2000
int sum_ints(int *values, size_t length) {
int result = 0;
for (size_t i = 0; i < length; i++)
result += values[i];
return result;
}
size_t read_int_file(int *dest, size_t sz, const char *fname) {
FILE *file;
size_t i;
if ((file = fopen(fname, "r")) == NULL) {
fprintf(stderr, "Critical: Failed to open file: %s\n", fname);
exit(EXIT_FAILURE);
}
for (i = 0; i < sz; i++)
if (fscanf(file, "%d!", dest + i) != 1)
break;
fclose(file);
return i;
}
int main(void) {
int data_x[DATA_SIZE] = { 0 },
data_y[DATA_SIZE] = { 0 };
size_t data_x_len = read_int_file(data_x, DATA_SIZE, "DataSet1.txt");
size_t data_y_len = read_int_file(data_y, DATA_SIZE, "DataSet2.txt");
float sum_x = sum_ints(data_x, data_x_len),
sum_y = sum_ints(data_y, data_y_len);
float total_sum = sum_x + sum_y;
float total_average = total_sum / (data_x_len + data_y_len);
printf("Sums: [X = %.2f] [Y = %.2f] [Total = %.2f]\n"
"The total average is: %0.3f\n",
sum_x, sum_y, total_sum,
total_average);
}
I have two identical arrays of struct , one in reverse order.
The problem is that i don't want duplicate the same data into the two arrays , i would a reversed array with elements pointing elements of the first array in a way that i can edit the members of struct of first array or from the reversed array taking effect in both.
you can view the source and run it online here https://onlinegdb.com/SJbepdWxS
#include <stdio.h>
typedef struct point{
int id;
float x,y,z;
} point;
void printPoints(point *pts,int len){
int i = 0;
while (pts !=NULL && i < len){
printf("id %d x %f y%f z %f\n",pts->id,pts->x,pts->y,pts->z);
pts++;
i++;
}
}
void translatePoints(point *pts,int len,float t){
int i = 0;
while (pts !=NULL && i < len){
pts->x = pts->x + t;
pts->y = pts->y + t;
pts->z = pts->z + t;
pts++;
i++;
}
}
void reversePoints(point *pts, int len, point *rev){
int i = 0;
int j = len;
while (i < len){
j=len-i-1;
rev[j]=pts[i];
i++;
}
}
int main()
{
int i;
int t1=200;
int t2=300;
int len=3;
point points[len];
point rev_points[len];
for(i=0; i<len ; i++){
points[i].id=i;
points[i].x=10+i;
points[i].y=20+i;
points[i].z=30+i;
}
//point * pts = points;
printf("\nprint points \n\n");
printPoints(points,len);
printf("\ntranslate points %d...\n\n",t1);
translatePoints(points,len,t1);
printf("\nprint points\n\n");
printf("\nreverse points to rev_points\n");
reversePoints(points,len,rev_points);
printf("\nprint rev_points \n\n");
printPoints(rev_points,len);
printf("\ntranslate rev_points %d...\n\n",t2);
translatePoints(rev_points,len,t2);
printf("\nprint rev_points\n\n");
printPoints(rev_points,len);
printf("\nprint points\n\n");
printPoints(points,len);
return 0;
}
I expect that struct values of both arrays change when i change value in one of the two array.
But changing values of struct in the first array , the second array not changes and the other way around.
One way to look at this is a set of points and two permutations on the set. This sets up a points array, which is used as a set, and forward_points and reverse_points as arrays of pointers to the point array that we are going to use as permutations.
#include <stdio.h>
struct Point {
int id;
float x,y,z;
};
/* Print a point. */
static void printPoint(struct Point *point) {
printf("id %d x %f y%f z %f\n",point->id,point->x,point->y,point->z);
}
/* These print out an array of pointers to point. */
static void printPointsRef(struct Point **ref, int len) {
struct Point **end = ref + len;
while(ref < end) printPoint(*(ref++));
}
/* This translates all the `pts` up to `len` by `(1,1,1)*t`. */
static void translatePoints(struct Point *pts, int len, float t) {
struct Point *end = pts + len;
while(pts < end) {
pts->x = pts->x + t;
pts->y = pts->y + t;
pts->z = pts->z + t;
pts++;
}
}
/* Helper function to `main`. */
static void printPoints(struct Point **forward_points,
struct Point **reverse_points, int len) {
printf("print points\nprint points forward:\n");
printPointsRef(forward_points,len);
printf("print points reverse:\n");
printPointsRef(reverse_points,len);
printf("\n");
}
int main(void)
{
const int len = 3;
/* This is the actual points structure. */
struct Point points[len];
/* These are arrays of pointers to points; they are
permutations of `points`. */
struct Point *forward_points[len], *reverse_points[len];
int i;
const int t1=200;
for(i=0; i<len; i++) {
/* Initialise element `i` of `points`. */
points[i].id=i;
points[i].x=10+i;
points[i].y=20+i;
points[i].z=30+i;
/* Initialise element `i` of `forward_points`
to point to `points[i]`, and `backward_points`
to point the other way (it doesn't matter that
the backwards points are uninitialised, they
will be.) */
forward_points[i] = &points[i];
reverse_points[i] = &points[len - 1 - i];
}
printPoints(forward_points, reverse_points, len);
/* Translation is a vector space operation and doesn't
care about order; we just do it on the original points. */
printf("translate points %d...\n\n",t1);
translatePoints(points,len,t1);
printPoints(forward_points, reverse_points, len);
return 0;
}
Of course, there is no integrity constraints on the pointers; nothing stopping one from pointing at anything, null, the same elements, or anything else.
I added an other struct with one element that is a pointer
typedef struct ptr_point{
point * p;
} ptr_point;
I edited the function reversePoints
void reversePoints(point *pts, int len, ptr_point *rev){
// This function is used only to test pointers
int i = 0;
int j = len;
while (i < len){
j=len-i-1;
rev[j].p = &pts[i];
i++;
}
}
and added another function to print ptr_points
void printPtrPoints(ptr_point *pts,int len){
int i = 0;
while (i < len){
printf("id %d x %f y%f z %f\n",pts->p->id,pts->p->x,pts->p->y,pts->p->z);
pts++;
i++;
}
}
and declaring the second array as ptr_point array
ptr_point rev_points[len];
In conclusion : now data in the second array are not replicated but pointing to element structure of the first array.
The need to not replicate data arise in presence of millions of coordinate points that if replicate more than one time , sorting it for example by x, y, z and so on , occupe much memory with the difficulty of managing .
This fix however forces me to use structures->type in order to change the access mode to read or set values.
I don't know if this is the best solution but it has solved the problem for not duplicate the data.
you can run the source with fixes here: https://onlinegdb.com/SknP_i-eS
Thank you all for the advice.
I want to pass two arguments into void Dividing from void Assign_numbers and void Maximum. I have only learnt to pass one argument at a time. Can you please tell me what I have to do print out the following variables inside void Dividing. If it's possible, I don't want the format of my code to change drastically. Can you also show me an example, since I am a visual learner. Thanks
#include <stdlib.h>
#include <stdio.h>
#define Max 6
struct Numbers
{
double a,b,c,d,e,f;
};
void Maximum(double *ptr);
void Dividing(double Maximum, double *ptr);
void Assign_numbers()
{
struct Numbers number;
number.a=45.78;
number.b=81.45;
number.c=56.69;
number.d=34.58;
number.e=23.57;
number.f=78.35;
Maximum((double*) &number);
Dividing((double*) &number);
}
void Maximum(double *ptr)
{
int i=0;
double Maximum = ptr[0];
for(i;i<Max;i++)
{
if(ptr[i]> Maximum)
{
Maximum = ptr[i];
}
}
Dividing(Maximum);
}
void Dividing(double Maximum, double *ptr)
{
printf("%.2f", Maximum);
printf("%.2f",ptr[3]);
}
int main()
{
Assign_numbers();
return 0;
}
Use array instead of struct - shwon here with reference example
Like Joachim Pileborg said. Don't use a struct as an array. In your case use a multidimensional array.
double[10][6] numbers;
You can easily iterate through such an array like so:
#include <stdio.h>
int main () {
/* an array with 2 rows and 6 columns*/
double numbers[2][6] = {
{45.78, 81.45, 56.69, 34.58, 23.57, 78.35},
{1,2,3,4,5, 6}
};
int i, j;
/* output each array element's value */
for ( i = 0; i < 2; i++ ) {
for ( j = 0; j < 6; j++ ) {
printf("numbers[%d][%d] = %f\n", i,j, numbers[i][j] );
}
}
/* Output by reference */
for(i = 0; i < 2; i++){
for(j=0; j < 6; j++ ){
printf("numbers[%d][%d] = %f\n", i, j,*(*(numbers + i) + j));
}
}
return 0;
}
Why the current code fails
Now onto explaining how your code (does not) work and a little about how pointers work. First off:
Dividing(double Maximum, double* ptr);
Does not work in the way you think it does. "double Maximum" is a new double variable that works within the scope of Dividing and is not a variable retrieved from the function:
void Maximum(double *ptr);
If you already knew this, then you should know or at least have expected how poor the naming of your variables are(keep it lowerCamelCase).
Now lets get onto what you're trying to do. IMHO your code is completely broken unless I am noticeing something. In Assign_numbers() you want to call Dividing() using a pointer reference. In Maximum() you want to call Dividing() again, but this time sending only a value. It doesn't make it better that you have 2 separate different calls that each have one parameter. But the function has to have two parameters. Now in order to iterate through the variables in a struct - again this is not recommended and the bottom code only serves as an example.
struct Numbers
{
double a,b,c,d,e,f;
};
struct Numbers Assign_numbers()
{
struct Numbers number;
number.a=45.78;
number.b=81.45;
number.c=56.69;
number.d=34.58;
number.e=23.57;
number.f=78.35;
return number;
}
int main()
{
struct Numbers number;
number = Assign_numbers(number);
double *value = &(number.a); //take address of the first element, since a pointer always counts upwards.
int i;
/*This loops through the addresses of the struct starting from the initial address in number.a and moves upwards 5 times and hopefully ends in number.f. Seriously bad way to construct arrays*/
/*Just try replacing sizeof(number) with sizeof(double). suddenly you get all kinds of weird values because you have ended up outside of the struct*/
/*Also note that this only works when all the datatypes in the struct have a size of 8 bytes(the size of double) */
for (i = 0; i < sizeof(number) / sizeof(double); i++){
printf("[%d]: %f\n",i, value[i]);
}
return 0;
}
New working code
With all that said. This is the closest I am going to to be able to make your code work since I have no idea what you're trying to accomplish:
#include <stdlib.h>
#include <stdio.h>
#define Max 6
struct Numbers
{
double a,b,c,d,e,f;
};
void Maximum(double *ptr);
void Dividing(double *ptr);
void Assign_numbers()
{
struct Numbers number;
number.a=45.78;
number.b=81.45;
number.c=56.69;
number.d=34.58;
number.e=23.57;
number.f=78.35;
Maximum(&number.a); //You need to parse the very first address of the struct. IN this case 'a'
Dividing(&number.a);
}
void Maximum(double *ptr)
{
int i=0;
double maximum = ptr[0];
for(i;i<Max;i++)
{
if(ptr[i]> maximum)
{
maximum = ptr[i];
}
}
printf("maximum: %f", maximum);
}
/*//removed the first parameter since it was not clear what it was for and you only had function calls to this function with one parameter */
void Dividing(double *ptr)
{
printf("%.2f",ptr[3]);
}
int main()
{
Assign_numbers();
return 0;
}
I made a typdef struct of students it features: student ID , ClassId, currentGrade , and lettergrade.
Now I want to sort highest to lowest grade. I already done that but the other parts of struct are not sorted with it. How do I go about making the struct stay together with the sorting?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
short id;
short enrolledClassID;
float currentGrade;
char letterGrade;
} Student;
void printStudentInfo(Student student);
void printStudentArray(Student* student,int sizeOfArray);
void sortByGrade(Student* student,int sizeOfArray);
int main()
{
Student studentArray[5] = {
{25,278,95,'A'},
{ 27,278,56,'F' },
{ 29,321,74,'C' },
{ 31,321,63,'D' },
{ 15,278,81,'B' }
};
Student* pStudents = &studentArray;
printStudentArray(pStudents,5);
sortByGrade(pStudents, 5);
printStudentArray(pStudents, 5);
//studentArray[0].currentGrade;
system("Pause");
}
void sortByGrade(Student* student, int sizeOfArray) {
int min, i;
Student temp;
while (sizeOfArray > 0)
{
min = 0;
for (i = 1; i < sizeOfArray; i++)
if (student[i].currentGrade < student[min].currentGrade)
min = i;
temp.currentGrade = student[sizeOfArray - 1].currentGrade;
student[sizeOfArray - 1].currentGrade = student[min].currentGrade;
student[min].currentGrade = temp.currentGrade;
sizeOfArray--;
}
}
void printStudentInfo(Student student) {
printf("The student ID is %i, class ID is %i, current grade in class is %0.2f\n, and letter grade is %c\n", student.id, student.enrolledClassID,student.currentGrade,student.letterGrade);
}
void printStudentArray(Student* student,int sizeOfArray) {
for (int i = 0; i < sizeOfArray; i++) {
printStudentInfo(student[i]);
}
}
You're only moving around the current grade, not the entire structure. So instead of this:
temp.currentGrade = student[sizeOfArray - 1].currentGrade;
student[sizeOfArray - 1].currentGrade = student[min].currentGrade;
student[min].currentGrade = temp.currentGrade;
Do this:
temp= student[sizeOfArray - 1];
student[sizeOfArray - 1] = student[min];
student[min] = temp;
Using qsort() to sort your array is not difficult. The first argument is the array itself, the second is the number of elements in the array, the third is the size of each array element (sizeof (Student)), and the fourth is a function pointer that returns -1 if the compared to elements are in the correct order, 0 if equal, and +1 if in the wrong order.
So:
int compareByGrade(const void *ptr1, const void *ptr2)
{
const Student *const s1 = ptr1;
const Student *const s2 = ptr2;
if (s1->currentGrade > s2->currentGrade)
return -1; /* Correct order */
else
if (s1->currentGrade < s2->currentGrade)
return +1; /* Wrong order */
else
return 0; /* Same grade */
}
although I personally like to rewrite that as
int compareByGrade(const void *ptr1, const void *ptr2)
{
const float val1 = ((const Student *)ptr1)->currentGrade;
const float val2 = ((const Student *)ptr2)->currentGrade;
return (val1 > val2) ? -1 : (val1 < val2) ? +1 : 0;
}
which does the exact same thing, but with more concise expressions. Use the one you find easier to read, understand, and maintain (in the long term).
In both cases, the sortByGrade() function is just
void sortByGrade(Student *const array, const size_t elements)
{
if (array != NULL && elements > 1)
qsort(array, elements, sizeof array[0], compareByGrade);
}
Note that you should use size_t type for nonnegative memory sizes -- size_t is usually unsigned (cannot represent negative values) --, things like number of elements in array, array indices, string lengths, and so on. It is the purpose of the type.
On current 64-bit architectures, int is only 32-bit, so if you get into the habit of using int for memory sizes, your code will only be able to reference just 2 GB of memory. This is a real problem with old programs, because their programmers didn't think it'd ever be a problem. (It is so bad, actually, that the Linux kernel had to restrict writes to files to less than 2GB at a time.)
So, please, become better than those problematic old-timey programmers, and learn how to use size_t instead of unsigned int or int.