sorting structure elements in C - c

I have the following code, in which I must sort book titles by alphabetical order. this is the code I have and am unsure of how to perform the actual sort. any help regarding how to sort more than 2 books would also be appreciated, because the user is prompted to enter up to 30 books.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
struct Books
{
char title[256];
char author[256];
char genre[256];
int qualityRATE;
int pages;
};
int numberbook = 1;
int casee;
int booksnumber;
int i;
int main()
{
char again;
do
{
printf("how many books will you be entering today?");
scanf("%i", &booksnumber);
printf("Enter the information for your book.\n Name\n Author\n Genre\n quality rating\n\n");
struct Books book1;
struct Books book2;
scanf("%s", book1.title);
scanf("%s", book2.title);
printf("The title of book %i is: %s\n", numberbook, book1.title);
printf("The title of book %i is: %s\n", numberbook, book2.title);
printf("how would you like to sort?\n 1: By title\n 2: by Author\n 3: by pages\n\n");
scanf("%i", &casee);
switch(casee)
{
case 1:
for(i = 1; i < booksnumber, i++;)
{
if(strcmp(book[i].title, book[i+1].title) < 0)
strcpy(book[i+1].title, book[i].title);
else
if(strcmp(book[i+1].title, book[i].title) < 0)
strcpy(book[i].title, book[i+1].title);
}
printf("\n%s\n", book1.title);
break;
case 2:
break;
}
printf("Another book?\n");
numberbook++;
scanf("%s", &again);
}
while(again == 'y');
return 0;
}

I see in your code some problems:
You have to initialize an array of book structures, not book1 and book2, declaring:
struct books book[nnn] /* where nnn is the maximum number of book */
You have to use a counter (should be booksnumber) starting from 0 into the do while loop
You have to use scanf using book[booksnumber] and increment booksnumber for each scanf.
If you want a solid sort engine I suggest you to use the function qsort (qsort is a C library function in stdlib.h)
see: www.cplusplus.com/reference/cstdlib/qsort
A correct way to sort the item should be that in the following code:
struct Books app;
int i,j;
for(i=0;i<booksnumber;i++) {
for(j=i+1;j<booksnumber;j++) {
if (strcmp(book[i].title,book[j].title)<0) {
app=book[i];
book[j]=book[i];
book[i]=app;
}
}
}
I think that the first for loop should be better as below, but I have written this code on the fly and then I have not verified its behavour.
for(i=0;i<booksnumber-1;i++)
I've not verified if the direction of the sort is as you require, if is not you may change the "sign" of the comparation inverting it. IE:
if (strcmp(book[i].title,book[j].title)>0)

For just two books you can use swap. And I think you also need to swap all book properties, not just its title :
void swapBook(struct Books *a, struct Books *b) {
struct Books c = *a; /* backup first book */
*a = *b; /* replace first book with second book */
*b = c; /* replace second book with the backup of first book */
}
Then you should be able to use it like this:
if ( strcmp(book[i].title, book[i+1].title) < 0 ) {
swapBook( &book[i], &book[i+1] );
}
For more than two books, this is not going to work, you need to use qsort.

Related

Finding three leaders from arrays

Thank you for visiting this question. I know this looks like a question from a book which it totally is. I couldn't find the solution for this anywhere and I cant get one thing. Supposedly the code compare things like studs[i].score within for loop, but why it can assign the value of studs[i].score to another element of the struct like say first.score? The same goes for studs[i].name = first.name the program wont even compile. Any input matter, have been sitting with this for a week.
Have a great day!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stud {
char name[50];
float score;
};
//Please do not modify struct stud
//You are only allowed to modify inside printThreeLeaders
void printThreeLeaders(struct stud studs[], int count) { //why is count here? C arrays do not carry any size indicator, we
//must explicitly pass the number of elements in as an argument
//Please do not modify the content of studs array
struct stud first, second, third;
//Your code here
for (int i=0;i<count;i++){
if (studs[i].score>third.score){
if(studs[i].score>second.score){
if (studs[i].score>first.score){
studs[i].score=first.score;
studs[i].name=first.name;
}
}studs[i].score=second.score;
studs[i].name=second.name;
}studs[i].score=third.score;
studs[i].name=third.name;
}
//Please find the top three highest scoring students on the leaderboard
//and print out their names and scores.
//You are allowed to use string functions such as strcmp or strcpy
//Although you might not need them
//Please do not modify the following code
printf("Leader board:\n");
printf("First place: %s, %.2f\n", first.name, first.score);
printf("Second place: %s, %.2f\n", second.name, second.score);
printf("Third place: %s, %.2f\n", third.name, third.score);
}
//Please do not modify main function
int main(void) {
struct stud students[20];
int stud_count = 0;
char temp_name[50];
float grade = 0;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
while (grade != -1)
{
scanf("%s", temp_name);
students[stud_count].score = grade;
strcpy(students[stud_count].name, temp_name);
stud_count ++;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
}
if(stud_count > 2) {
printThreeLeaders(students, stud_count);
}
return 0;
}
A few issues:
You do modify the studs array with: studs[i].score=second.score;
The three variables first, second, and third are uninitialized so you have UB (undefined behavior)
You don't need to use str* functions to copy the name if you copy the whole struct.
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud {
char name[50];
float score;
};
// Please do not modify struct stud
// You are only allowed to modify inside printThreeLeaders
void
printThreeLeaders(struct stud studs[], int count)
{
// why is count here? C arrays do not carry any size indicator, we
// must explicitly pass the number of elements in as an argument
// Please do not modify the content of studs array
// NOTE/BUG: first/second/third are _not_ initialized
#if 0
struct stud first, second, third;
#else
struct stud first = { .score = -1 };
struct stud second = { .score = -1 };
struct stud third = { .score = -1 };
#endif
// Your code here
for (int i = 0; i < count; i++) {
const struct stud *st = &studs[i];
float score = st->score;
if (score > first.score) {
third = second;
second = first;
first = *st;
continue;
}
if (score > second.score) {
third = second;
second = *st;
continue;
}
if (score > third.score) {
third = *st;
continue;
}
}
// Please find the top three highest scoring students on the leaderboard
// and print out their names and scores.
// You are allowed to use string functions such as strcmp or strcpy
// Although you might not need them
// Please do not modify the following code
printf("Leader board:\n");
printf("First place: %s, %.2f\n", first.name, first.score);
printf("Second place: %s, %.2f\n", second.name, second.score);
printf("Third place: %s, %.2f\n", third.name, third.score);
}
// Please do not modify main function
int
main(void)
{
struct stud students[20];
int stud_count = 0;
char temp_name[50];
float grade = 0;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
while (grade != -1) {
scanf("%s", temp_name);
students[stud_count].score = grade;
strcpy(students[stud_count].name, temp_name);
stud_count++;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
}
if (stud_count > 2) {
printThreeLeaders(students, stud_count);
}
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
Here is the test input I used:
1 Fred
2 Bob
3 Alice
4 John
5 Mary
6 Frank
7 Abel
8 Cain
9 Peter
10 Kilroy
11 Smith
12 Jones
-1
Here is the [cleaned up] program output:
Leader board:
First place: Jones, 12.00
Second place: Smith, 11.00
Third place: Kilroy, 10.00
UPDATE:
Amazing, it does work. The problem was in initialization of first, second and third. With this edits it does work. My incorrect reasoning was that initialization happened at 'struct stud first second third'. –
JEDi455
C is all about minimalism and speed.
Initialization [of stack based variables] is not done by default for speed.
Here, for this problem, explicit initialization was needed.
But, in another problem, suppose we had (e.g.):
int x,y,z;
If we explicitly assign them values with:
/* some small blob of code unrelated to x/y/z ... */
x = funcA();
y = funcB(x);
z = funcC(x,y);
Then, we'd be cursing the compiler for wasting time by initializing them to default values, only to overwrite those values with our explicit code.
That is, if the compiler always treated:
int x,y,z;
as:
int x = 0, y = 0, z = 0;
We'd not want the compiler to "help" us in this way. That is, if we wanted the latter, we'd have written that.
C gives the programmers full control [and assumes they know what they're doing]. The compiler will try to help by flagging statements with errors or warnings, but it's often up to the programmer.

Trying to create a loop that has an array continuously add data within it that the user creates

I just want to quickly note that im a third semester CS student so im fairly new to C and I just really want help on a project im creating for myself.
Okay so basically im trying to have it so that I create a question that the code asks the user such as "Type in your name, age, and house" (im trying to create this harry potter quiz for my gf). So I want to store the user information within an array inside of this structure I created. I want it so that the user puts down their information and it stores it in the structure and then later the user can add another person to compare their results to and itll store this users data as well and whenever you want to print it all itll print it. Im hoping this makes sense so please feel free to ask questions but ill
#include<stdio.h>
#include <stdlib.h>
#include "sortinghatquiz.h"
#define maxNum 100
int main_sorting_quiz()
{
sorting_hat_menu();
sorting_hat_switch();
}
int sorting_hat_menu()
{
char array[]={"."};
for (int i = 0; i < 50; i++)
{
printf("%c\n", array[0]);
}
printf("\n\n\t\t\tWelcome to the Hogwarts Sorting Hat Quiz!!!\n");
printf("\t\t\t________________________________________\n");
printf("\t\t\t1 - Start the quiz!\n\t\t\t2 - Find Existing Quiz!\n\t\t\t3 - Compare results with another user!\n\t\t\t4 - Return to main menu!\n\n");
}
int sorting_hat_switch()
{
int choice_quiz,x;
printf("\n\t\t\tChoose your option: ");
scanf("%d", &choice_quiz);
switch (choice_quiz)
{
case 1:
start_quiz(x);
break;
case 2:
find_quiz();
break;
case 3:
compare_results();
break;
default:
break;
}
}
int start_quiz(quizinfo *i)
{
quizinfo A[maxNum] = {};
for (i = 0; i < 4; i++)
{
start_quiz_menu(i);
return i;
}
printf("\nHeres the first persons data %s, %s, %s\n", A[0].name, A[0].age, A[0].house);
printf("\nHeres the second persons data %s, %s, %s\n", A[1].name, A[1].age, A[1].house);
printf("\nHeres the third persons data %s, %s, %s\n", A[2].name, A[2].age, A[2].house);
printf("\nHeres the fourth persons data %s, %s, %s\n", A[3].name, A[3].age, A[3].house);
//Type in your name
//Type in your age
//Type in your desired house (this wont influence your decision)
//All of this data needs to be stored within structure
}
int start_quiz_menu(quizinfo *x)
{
int i;
quizinfo A[maxNum] = {};
printf("\t\t\tType your name in: ");
scanf("%s", A[i].name);
printf("\n\t\t\tType in your age: ");
scanf("%s", A[i].age);
printf("\n\t\t\tType in your desired house to see if you think you know yourself: ");
scanf("%s", A[i].house);
printf("\n\n\t\t\tHello %s, at the age of %s you have begun your quest to see which hogwarts house you are placed in.\n\t\t\tLets see if %s really is your true house.....\n", A[i].name, A[i].age, A[i].house);
}
int find_quiz()
{
printf("Find Quiz Test 1");
}
int compare_results()
{
printf("Compare results Test 1");
}
Im experimenting with libraries so its all connected and compiled into one main.c file so heres the .h file for this piece of code
#ifndef _SORTINGHATQUIZ_H_
#define _SORTINGHATQUIZ_H_
typedef struct
{
char name[100];
int age[10];
char house[100]
}quizinfo;
int main_sorting_quiz();
int sorting_hat_menu();
int start_quiz(quizinfo *i);
int start_quiz_menu(quizinfo *x);
int find_quiz();
int compare_results();
#endif
Also like I said, im fairly new to this so If theres anything I can optimize to make more efficient then I would love to hear some advice. Thanks!

Having problems displaying structure array content

I want to display structure members based on user input, but I don't know if I've stored the input properly.
When I try display all people, it just outputs random numbers.
These are the structures and function prototypes
#define MAX_NAME_LEN 15
#define MAX_NUM_PERSON 4
#define MAX_JOB_LENGTH 20
typedef struct birth_date
{
int month;
int day;
int year;
} person_birth_t;
typedef struct person
{
char pName[MAX_NAME_LEN];
char job[MAX_JOB_LENGTH];
person_birth_t birth_t;
} person_t[MAX_NUM_PERSON];
void print_menu (void);
void scanPerson(person_t p, int);
void displayPeople(person_t p);
This is the main code for the program, a menu is printed asking user to input a number, if a user enters 1 then it prompts them to add a person. Entering 2 displays all people entered.
int main(void)
{
/* TODO */
print_menu();
return 0;
}
void print_menu (void)
{
int choice;
person_t p;
static int index = 0;
int *indexP = NULL;
indexP = &index;
/*Print the menu*/
scanf("%d", &choice);
switch (choice)
{
case 1:
if (index < MAX_NUM_PERSON){
scanPerson(p, index);
++*indexP;
print_menu();
} else {
printf("Can't add more people - memory full \n");
print_menu();
}
break;
case 2:
displayPeople(p);
break;
case 3:
exit(0);
break;
default:
print_menu();
}
}
/*function called when add person is chosen from menu */
void scanFlight(person_t p, int index){
/*printf to enter name*/
scanf(" %s", p[index].pName);
/*printf to enter job*/
scanf("%s", p[index].job);
}
void displayPeople(person_t p){
for(int i = 0; i < MAX_NUM_PERSON; i++){
printf("%s %d-%d-%d %s \n",p[i].pName
,p[i].birth_t.month
,p[i].birth_t.day
,p[i].birth_t.year
,p[i].job);
}
}
I've tried other ways to take input and add it to a struct array, but I'm just not sure how to do it right.
person_t p;
Here, you use the local variable p (in print_menu function), so each recursion, you just print the parameters of the local variable that is not initialized.
To solve it, you can declare p as the global variable.
OT, in scanFlight function, to avoid overflow, you should change the scanf function to:
/*printf to enter name*/
scanf("%14s", p[index].pName);
/*printf to enter job*/
scanf("%20s", p[index].job);
And, rename scanPerson to scanFlight, because i do not see any implementation of scanPerson function in your code. I think it's typo, no ?
None of the methods were working, so instead of trying to figure it out, I scrapped the static index and indexP.
Instead, I initialized p with malloc:
person_t *p= malloc(MAX_NUM_PERSON * sizeof(person_t));
I changed the scan function to accommodate for the change and made index a pointer instead, and I made the display function pass the index.
When I ran it, the output was correct.

When I run this program, after entering a name, I get a segmentation fault. How can I fix this to make it work properly?

Restauraunt.c
This program allows you to create a restaurant menu, stores it in a file, and then rates each item on the menu. It uses file functions to output everything into a file that can then be viewed through almost any program. When the program gets to the line in nametofile() 'fprintf(restauraunt, "%s Restauraunt\n\n",name);' the program gives a segmentation fault. I do not know why it is doing this, I have attempted several different methods of debugging, but none have worked. If you have any suggestions, please comment them below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
FILE *restauraunt;
char name[20];
char item[20];
char price[20];
int count=0;
void nametofile();
void rate();
void itemtofile();
void counter();
void renamefile();
int main()
{
int i,j;
int num;
printf("Restauraunt Creator\n\n");
printf("Enter the name of your restauraunt:\n");
scanf("%s",&name);
nametofile();
printf("\nEnter the number of items to be included in your menu:\n");
scanf("%d", &num);
/* Cycles through each entry to the menu */
for(i=0;i<num;i++)
{
counter();
fpurge(stdin);
printf("\nPlease enter the name of item number %d:\n",count);
scanf("%s", &item);
printf("\nPlease enter the price of item number %d:\n",count);
scanf("%s", &price);
itemtofile();
rate();
}
renamefile();
}
/*void nametofile()
{
restauraunt = fopen("restauraunt","w");
fprintf(restauraunt, "%s Restauraunt\n\n",name);
fclose(restauraunt);
}*/
/* The function that sends the restaurant name to the file */
void nametofile()
{
int i;
i = strlen(name);
name[i+1] = '\0';
restauraunt = fopen("restauraunt","w");
/* the line that gives a segmentation fault */
fprintf(restauraunt, "%s Restauraunt\n\n",name);
fclose(restauraunt);
}
/* rates each menu item */
void rate()
{
int rating;
srandom((unsigned)time(NULL));
restauraunt = fopen("restauraunt", "a");
rating = random() % 5 + 1;
fprintf(restauraunt,"Your food's rating was:\t%d stars!",rating);
switch(rating)
{
case 1:
{
fprintf(restauraunt," Here's why: Your food was not very good tasting and the price was ridiculously high.\n");
break;
}
case 2:
{
fprintf(restauraunt," Here's why: Your food was mildly good tasting and the price was too high.\n");
break;
}
case 3:
{
fprintf(restauraunt," Here's why: Your food was somewhat good tasting and the price was fair.\n");
break;
}
case 4:
{
fprintf(restauraunt," Here's why: Your food was quite good tasting and the price was very nice.\n");
break;
}
case 5:
{
fprintf(restauraunt," Here's why: Your food was very delicious and the price was amazingly low.\n");
break;
}
}
}
/* sends each item to the file */
void itemtofile()
{
restauraunt = fopen("restauraunt","a");
fprintf(restauraunt, "%s: $%s\nRating:",item,price);
fclose(restauraunt);
}
/* counts up one each time function is called */
void counter()
{
count += 1;
}
/* renames the file at the end */
void renamefile()
{
int x,y;
char bridge[] = { "menu" };
name[0] = tolower(name[0]);
x = strcat(name,bridge);
y = rename("restauraunt",name);
}
name is a char array. When you pass it to scanf or other functions, it decays to a pointer, so you do not need the & operator:
scanf("%19s", name);
When you read strings with scanf, it is a good idea to pass the size limit: this lets you avoid buffer overruns. Since name is declared as char[20], you pass 19, because one more char needs to be reserved for the null terminator.

How to approach and optimize code in C

I am new to C and very much interested in knowing how to approach any problem which has more than 3 or 4 functions, I always look at the output required and manipulate my code calling functions inside other functions and getting the required output.
Below is my logic for finding a students record through his Id first & then Username.
This code according to my professor has an excessive logic and is lacking in many ways, if someone could assist me in how should I approach any problem in C or in any other language it would be of great help for me as a beginner and yes I do write pseudo code first.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int id; //Assuming student id to be unique
int age;
char *userName; //Assuming student userName to be unique
char *dept;
}student; // Alias "student" created for struct
student* createstruct(); // All function prototype declared
student* createArray();
void addstruct(student* s2);
void searchChar(student* s2,int num);
void searchInt(student* s2,int num);
student* createstruct() // function createStruct() to malloc data of struct student.
{
student *s;
s = (student*)malloc(sizeof(student));
s->userName = (char*)malloc(sizeof(char)*32);
s->dept = (char*)malloc(sizeof(char)*32);
printf("please enter id ");
scanf("%d",&s->id);
printf("please enter age ");
scanf("%d",&s->age);
printf("please enter userName ");
scanf("%31s",s->userName);
printf("please enter department ");
scanf("%31s",s->dept);
printf("\n");
return s;
}
student* createArray()
{
student *arr; //declaration of arr poiter, type struct student
arr = (student*)malloc(sizeof(student)*10); // memory allocated for a size of 10
return arr;
}
void addstruct(student *s2) // function for adding data to the structures in array
{
int i,num;
student* s1;
printf("please enter the number of records to add:");
scanf("%d",&num);
printf("\n");
if(num>0 && num<11)
{
for(i=0;i<num;i++) // if user want to enter 5 records loop will only run 5 times
{
s1 = createstruct();
s2[i].id = s1->id; // traversing each element of array and filling in struct data
s2[i].age = s1->age;
s2[i].userName = s1->userName;
s2[i].dept= s1->dept;
}
}
else if(num>10) // if user enters more than 10
{
for(i=0;i<10;i++) // loop will still run only 10 times
{
s1 = createstruct();
s2[i].id = s1->id;
s2[i].age = s1->age;
s2[i].userName = s1->userName;
s2[i].dept = s1->dept;
}
printf("Array is full"); // Array is full after taking 10 records
printf("\n");
}
searchInt(s2,num); // Calling searchInt() function to search for an integer in records
searchChar(s2,num); // Calling searchChar() function to search for a string in records
free(s1);
free(s2);
}
void searchChar(student* s2,int num) // function for searching a string in records of structure
{
char *c;
int i;
c = (char*)malloc(sizeof(char)*32);
printf("please enter userName to search ");
scanf("%31s",c);
printf("\n");
for (i=0;i<num;i++) //num is the number of struct records entered by user
{
if ((strcmp(s2[i].userName,c)==0)) //using strcmp for comparing strings
{
printf("struct variables are %d, %d, %s, %s\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in userName matches: <%s>\n",c);
break;
}
}
}
void searchInt(student* s2,int num) //searchs for an integer and prints the entire structure
{
int i,z;
printf("please enter id to search ");
scanf("%d",&z);
printf("\n");
for (i=0;i<num;i++)
{
if (s2[i].id == z)
{
printf("struct variables are %d, %d, %s, %s\n\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in id matches: <%d>\n\n",z);
break;
}
}
}
int main(void)
{
student *s2;
s2 = createArray();
addstruct(s2);
return 0;
}
I'm not going to go into optimizing, because if you wanted better theoretical performance you would probably go with different data structures, such as ordered arrays/lists, trees, hash tables or some kind of indexing... None of that is relevant in this case, because you have a simple program dealing with a small amount of data.
But I am going to tell you about the "excessive logic" your professor mentioned, taking your searchInt function as an example:
for (i=0;i<num;i++)
{
if (s2[i].id == z)
{
printf("struct variables are %d, %d, %s, %s\n\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in id matches: <%d>\n\n",z);
break;
}
}
The thing here is that every time around the loop you're testing to see if you're at the last element in the loop. But the loop already does that. So you're doing it twice, and to make it worse, you're doing a subtraction (which may or may not be optimized into a register by the compiler).
What you would normally do is something like this:
int i;
student *s = NULL;
for( i = 0; i < num; i++ )
{
if( s2[i].id == z ) {
s = &s2[i];
break;
}
}
if( s != NULL ) {
printf( "struct variables are %d, %d, %s, %s\n\n",
s->id, s->age, s->userName, s->dept );
} else {
printf("nothing in id matches: <%d>\n\n",z);
}
See that you only need to have some way of knowing that the loop found something. You wait for the loop to finish before you test whether it found something.
In this case I used a pointer to indicate success, because I could then use the pointer to access the relevant record without having to index back into the array and clutter the code. You won't always use pointers.
Sometimes you set a flag, sometimes you store the array index, sometimes you just return from the function (and if the loop falls through you know it didn't find anything).
Programming is about making sensible choices for the problem you are solving. Only optimize when you need to, don't over-complicate a problem, and always try to write code that is easy to read/understand.

Resources