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.
Related
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.
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.
I have a struct person that has the following elements, defined in data.h
typedef struct person{
char firstName[20];
char familyName[20];
char telephoneNum[20];
int type; // 0 = student / 1 = employee;
}newPerson;
I created an array of person[MAX_PERSONS] that is initialized in my menu() function. I then have an addFirstName(newPerson pers) function. However when I try to test print format using my printFormat(newPerson pers)function, I get blank, instead of the inputted name.
I have included the menu(), addFirstname(newPerson pers), and printFormat(newPerson pers) function below. I was wondering if anyone could tell me the reason for this. Any help or pointers would be appreciated. Thank you in advance.
int menu(){
int num = 0;
newPerson person[MAX_PERSONS];
int option; // for user input for menu
printf("\n\tPlease choose one of the following options to continue (0-9): ");
scanf("%d", &option );
printf("\n\tYou selected %d\n", option);
if (option == 0){ //program will close
printf("\tProgram will now close.\n");
exit(1);
}
if (option == 1){ //program will ask for name input
addRecord(person[num]);
printFormat(person[num]);
char choice[0];
printf("\n\t\tWould you like to enter another record? (y/n): ");
scanf("%s", choice);
if (choice[0] == 'y'){
num++;
addRecord(person[num]);
}
if (choice[0] == 'n'){
num++;
mainMenu();
}
/*
IF YES, THEN NUM++
THEN RUN ADDRECORD(PERSONNUM) AGAIN.
IF NO, THEN RETURN TO MAIN MENU.
PRINTMENU
THEN RUN MENU AGAIN
*/
}
printf("\n\tNot a valid option, please try again // THE END OF MENU FUNCTION\n");
return 0;
}
void addFirstName(newPerson pers){
char firstName[20];
printf("\n\tEnter first Name: ");
scanf("%20s", firstName);
strcpy(pers.firstName, firstName);
printf("\n\tThe name entered is %s", pers.firstName);
}
void printFormat(newPerson pers){
printf("\t\tThe name is %s", pers.firstName);
}
It's because you pass the structure to addFirstName by value meaning that the function receives a copy of the structure. And changing a copy will of course not change the original.
While C does not support passing arguments by reference, it can be emulated using pointers. So change the addFirstName function to receive a pointer to the structure as its argument.
Your big problem is that you are passing structures by value instead of by pointers. This result in that you change copies of original objects inside your function addFirstName and not the original object. You should declare it as:
void addFirstName( newPerson* pers);
void printFormat( newPerson* pers);
Example:
#include <stdio.h>
void call_by_value(int x) {
printf("Inside call_by_value x = %d before adding 10.\n", x);
x += 10;
printf("Inside call_by_value x = %d after adding 10.\n", x);
}
int main() {
int a=10;
printf("a = %d before function call_by_value.\n", a);
call_by_value(a);
printf("a = %d after function call_by_value.\n", a);
return 0;
}
this will produce:
a = 10 before function call_by_value.
Inside call_by_value x = 10 before adding 10.
Inside call_by_value x = 20 after adding 10.
a = 10 after function call_by_value.
I am writing a program to create a structure named 'student'. I need to input various data about a particular student. Here is my program till now.
#include<stdio.h>
#include<stdlib.h>
struct student
{
char* name;
int id;
float marks_1;
float marks_2;
};
void main()
{
int num, var_i, var_j, var_k, var_l, duplicated_id = 0;
printf("Enter number of students\n");
scanf("%d", &num);
struct student s[num];
printf("Enter the data for the students\n");
for (var_i = 0; var_i < num; var_i++)
{
var_j = var_i + 1;
printf("Enter name of student_%d\n", var_j);
scanf(" %[^\n]%*c", &s[var_i].name);
printf("Enter id of student_%d\n", var_j);
scanf("%d", &s[var_i].id);
for (var_k = 0; var_k < var_i; var_k++)
{
if (s[var_k].id == s[var_i].id)
{
printf("Duplicate Id, program will exit");
return;
}
}
printf("Enter marks(sub_1) of student_%d\n", var_j);
scanf("%d", &s[var_i].marks_1);
printf("Enter marks(sub_2) of student_%d\n", var_j);
scanf("%d", &s[var_i].marks_2);
}
}
In the following for loop I am checking all the previously entered 'id' values to check if there is a duplicate. In case of a duplicate, the program will exit.
for(var_k=0;var_k<var_i;var_k++)
{
if(s[var_k].id==s[var_i].id)
{
printf("Duplicate Id, program will exit");
return;
}
}
Now instead of exiting the program I want to prompt the user to enter a different value. This goes on till he enters a unique value. How should I do it?
Any help appreciated.
This is wrong:
scanf(" %[^\n]%*c", &s[var_i].name);
You're passing the address of the pointer member name (i.e. you're passing a char **) to scanf() which per the format string, is expecting a char* and enough memory to hold the data it subsequently reads. This is invalid, is undefined behavior, and blindly overwrites data in the s[] array. Frankly I'm amazed this doesn't seg-fault your process.
Change this:
struct student
{
char* name;
int id;
float marks_1;
float marks_2;
};
To this:
struct student
{
char name[128]; // or some other suitable size.
int id;
float marks_1;
float marks_2;
};
And change this:
scanf(" %[^\n]%*c", &s[var_i].name);
To this:
scanf(" %[^\n]%*c", s[var_i].name);
I strongly suggest a size-limiter on that scanf() call as well, but I leave that to you to discover. Read about the API here.
Just use a loop.
here is some psudocode
bool isDuplicate = false
do
{
GetInput()
isDuplicate = CheckForDuplicate()
}while(isDuplicate);
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.