I'm trying to sort dates from an array i've got the following code (without including the array and the file that i'm trying to read and the other with the sorted dates that i'm trying to write.
int aniomayor=tot[0].anio;
int diamayor=tot[0].dia;
int mesmayor=tot[0].mes;
while (i<nf) {
if (tot[i].anio > aniomayor) {
int aniomayor=tot[i].anio;
int diamayor=tot[i].dia;
int mesmayor=tot[i].mes;
}
else if (tot[i].anio == aniomayor && tot[i].mes > mesmayor) {
int aniomayor=tot[i].anio;
int diamayor=tot[i].dia;
int mesmayor=tot[i].mes;
}
else if (tot[i].anio == aniomayor && tot[i].mes == mesmayor && tot[i].dia > diamayor) {
int aniomayor=tot[i].anio;
int diamayor=tot[i].dia;
int mesmayor=tot[i].mes;
}
i++;
}
fprintf(f, "%s ", diamayor);
fprintf(f, "%s ", mesmayor);
fprintf(f, "%s \n", aniomayor);
I think it would work but in the 2,3,4.. line it will print always the same date and i don't know how to do for it to ignore the dates that already had been sorted. Thanks in advance.
The original int declaration establishes variables. The subsequent ones create "shadow" variables that have the same name but are not the same variable.
Here's a demonstration:
#include <stdio.h>
int main() {
int x = 1;
if (x == 1) {
int x = 2;
printf("x=%d\n", x);
}
printf("x=%d\n", x);
return 0;
}
This prints:
x=2
x=1
The top-level x never gets modified, so it appears to revert to the original value.
You should remove the int prefix from those, just assign to the existing variable.
When you say int x = y; in C you are declaring a variable and assigning a value. To assign to an existing variable x = y; is sufficient.
The int prefix is only necessary on the first instance of the variable so the compiler knows what type to use for that and all subsequent references inside the same scope.
Now normally the compiler would complain about creating another variable with the same name if it's done in the same scope. In your case because you're doing it inside an if, technically that's a different scope so you can have duplicates.
As has been mentioned in the comments, it is preferable to use qsort, (if one doesn't care about stability.) One needs a function pointer, which is compare_dates in the code below.
#include <stdlib.h> /* EXIT*, rand, qsort */
#include <stdio.h> /* *printf */
#include <time.h> /* clock */
#include <assert.h> /* assert */
struct Date { int anio, mes, dia; };
/** Random [i, j]. https://stackoverflow.com/a/6852396/2472827
This is just used for test purposes. */
static int rand_range(const int i, const int j) {
const unsigned long max = (unsigned long)j - i,
num_bins = max + 1l,
num_rand = (unsigned long)RAND_MAX + 1,
bin_size = num_rand / num_bins,
defect = num_rand % num_bins;
unsigned long x;
assert(i <= j && num_bins <= RAND_MAX);
do { x = 1l * rand(); } while (num_rand - defect <= x);
return i + x / bin_size;
}
/** Initiaises the date with random. */
static void init_date(struct Date *const date) {
assert(date);
date->anio = rand_range(1950, 2050);
date->mes = rand_range(1, 12);
date->dia = rand_range(1, 30); /* Approximately. */
}
/** Prints the date in a static string.
Assumes the date is sanitised, or else this presents a risk of overflow. */
static const char *print_date(const struct Date *const date) {
static char print[128]; /* Should be 11 if -999 <= year < 9999. */
assert(date);
sprintf(print, "%4.4d-%2.2d-%2.2d", date->anio, date->mes, date->dia);
return print;
}
/** The arguments must be const struct Date *.
#return -, =, + */
static int compare_dates(const void *p, const void *q) {
const struct Date *x = (const struct Date *)p, *y = (const struct Date *)q;
assert(p && q);
if(x->anio > y->anio) return 1;
if(x->anio < y->anio) return -1;
if(x->mes > y->mes) return 1;
if(x->mes < y->mes) return -1;
if(x->dia > y->dia) return 1;
if(x->dia < y->dia) return -1;
return 0;
}
int main(void) {
struct Date dates[64];
const size_t dates_size = sizeof dates / sizeof *dates;
size_t i;
/* Generate dates. */
srand((unsigned)clock());
for(i = 0; i < dates_size; i++) init_date(dates + i);
/* Sort it using compare_dates. */
qsort(dates, dates_size, sizeof *dates, &compare_dates);
/* Print. */
for(i = 0; i < dates_size; i++) printf("%s.\n", print_date(dates + i));
return EXIT_SUCCESS;
}
See How to generate a random integer number from within a range.
Related
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 am trying to create a array of array of string where each row (if considered matrix) should have 3 strings of any length and a maximum of 10 rows
The data Structure is correct but I am very much surprised with the output I get in the global variable. So the matrix would act as the database to the program and hence kept in global space
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// Maximum buffer size needed
#define MAX_NUM_ITEMS 10
#define MAX_ITEM_PER_ROW 3
static char *array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW];
#define ITOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 1)
char *itoa_base(char *, int , int);
#define TO_BASE(x,b) itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
char *itoa_base(char *s, int x, int base) {
s += ITOA_BASE_N - 1;
*s = '\0';
if (base >= 2 && base <= 36) {
int x0 = x;
do {
*(--s) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[abs(x % base)];
x /= base;
} while (x);
if (x0 < 0) {
*(--s) = '-';
}
}
return s;
}
int main(void)
{
int count = 0;
for (int i = 0; i < MAX_NUM_ITEMS; i++){
for (int j = 0; j < MAX_ITEM_PER_ROW; j++ ){
++count;
array[i][j] = TO_BASE(count, 16);
}
}
for (int i = 0; i < MAX_NUM_ITEMS; i++){
for (int j = 0; j < MAX_ITEM_PER_ROW; j++ ){
printf("%s ",array[i][j]);
}
printf("\n");
}
return 0;
}
From my logic I should see
1 2 3
4 5 6
7 8 9 and so on and not E E E
can't understand why that is happening
First, this:
(char [ITOA_BASE_N]){0}
Does not get you a new instance of a character array, unlike say golang. So, every time you call itoa(), you are calling it with the same character array. Somewhat worse, the character array is occupying a reclaimable stack address [ its scope is only that inner loop ], so it can be over written with random stuff shortly after. It is remarkably consistent though; I will give it that.
Changing the invocation to:
array[i][j] = strdup(TO_BASE(count, 16));
and adding a #include at the top produces the output you wanted.
If dynamic allocation is not permissible in your application, you will have to use a static allocation scheme, which you could make a bounded version of strdup like:
char *strnew(char *s) {
static char strspace[ITOA_BASE_N * MAX_NUM_ITEMS * MAX_ITEM_PER_ROW ];
static char *strnext = strspace;
if (strlen(s) + strspace >= &strspace[sizeof strspace]) {
s = "<error: out of space>"; /* something more clever is possible */
} else {
strcpy(strnext, s);
s = strnext;
strnext += strlen(strnext)+1;
}
return s;
}
which you could substitute for strdup. If you do the next person down the line a favour and use a more descriptive notion like MAX_STRING_SPACE which is based on the calculation; and rather than insert a "bad value", cause some sort of exception, I am sure they would appreciate it.
The problem is here:
itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
^^^^^^^^^^^^^^^^^^^^^^^
you are allocating a temp array (on the stack) which is only valid up to the end of the containing expression statement. So when the time comes to print them, the pointers you've stored in the matrix are dangling. What the compiler ends up doing is reusing the same memory for every call, so the strings end up overwriting.
You could instead use a static matrix of arrays rather than pointers:
static char array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW][ITOA_BASE_N];
then your call in the first loop becomes
itoa_base(array[i][j], count, 16);
you'll also need to "fix" itoa_base so it puts the result in the front of the array rather than the back. Obvious way is with a recursive loop like:
char *itoa_base(char *s, int x, int base) {
if (base >= 2 && base <= 36) {
if (x < 0) {
*s++ = '-';
x = -x; }
if (x >= base)
s = itoa_base(s, x/base, base);
*s++ = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[x % base];
}
*s = '\0';
return s;
}
Seems like the function qwertyInches() should work but when I call it in main() it gives me
[Error] called object 'qwertyInches' is not a function or function pointer.
Any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Global constant
const int MAX_LENGTH = 81; // global constant for max input line length
void qwertyInches (char row[], double *inches, int x, double y) {
int d;
for (d = 0; d < strlen(row); d++) {
if (x == row[d]) {
*inches = *inches + y;
}
}
}
int main() {
int count[256] = { 0 };
int letterCounter = 0;
int qwertyCounter = 0;
int homeRowCounter = 0;
int dvorakCounter = 0;
char qwertyHomeRow[23] = {"asdfghjkl;ASDFGHJKL:\"'" };
char dvorakHomeRow[22] = {"aoeuidhtns-_AOEUIDHTNS"};
double percentOfCharQwerty = 0.0;
double percentOfCharDvorak = 0.0;
char qwertyHomeRowInches[4] = {"ghGH"};
char qwertyRowInches[46] = {"qweruiopQWERUIOP{[}]\ZzXx|CcVvNnMm<,>./?"};
char qwertyNumberInches[25]= {"`~1!2#3#4$5%7&8*9(0)-_=+)"};
char qwertyTAndYInches[4] = {"TtYy"};
char num6Inches[2] = {"6^"};
char dvorakHomeRowInches[4]= {"iIDd"};
char dvorakRowInches[41] = {"\"<',.>PpGgCcRrLl?/:+=|:;QqJjKkBb\MmWwVvZz"};
char dvorakYandFInches[4] = {"YyFf"};
char dvorakNumberInches [25] = {"~`1!2#3#4$5%7&8*9()0{[]}"};
double dvorakInches = 0.0;
double qwertyInches = 0.0;
/* loop counters */
int k;
int l;
int d;
/* file handle --- in this case I am parsing this source code */
FILE *fp = fopen("newsample.txt", "r");
/* a holder for each character (stored as int) */
int c;
/* for as long as we can get characters... */
while((c=fgetc(fp))) {
/* break if end of file */
if(c == EOF) {
break;
}
else if (c == 32 || c == 10 || c == 9) {
count[c]+=1;
}
/* otherwise add one to the count of that particular character */
else {
count[c]+=1;
letterCounter++;
for (l = 0; l < strlen(dvorakHomeRow); l++) {
if (c == qwertyHomeRow[l]) {
qwertyCounter++;
}
if (c == dvorakHomeRow[l]) {
dvorakCounter++;
}
}
qwertyInches(strlen(qwertyHomeRowInches) , &qwertyInches, c, .75 );
}
}
percentOfCharQwerty = (double) qwertyCounter / (double) letterCounter * 100;
percentOfCharDvorak = (double) dvorakCounter / (double) letterCounter * 100;
printf("Amount of Letters: %d\n", letterCounter);
printf("qwerty counter: %d\n", qwertyCounter);
printf("Dvorak counter: %d\n", dvorakCounter);
printf("Percent of qwerty letters %.2lf\n", percentOfCharQwerty);
printf("Percent of Dvorak letters %.2lf\n", percentOfCharDvorak);
printf("qwertyInches: %.2lf\n", qwertyInches);
printf("dvorakInches: %.2lf\n", dvorakInches);
/* close the file */
fclose(fp);
return;
}
There is a qwertyInches local variable inside main() which shadows qwertyInches() function.
Quoting C11, chapter §6.2.1, Scopes of identifiers (emphasis mine)
[....] If an identifier designates two different entities in the same name
space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end
strictly before the scope of the other entity (the outer scope). Within the inner scope, the
identifier designates the entity declared in the inner scope; the entity declared in the outer
scope is hidden (and not visible) within the inner scope.
Solution: Change one of the names.
That said, the first argument of qwertyInches() function should be a char *, but you're passing a size_t (output of strlen()) which is plain wrong. Change that too.
when i call it in main it gives me this... [Error] called object 'qwertyInches' is not a function or function pointer.
And of course the compiler is right. Inside main(), this declaration shadows the function declaration:
double qwertyInches = 0.0;
Thus, in main(), qwertyInches refers to a local variable of type double, not a function.
you're defining both qwertyInches as a variable AND a function.
void qwertyInches (char row[], double *inches, int x, double y) {
and
double qwertyInches = 0.0;
Just change the name of one of the above. I generally give an "action" name to my functions, and a "thing" name to my variables.
I'm trying to write a generic function to sort different types of data. My code is:
#include<stdio.h>
#define GENERIC_SORT(TYPE) \
TYPE ##_SORT(TYPE a[],int n) \
{ \
int i,j; \
TYPE aux; \
for(i=1;i<n;i++) \
for(j=n-1;j>=i;j--) \
if(a[j]<a[j-1]) \
{ \
aux=a[j]; \
a[j]=a[j-1]; \
a[j-1]=aux; \
} \
}
GENERIC_SORT(int)
GENERIC_SORT(float)
GENERIC_SORT(double)
GENERIC_SORT(char)
int main(void)
{
int i,a[]={3,7,5,4,6,1};
int_SORT(a,6);
for(i=0;i<6;i++)
printf("%d ",a[i]);
return 0;
}
I'm preparing for an exam,and in the courses there's an example with GENERIC_MAX, which finds the maximum between 2 values. And I'm supposed to make the sort just like this...
It works fine on int, float, double and char. But how can I use it to sort a string array (char a[][100] or char *a[])?
A prime example of a generic sort is the C runtime library qsort(). One of its most versatile attributes is that it makes use of a "comparison function" which is passed as a parameter.
Why not adopt that tactic? While it is true that most comparison functions are trivial, in the case of accessing objects it is invaluable for interpreting what is inside the object.
What you need to do is generate the C equivalent of C++'s template functions using generics. This is usually a combination of function pointers and re-casting void* data to achieve the desired result. The qsort() function does just this. Included below is a code listing and sample run from a similar answer of mine from some time back that shows you how to use a simple Bubble Sort implementation for multiple data types.
To extend this to any data type, you just need to:
Create your own int compareDataType(void* a, void* b) function
Update the sizeOfElement and compareFcn parameters passed to the BubbleSort() function.
Your approach might work for primitive data types that already have defined comparison operations, but it won't work for abstract data types likes structs, etc.
Code Listing
/*******************************************************************************
* Preprocessor Directives
******************************************************************************/
#include <stdio.h> // printf
#include <stdlib.h> // calloc
#include <string.h> // memcpy
#include <time.h> // random seed initialization
#define ELEMENT_AT(arr, i, w) (((char*)arr) + ((i)*(w)))
#define BUF_SIZE (20)
/*******************************************************************************
* Function Prototypes
******************************************************************************/
typedef struct cricket_s {
char pname[BUF_SIZE];
char tname[BUF_SIZE];
int avg;
} cricket_t;
/*******************************************************************************
* Function Prototypes
******************************************************************************/
/* #functionName: bubbleSort
* #brief: Performs a bubble sort on an input array, using a user-
* provided function pointer for comparing data types so that
* the function can be as generic as possible.
* #param: arr: The array to search.
* #param: compareFcn: The comparison function to use.
* #param: sizeOfElement: The size of a single element in arr
* #param: numElements: The number of elements in arr
*/
void* bubbleSort(void* arr, int (*compareFcn)(void*, void*), size_t sizeOfElement, size_t numElements);
void rand_str(char *dest, size_t length);
int compareCricketAvg(void *a, void *b);
int compareCricketPname(void *a, void *b);
/*******************************************************************************
* Function Definitions
******************************************************************************/
/*----------------------------------------------------------------------------*/
void* bubbleSort(void* arr, int (*compareFcn)(void*, void*), size_t sizeOfElement, size_t numElements) {
if (!arr || !compareFcn || !numElements || !sizeOfElement) {
return NULL;
}
int i, j;
void* tempBuf;
/* Create a swap buffer */
if ((tempBuf = calloc(1, sizeOfElement)) == NULL) {
return NULL;
}
/* Sort the list via bubble sort (stable) */
for (i=0; i<(numElements-1); i++) {
for (j=0; j<(numElements - i -1); j++) {
if (compareFcn(ELEMENT_AT(arr, j, sizeOfElement), ELEMENT_AT(arr, j+1, sizeOfElement)) == (-1)) {
memcpy(tempBuf, ELEMENT_AT(arr, j, sizeOfElement), sizeOfElement);
memcpy(ELEMENT_AT(arr, j, sizeOfElement), ELEMENT_AT(arr, j+1, sizeOfElement), sizeOfElement);
memcpy(ELEMENT_AT(arr, j+1, sizeOfElement), tempBuf, sizeOfElement);
}
}
}
/* Clean up and exit */
free(tempBuf);
return arr;
}
/*******************************************************************************
* Comparson function s.
* Returns (-1) if a<b, +1 if a>b, 0 if a==b
*/
/*----------------------------------------------------------------------------*/
int compareCricketAvg(void *a, void *b) {
if (!a || !b) {
/* Treat bad input as equality */
return 0;
}
int ret;
if (((cricket_t*)a)->avg < ((cricket_t*)b)->avg) {
ret = (-1);
} else if (((cricket_t*)a)->avg > ((cricket_t*)b)->avg) {
ret = 1;
} else
ret = 0;
return ret;
}
/*----------------------------------------------------------------------------*/
int compareCricketPname(void *a, void *b) {
if (!a || !b) {
/* Treat bad input as equality */
return 0;
}
int ret;
char *s1, *s2;
s1 = ((cricket_t*)a)->pname;
s2 = ((cricket_t*)b)->pname;
ret = strncmp(s1, s2, BUF_SIZE);
if (ret > 0) {
ret = 1;
} else if (ret < 0) {
ret = (-1);
} else {
ret = 0;
}
return ret;
}
/*----------------------------------------------------------------------------*/
void rand_str(char *dest, size_t length) {
char charset[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (length-- > 0) {
size_t index = (double) rand() / RAND_MAX * (sizeof charset - 1);
*dest++ = charset[index];
}
*dest = '\0';
}
/*******************************************************************************
* Main Entry Point
******************************************************************************/
/*----------------------------------------------------------------------------*/
int main(void) {
srand(time(NULL)); // init random seed
int numPlayers = 10;
int i;
/* Dynamically allocate memory for a few teams */
cricket_t* team;
if ((team = calloc(numPlayers, sizeof(cricket_t))) == NULL) {
printf("Memory error\n");
return (-1);
}
/* Populate struct values */
for (i=0; i<numPlayers; i++) {
team[i].avg = rand() % 1000;
rand_str(team[i].pname, BUF_SIZE);
printf("Team %d - Pname:%s - Average:%d\n", i, team[i].pname, team[i].avg);
}
printf("\n");
/* Sort the list according to AVG value */
bubbleSort((void*)team, compareCricketAvg, sizeof(cricket_t), numPlayers);
/* Print sorted team */
for (i=0; i<numPlayers; i++) {
printf("Team %d - Pname:%s - Average:%d\n", i, team[i].pname, team[i].avg);
}
printf("\n");
/* Sort again, now by pname */
bubbleSort((void*)team, compareCricketPname, sizeof(cricket_t), numPlayers);
/* Print sorted team */
for (i=0; i<numPlayers; i++) {
printf("Team %d - Pname:%s - Average:%d\n", i, team[i].pname, team[i].avg);
}
printf("\n");
free(team);
return 0;
}
Sample Run
Team 0 - Pname:YY7plBOnjIi7YQTKjgqB - Average:605
Team 1 - Pname:sKGbl8pIAjHzq6U2UimD - Average:439
Team 2 - Pname:tBrmmKDNmvf6crrlQaWa - Average:226
Team 3 - Pname:vBXqESI0vju7KRuvvhS1 - Average:117
Team 4 - Pname:YdYqzPBv0s0Bqqgi9hNs - Average:209
Team 5 - Pname:VdDpJ8GB9dAnb0W1Bs14 - Average:633
Team 6 - Pname:DuUTM3bAvXvJAVsJB3TP - Average:212
Team 7 - Pname:h1Fd2hF3l8GQ2AD6LdBI - Average:237
Team 8 - Pname:kjEN3gRX5ve6ar8r7cMg - Average:467
Team 9 - Pname:Djtgpet1XdmhSal81iew - Average:473
Team 0 - Pname:VdDpJ8GB9dAnb0W1Bs14 - Average:633
Team 1 - Pname:YY7plBOnjIi7YQTKjgqB - Average:605
Team 2 - Pname:Djtgpet1XdmhSal81iew - Average:473
Team 3 - Pname:kjEN3gRX5ve6ar8r7cMg - Average:467
Team 4 - Pname:sKGbl8pIAjHzq6U2UimD - Average:439
Team 5 - Pname:h1Fd2hF3l8GQ2AD6LdBI - Average:237
Team 6 - Pname:tBrmmKDNmvf6crrlQaWa - Average:226
Team 7 - Pname:DuUTM3bAvXvJAVsJB3TP - Average:212
Team 8 - Pname:YdYqzPBv0s0Bqqgi9hNs - Average:209
Team 9 - Pname:vBXqESI0vju7KRuvvhS1 - Average:117
Team 0 - Pname:vBXqESI0vju7KRuvvhS1 - Average:117
Team 1 - Pname:tBrmmKDNmvf6crrlQaWa - Average:226
Team 2 - Pname:sKGbl8pIAjHzq6U2UimD - Average:439
Team 3 - Pname:kjEN3gRX5ve6ar8r7cMg - Average:467
Team 4 - Pname:h1Fd2hF3l8GQ2AD6LdBI - Average:237
Team 5 - Pname:YdYqzPBv0s0Bqqgi9hNs - Average:209
Team 6 - Pname:YY7plBOnjIi7YQTKjgqB - Average:605
Team 7 - Pname:VdDpJ8GB9dAnb0W1Bs14 - Average:633
Team 8 - Pname:DuUTM3bAvXvJAVsJB3TP - Average:212
Team 9 - Pname:Djtgpet1XdmhSal81iew - Average:473
You can circumvent the problem of non-symbol types like char * or struct point by defining new types with typedef. A better approach may be to pass the name of the new function to the macro as additional parameter.
The problem of the comparison can be solved by passing the comparison criterion, as in the callback function of qsort that others have pointed you to. Because the function is not really called, but substituted at compile time, it can be a macro.
Here's your macro extended:
#define GENERIC_SORT(NAME, TYPE, LT) \
void NAME(TYPE a[], int n) \
{ \
int i, j; \
\
for (i = 1; i < n; i++) { \
for (j = n - 1; j >= i; j--) { \
if (LT(a[j], a[j - 1])) { \
TYPE aux = a[j]; \
a[j] = a[j - 1]; \
a[j - 1] = aux; \
} \
} \
} \
}
Your integer sort is then:
#define LESS(a, b) ((a) < (b))
GENERIC_SORT(int_sort, int, LESS);
int main(void)
{
int array[] = {
6, 3, 9, 2, 7, 10, 5, 1
};
int n = sizeof(array) / sizeof(*array);
int i;
int_sort(array, n);
for (i = 0; i < n; i++) {
printf("%d\n", array[i]);
}
return 0;
}
Sort strings with a comparison function:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gen.h" /* your macro */
int str_less(const char *a, const char *b)
{
return strcmp(a, b) < 0;
}
GENERIC_SORT(str_sort, const char *, str_less);
int main(void)
{
const char *array[] = {
"apricot", "orange", "banana", "apple", "papaya", "kiwi"
};
int n = sizeof(array) / sizeof(*array);
int i;
str_sort(array, n);
for (i = 0; i < n; i++) {
printf("%s\n", array[i]);
}
return 0;
}
If you already have the GENERIC_MAX code (as described in a comment), you can use it instead of comparing and swapping. To do it, define GENERIC_MIN (should be easy - very similar to generic max). Then:
#define GENERIC_SORT(TYPE) \
TYPE ##_SORT(TYPE a[],int n) \
{ \
int i,j; \
TYPE aux_min, aux_max; \
for(i=1;i<n;i++) \
for(j=n-1;j>=i;j--) \
{ \
aux_min=GENERIC_MIN(a[j], a[j-1]); \
aux_max=GENERIC_MAX(a[j], a[j-1]); \
a[j-1]=aux_min; \
a[j]=aux_max; \
} \
}
I have priority queue which returns with pop function just int y, but I need return int x and int y. So I found, that I can use struct (struct point) to return two values from function, but I can't figure, how it implement (rewrite int out to struct and use it in main).
Structs:
typedef struct { int x; int y; int pri; } q_elem_t;
typedef struct { q_elem_t *buf; int n, alloc; } pri_queue_t, *pri_queue;
struct point{int PointX; int PointY;};
Pop function:
int priq_pop(pri_queue q, int *pri)
{
int out;
if (q->n == 1) return 0;
q_elem_t *b = q->buf;
out = b[1].y;
if (pri) *pri = b[1].pri;
/* pull last item to top, then down heap. */
--q->n;
int n = 1, m;
while ((m = n * 2) < q->n) {
if (m + 1 < q->n && b[m].pri > b[m + 1].pri) m++;
if (b[q->n].pri <= b[m].pri) break;
b[n] = b[m];
n = m;
}
b[n] = b[q->n];
if (q->n < q->alloc / 2 && q->n >= 16)
q->buf = realloc(q->buf, (q->alloc /= 2) * sizeof(b[0]));
return out;
}
Use in main():
/* pop them and print one by one */
int c;
while ((c = priq_pop(q, &p)))
printf("%d: %d\n", p, c);
I'm starting with C, so I will be gratefull for any help.
You can declare your structures like so:
typedef struct queue_element_struct { // It's good practice to name your structs
int x,y;
int pri;
} queue_element_t;
typedef struct priority_queue_struct {
queue_element_t *buf;
int n, alloc;
} pri_queue_t, *pri_queue; // Don't know what `*pri_queue` is for
Then change your function to return a pointer to a queue_element_t structure
queue_element_t * priq_pop(pri_queue q, int *pri)
Change
int out;
if (q->n == 1) return 0;
q_elem_t *b = q->buf;
out = b[1].y;
To
// Create new pointer to queue_element_t structure
// that will be returned by this function
queue_element_t *out;
out = (queue_element_t *) malloc(sizeof(queue_element_t));
if (! out) {
// Could not allocate
}
if (q->n == 1) return 0;
// Set data from queue
out->x = q->buf[1].x;
out->y = q->buf[1].y;
I don't know exactly what your function does, but that is how you return a structure in C.
You said you're just starting with C, so I recommend:
“Code Complete” book by Steve McConnell. It is very useful to comment your code (no matter how small)
properly name your variables: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Variable_Names
learn about pointers. All you can read about them, read it.
You could make your queue data of type struct point
Structs:
typedef struct point{int PointX; int PointY;} q_data;
typedef struct { q_data d; int pri; } q_elem_t;
typedef struct { q_elem_t *buf; int n, alloc; } pri_queue_t, *pri_queue;
Pop function:
q_data priq_pop(pri_queue q, int *pri)
{
q_data out = {0,0};
if (q->n == 1) return out;
q_elem_t *b = q->buf;
out = b[1].d;
if (pri) *pri = b[1].pri;
/* pull last item to top, then down heap. */
--q->n;
int n = 1, m;
while ((m = n * 2) < q->n) {
if (m + 1 < q->n && b[m].pri > b[m + 1].pri) m++;
if (b[q->n].pri <= b[m].pri) break;
b[n] = b[m];
n = m;
}
b[n] = b[q->n];
if (q->n < q->alloc / 2 && q->n >= 16)
q->buf = realloc(q->buf, (q->alloc /= 2) * sizeof(b[0]));
return out;
}
Use in main():
/* pop them and print one by one */
q_data c;
while ((c = priq_pop(q, &p)))
printf("%d: %d, %d\n", p, c.PointX, x.PointY);
Something like this should do the trick. I didn't test it though, so there might be errors.
good luck!
In C++ you would use a vector or something similar to store an array of Unfortunately you can't fall back on this.
Why not use an array though, you could have your queue be an array of q_elem_t?
q_elem_t *my_array = q_elem_t array[100]; //pseudo code
For more about making an array of structs see here: How do you make an array of structs in C?
The only thing with an array is that you need to either malloc an arbitrary size (i.e. array[100]) or you need to dynamically control the memory of the array. If you are starting out it might just be best to declare an array of size 100.
To me it looks like the confusion is in the lack of datastructure. Array is a good starting point but if you want to learn more check out linked lists and things like that.