How should I solve the function's problem? - c

I'm working on a project for my uni and I got stuck. First of all, these are the structures and #define that I use, and then below that are the two functions that I use:
#define NAME_SIZE 51
#define NATIONALITY_SIZE 20
#define SEX_SIZE 8
#define EVENT_SIZE 8
#define CHIEF_SIZE 5
typedef struct competitor
{
int id;
char name[NAME_SIZE];
char nationality[NATIONALITY_SIZE];
char sex[SEX_SIZE];
double weight;
char event[EVENT_SIZE];
}competitor;
typedef struct comp_ldata
{
competitor data;
struct comp_ldata* next;
}comp_ldata;
typedef struct referee
{
int ref_id;
char rname[NAME_SIZE];
char nationality[NATIONALITY_SIZE];
char chief[CHIEF_SIZE];
}ref;
typedef struct ref_ldata
{
ref data;
struct ref_ldata* next;
}ref_ldata;
bool ref_nationality(ref_ldata* sorted, char* ref_nat)
{
bool status = false;
ref_ldata* temp_s;
temp_s = sorted->next;
for(int i = 0 ; temp_s != NULL ; temp_s=temp_s->next)
{
if (strcmp(ref_nat , (temp_s->data).nationality) == 0)
i++;
if (i >= 2)
{
status = true;
return status;
}
}
return status;
}
I am stuck, although my program runs well, I don't know how to change the function. The ref_nationality function got 2 parameters, first is the sorted list and the referee's nationality. As you can see it will return a true value if it has been used more than two times and a false if not.
This function is a part of a bigger program and the concept is to draw the athletes and assign 7 judges to them. This function aim would be to have a maximum of 2 judges of the same nationality for each fight. So if in the first match there were two germans and two italians, in the second fight there could again be two Germans, two Italians etc...
However, as I have written, only two judges of the same nationality are allowed in total. What should I change to achieve the desired result?
Also sorry, I the sites didn't allow me to post more code because then I had to write more description but I didn't know what else to write. If the rest of the code is needed I will post it in the comments.

Related

Comparing a string with a struct member in C

I am attempting to create a small ticket pricing system. The user inputs the people accompanying them to the theme park as a command line argument (senior/adult/child/student) including themselves (what they are according to that list) and I compare the command line arguments with the struct members named tier - this part will be completed later with pointers to check each one, but until then I'm just attempting to get this lesser version of the completed program to work and cannot seem to. It won't allow me to compare a struct member (string) with a command line argument. I'm finding rectifying this slightly confusing because the error message
strcmpare.c:17:29: error: use of undeclared identifier 'senior' if (strcmp(argv[a], senior.tier[a]) == 0)
isn't yielding any clues as to what I should do. Here's the code so far (I am using the cs50 course and sandbox, thus the cs50.h header file. Apologies in advance, I'm not sure what the equivalent is in C):
#include <cs50.h>
#include <stdio.h>
#include <string.h>
struct ages
{
char tier[7];
int price;
};
void structorganizer(struct ages senior, struct ages adult, struct ages child, struct ages student);
int main(int argc, string argv[])
{
for (int a = 0; a <= (argc-1); a ++)
{
if (strcmp(argv[a], senior.tier[a]) == 0)
{
printf("no errors");
return 0;
}
printf("scrutinise more");
return 1;
}
}
void structorganizer(struct ages senior, struct ages adult, struct ages child, struct ages student)
{
strcpy(senior.tier, "Senior");
senior.price = 10;
strcpy(adult.tier, "Adult");
adult.price = 30;
strcpy(child.tier, "Child");
child.price = 0;
strcpy (student.tier, "Student");
student.price = 20;
}
I'm finding rectifying this slightly confusing because the error message isn't yielding any clues as to what I should do.
On the contrary, it actually tells you EXACTLY what to do. That's not always the case with error messages, but here it is. The variable senior is not declared, so you need to declare it.
So where should you do that. You seem to want to use structorganizer to initialize things. Usually, global variables are a thing you want to avoid and there are certainly better ways of solving this, but just to quickly get things working. Remove all arguments from the function and declare global variables before, and call structorganizer first thing in main like this:
struct ages
{
char tier[8]; // Changed to 8 because you need one more than the string length
int price;
};
// Evil global variables, just to make code work with as little
// changes as possible
struct ages senior, adult, ages, child, student;
void structorganizer(); // Init the evil globals
int main(int argc, string argv[])
{
structorganizer();
// Continue as before
That should be enough to just get the code working, but you clearly need to spend more time with the basics here. The code you're writing right now is too advanced for you. No shame in trying though :)
There are absolutely cases where it's good to use an initializer function, but I cannot really say that this is one of them. I would declare them in main like this:
int main(int argc, string argv[])
{
struct ages senior = { .tier = "Senior", .price=10 };
struct ages adult = { .tier = "Adult", .price=30 };
struct ages child = { .tier = "Child", .price=0 };
struct ages student = { .tier = "Student", .price=20 };

Pass a string in a struct to a function and return it

I want to return the name of the smallest city population-wise, if it is the second city. (Please don't mind the if statement, I know it's bland), the missing return is what bothers me.
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
typedef struct Coordinate{
int x,y;
}Coordinate;
typedef struct city{
char name[20];
int population;
Coordinate coordinates;
}city;
char *rSmallestCity(city **cl, int n)
{
char *rtrn = NULL;
if(cl[n-2]->population>cl[n-1]->population)
{
rtrn = &cl[n-1]->name;
}
return rtrn;
}
int main()
{
city c1 ={.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4};
city c2 ={.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2};
city *clist[2];
clist[0]=&c1;
clist[1]=&c2;
printf("\n%s is smallest\n",rSmallestCity(clist,2));
}
warning: assignment to 'char ' from incompatible pointer type 'char ()[20]' [-Wincompatible-pointer-types]|
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
A good question. And your assumption is correct. Creating a variable inside a function it's existence ends upon leaving the function. But in this case, because the struct member name is already a char * you do not need to create another variable. Just return c1.name. (see code example below.)
A few other suggestions:
In the struct declaration:
typedef struct Coordinate{
int x,y;
}Coordinate;
You've used the same symbol (Coordinate) for the struct name, and for it's typedef. This is not a good practice. If you need both a struct name and a typedef, pick different symbols. BTW, in this this example, only one or the other is needed. Say you pick the typedef, then the struct is completely defined by:
typedef struct {
int x,y;
}Coordinate;
That suggestion applies to both struct declarations in your example code.
The signatures for the main function do not include int main(){...} rather
int main(void){..., return 0;} and int main(int argc, char *argv[]){..., return 0;}
The following code example illustrates some of the other suggestions for improvements in comments under your post,
typedef struct {
int x,y;
}Coordinate;
typedef struct {
char name[20];
int population;
Coordinate coordinates;
}city;
//return char * rather than char to allow for full null terminated char array (string)
char * rSmallestCity(city c1[],int cityCount)//generisize function prototype to
{ //to easily accommodate bigger arrays if needed
long long size, sizeKeep = 8e9; //index and population. initialize larger than possible population
int indexKeep = 0;
//note you do not need to define a char *, the struct already contains one
for(int i=0; i<cityCount; i++)//use a loop rather than a single comparison, keep the smalles
{
size = c1[i].population;
sizeKeep = (size < sizeKeep) ? indexKeep = i, size : sizeKeep;
}
printf("\n%s\n",c1[indexKeep].name);
return c1[indexKeep].name;
};
int main(void)//use minimum signature for main, and call return before leaving.
{
//combining your original declarations and assignments for struct
//into a single declaration/definition.
city c1[] = {{.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4},
{.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2}};
int cityCount = sizeof(c1)/sizeof(c1[0]);
printf("\n%s is smallest",rSmallestCity(c1, cityCount));
return 0;
};
The solution that I originally left in comment under OP (remove & in the line &cl[n-1]->name;) needs some explanations to avoid problems later.
(It is an educational answer not a full answer on pointers, array decay, ... And many examples can be found on stackoverflow. I tried to simplify)
Try this simple code.
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1);
printf("%p\n",&myString1);
}
The output is the same, but an array name and the address of an array name are not the same. The array name is evaluated to the address of its first element. So it works in your case but a warning is issued during compilation and it is very important. Firstly, do not remove compilation warnings.
Now, try this code :
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1+1);
printf("%p\n",&myString1+1);
}
The outputs are different. Because myString1 is evaluated to char* and &myString1 to char [25]. So +1, in the first, case adds one (sizeof char) to the pointer and in the other case, it adds 25.
Delete the "&" in the line:
rtrn = &cl[n-1]->name;
To extremely simplify, you assigned an "address of char[]" to a char*, but array syntax makes it work regardless.

Trying to display to student data from file according to sorted student ID

I am not able to sort the data i am fetching from file, i want it to print to console by ascending order of ID, I am not able to convert char ID to integer ID to compare
struct student{
char ID[15];
char name[20];
char add[20];
char parname[20];
int Class;
float gpa;
long unsigned int phone_no;
};
void sort_accord_id()
{
while(fread(&stu,sizeof(stu),1,fp))
{
strcpy(s[count].ID,stu.ID);
strcpy(s[count].name,stu.name);
printf("ID:%s\n", stu.ID);
printf("\t%s",s[count].ID);
printf("\t%s",s[count].name);
count++;
}
for(i=0;i<=count-1;i++)
{
for(j=0;j<=count-1;j++)
{
if(s[j].ID-'0'<s[j+1].ID-'0')
{
temp=s[j];
s[j]=s[j+1];
s[j+1]=temp;
}
}
}
}
If it is reading properly to (what I'm assuming to be) the student struct 'object' stu, one approach would be to keep them all in an array (dynamically allocated on heap would be best, otherwise just large enough to keep them all [careful with that!]), then sort them with stdlib.h's qsort().
I can offer help on dynamic arrays if you want but some googling would also do the trick I'm sure.
If you had an array of student structs (which I also suggest you typedef, but for the sake of this answer's clarity I won't) called arr, you could sort them like so:
First #include <stdlib.h> at the top of your file
Then the following function to compare their ID's with strcmp:
int student_cmp(const void* a, const void* b)
{
struct student* studentA = (struct student*)a;
struct student* studentB = (struct student*)b;
return strcmp(studentA->ID, studentB->ID);
}
And finally, you can call qsort in your sort_accord_id() like so:
qsort(arr, 2, sizeof(struct student), student_cmp);
Let me know if you have other questions. And welcome to Stack Overflow!

How to set size of nested structure?

I'd like to make a simple database without making a dynamic sized array. I thought nested structure can help me, but so far it's nothing but pain. This was my idea when I started:
#include <stdio.h>
#define MAXDOG 50
#define MAXCHAR 20
struct allDog {
int size;
struct oneDog[MAXDOG] {
char dogName[MAXCHAR];
char OwnerName[MAXCHAR];
};
};
I'm pretty sure that my problem is the [MAXDOG] part after struct oneDog, can I give a static size somehow to the inner structure?
You can read the part of the exam I try to do below:
The program asks for the Dog's & Owner's name (MAX 50) then prints out the data. You can't use dynamic arrays...
You're overcomplicating things - try this:
#define MAXDOG 50
#define MAXCHAR 20
typedef struct { // struct which defines one dog
char dogName[MAXCHAR];
char ownerName[MAXCHAR];
} Dog;
typedef struct { // struct which contains array of dogs
int size; // no of dogs in array currently
Dog dogs[MAXDOGS]; // array of up to MAXDOGS dogs
} Dogs;
You sized the type not the member, syntax is:
struct allDog { // type
int size;
struct oneDog { // type
char dogName[MAXCHAR];
char OwnerName[MAXCHAR];
} dogs[MAXDOG]; // member
};
Take care to be consistent with caps in naming, member OwnerName should be written ownerName to be consistent with other members. Types are generally typed AllDog and OneDog, to differentiate in between members and types.

Array of struct pointers, invalid initializer error, in C

This code:
extern void *malloc(unsigned int);
struct Box {
int x, y ,w, h;
};
struct Wall {
char color[15];
struct Box *boxes[20];
};
int main(int argc, const char *argv[])
{
struct Wall *mywall = malloc(sizeof(struct Wall));
struct Box *myboxes[] = mywall->boxes;
return 0;
}
gives me invalid initializer error at line 14. What I am trying to do, is to get a copy of array of struct pointers, which are in a different struct.
Ouch; there are a number of problems here.
extern void *malloc(unsigned int);
Don't do that; use #include <stdlib.h> because that will be correct and what you wrote is typically incorrect (the argument to malloc() is a size_t, which is not necessarily an unsigned int; it might be unsigned long, or some other type).
struct Box {
int x, y ,w, h;
};
Apart from erratic space, struct Box is OK.
struct Wall {
char color[15];
struct Box *boxes[20];
};
And struct Wall is OK too.
int main(int argc, const char *argv[])
You aren't using argc or argv, so you'd be better using the alternative declaration of:
int main(void)
Original code again:
{
struct Wall *mywall = malloc(sizeof(struct Wall));
This allocates but does not initialize a single struct Wall. Of itself, it is OK, though you should check that the allocation succeeded before you use it. You also need to worry about allocating the struct Box items that the elements of the array will point to.
struct Box *myboxes[] = mywall->boxes;
You've got a minor catastrophe on hand here. You can't copy arrays like that. You haven't checked that you've got an array. Ignoring the error checking, you are stuck with one of:
struct Box *myboxes[] = { &mywall->boxes[0], &mywall->boxes[1], ... };
or:
struct Box **myboxes = &mywall->boxes;
I'm not convinced that you'd want the second version, for all it's shorter.
return 0;
I like to see return 0; at the end of main(), even though C99 allows you to omit it.
}
How about:
struct Box **myboxes = mywall->boxes;
?
Then you can do stuff like:
for ( int i = 0 ; i < 15 ; i++ )
mywall->boxes[i] = malloc(sizeof(Box));
Box* x = myboxes[1];
As the code is now, mywall->boxes isn't initialized.
NOTE: just re-read the question - this won't return a copy of the array, but point to the same location. There's no short solution for a copy without using memcpy or just copying the structs.

Resources