sort/search in stack [duplicate] - c

This question already has an answer here:
How to sort an array of structs in C?
(1 answer)
Closed 8 years ago.
I have created a stack system in C
It takes the First Name, Last name, and an employee number and the program runs fine.
#include<stdio.h>
#include<conio.h>
#define MAX 20
struct system
{
char first_name[15];
char surname[15];
}employee[20], temp;
int stack[MAX],front=-1,top=-1;
int i;
void push_element();
void pop_element();
void display_stack();
void display_first();
int main()
{
int option;
printf("STACK PROGRAM");
do
{
printf("\n\n 1.Push an element");
printf("\n 2.Pop an element");
printf("\n 3.Display stack");
printf("\n 4.Display first");
printf("\n 5.Display last");
printf("\n 6.Exit");
printf("\n Enter your choice: ");
scanf("%d",&option);
switch(option)
{
case 1: push_element();
break;
case 2: pop_element();
break;
case 3: display_stack();
break;
case 4: display_first();
break;
case 5: display_last();
break;
case 6: return 0;
}
}while(option!=6);
}
void push_element()
{
printf("\n Enter the first name: ");
scanf("%s",employee[i].first_name);
printf("\n Enter the Last name: ");
scanf("%s",employee[i].surname);
int num;
printf("\n Enter the employee number: ");
scanf("%d",&num);
i++;
if(front==0 && top==MAX-1)
printf("\n You have entered more than 20. Please delete a current input to make room. ");
else if(front==-1&&top==-1)
{
front=top=0;
stack[top]=num;
}
else if(top==MAX-1 && front!=0)
{
top=0;
stack[top]=num;
}
else
{
top++;
stack[top]=num;
}
}
void pop_element()
{
top--;
return top;
}
void display_stack()
{
int i;
if(front==-1)
printf("\n No Employees to display");
else
{
printf("\n List of employees:\n\n ");
printf(" Employee number First Name Surname\n\n");
for(i=front;i<=top;i++)
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
}
}
void display_first()
{
int i;
if(front==-1)
printf("\n No Employees to display");
else
{
printf("\n The first Employee in the stack is:\n\n ");
printf(" Employee number First Name Surname\n\n");
for(i=front;i<=top;i++)
break;
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
}
}
void display_last()
{
int i;
if(front==-1)
printf("\n No Employees to display");
else
{
printf("\n The last Employee in the stack is:\n \n");
printf(" Employee number First Name Surname\n\n");
for(i=top;i<=front;i++)
break;
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
}
}
I for the life of me cannot figure out how to sort the stack. I have tried other pieces of code and many different things, but none of them have came close to finding it
But I am wanting to sort it by alphabetical order. So not by entry time or Employee number, but by the First initial of the Surname
A search function is also required for this, and to be done by Employee number.
I have looked online, and the use of sorting and searching in a stack isn't a common thing, but I required to have it.
I am not good at C and I am fairly new to it. Any tips or things that may help me greatly would be appreciated. Also I apologies for any formatting errors, I'm fairly new to programming altogether and using software.

Your data structure doesn't directly record an employee number. You have the array stack which records the employee number, and the array employee which records names. You need to preserve the relationship stack[i] contains the employee number for employee[i] which means any sorting of the existing data structure has to sort two arrays in parallel. While it can be done, it is not the best way to fix the problems (and it is harder than it need be, and will require a custom sort function).
You should upgrade the data structure to include the employee number:
struct employee
{
int number;
char first_name[15];
char surname[15];
} employee[20];
Note that I've retagged the structure as struct employee (instead of struct system) since it seems more relevant to the content of the structure.
You can then use the qsort() function from the standard C library (declared in <stdlib.h>) and the techniques documented in the proposed duplicate (How to sort an array of structs in C?) to sort the data straight-forwardly. It is also easier to write your searching code.
You can also clean up the display code; you can have a single function that is passed an employee structure (or pointer to one). It will contain a single printf() statement that formats the data correctly. This saves you writing the same elaborate printf() code 3 times, making it easier to fix the formatting if (when) you need to do so. You can also avoid using tabs in the output (generally a good idea), leading to:
void print_employee(const struct employee *emp)
{
printf("%8d %-15s %-15s\n", emp->number, emp->first_name, emp->surname);
}
This will produce well aligned output unless your employee number grows to more than 8 digits (in which case, change the 8 to 10 or whatever). You can also generalize one step further if you wish, passing a FILE *fp argument to the function, and using fprintf(fp, "…", …) instead of printf().
You call the function:
print_employee(&employee[i]);
You might also consider a function to print the headings since you have that function call 3 times. Alternatively, you might just have a constant string at file scope that contains the correct headings which you use in 3 places. You could do that with the print_employee() function too; have a constant string at file scope that is the format you use.
Also, in your display_first() and display_last() functions, the loops are curious. You've written:
for(i=front;i<=top;i++)
break;
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
You should realize (on review) that this is equivalent to:
i = front;
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
(If front is larger than top, then i = front is the only part of the loop executed; otherwise, the break is executed; either way, after the loop, i == front.)

Related

Code to get user inputs with strange errors and warnings (C4477, C4996, C4013, C4566, C6031, C6067)

This code grabs input from users, and first, to ensure they have entered the correct type of input, I let the function print out the menu on the screen and then scanf() the user input. It should be very straight forward code, but I keep getting errors and warnings which I don't understand, can someone plesae help me with this?
(I am still in the process of getting used to code in C.)
//include library
#include<stdio.h>
#include<string.h>
//variable declaration
int age,userInputOption,ptr_InputCk;
char name[20];
float point;
//Fuction prototype
void displayMenu();
void wrongInput();
char getTheName(char name[20]);
void optionSwitch();
int getTheAge(int age);
float getThePoint(float point);
//void clearData(char name, int age, float point);
int quitTheProgram();
void displayKnownData();
//main function
int main() {
displayMenu();
ptr_InputCk = scanf("%d", &userInputOption);
if (ptr_InputCk != 1) {
wrongInput();
displayMenu();
}
else if (userInputOption >=1 || userInputOption <=5) {
optionSwitch();
}
else if(userInputOption == 6) {
quitTheProgram();
}
return (0);
}
//Define Functions
void displayMenu() {
printf("1. enter a name: \n\n");
printf("2. enter an age: \n\n");
printf("3. enter the person’s points per game: \n\n");
printf("4. display the known data: \n\n");
printf("5. clear all data: \n\n");
printf("6. quit: \n\n");
printf("Please enter a number between 1 ~ 6:\n\n");
}
void wrongInput() {
printf("Wrong input, please re-enter");
}
void optionSwitch() {
switch (userInputOption) {
case 1:
getTheName(name);
break;
case 2:
getTheAge(age);
break;
case 3:
getThePoint(point);
break;
case 4:
displayKnownData();
break;
//case 5:
//clearData(name,age,point);
//break;
case 6:
quitTheProgram();
break;
}
}
char getTheName(char name[20]) {
printf("Please enter your name: \n");
scanf("%s", &name);
printf("You name: %s\n", name);
return (name[20]);
}
int getTheAge(int age) {
printf("Please enter your age: \n");
scanf("%d", &age);
printf("Your age: %d\n", age);
return (age);
}
float getThePoint(float point) {
printf("Please enter points: \n");
scanf("%f", &point);
printf("Your age: %f\n", point);
return (point);
}
/*/
void clearData() {
char* name = NULL;
int* age = NULL;
float* point = NULL;
return(name, age, point);
}*/
int quitTheProgram() {
_exit(0);
}
void displayKnownData() {
printf("name: %s\nage: %d\npoint: %f\n", name, age, point);
}
I would like to add that using scanf the way you did to fill a string isn't secure because you can easily overflow your buffer (char name[20]) if the user enters more than 19 characters.
Other solutions:
#include <stdio.h>
#define MAX_LIMIT 20
int main()
{
char str[MAX_LIMIT];
fgets(str, MAX_LIMIT, stdin);
printf("%s", str);
return 0;
}
Or
(...)
puts ("Please enter a string of 20 characters or fewer.");
scanf ("%20s", string1);
C4013 - _exit(0) does not exist in the declared libraries, if you were working on linux you'd find it in unistd.h.
Since you're working with msvc, apparenty you have such function declared on process.h (don´t quote me on that), I would, however, prefer to use the more appropriate exit(0) (or alternatively _Exit(0)), you should find these in stdlib.h, you need to include it in your file's headers.
C4477/C6067 - name is already a pointer, you need not to use the & operator:
scanf("%19s", name); // Be sure to include a width specifier to avoid buffer oferflow
C4996 - msvc does not like scanf at all, you can either:
1 - Use scanf_s as it tells you to (there are also some corrections I would make to the function itself as commented bellow):
void getTheName(char* name, size_t size) { // void return type
//buffer size for scanf_s
printf("Please enter your name: \n");
scanf_s("%s", name, size); //<---
printf("Your name: %s\n", name);
//no return needed, the input gets stored on the memory pointed by name
}
(Since name is global you could use sizeof(name) for buffer size, but I would advise you to make it local to its necessary scope, globals can get out of hand fast. The advice extends to all of your global variables, none of them seems to need to be global in your code.)
2 - Alternatively you could suppress that specific error, you can see how to do it here:
Why does Visual Studio 2013 error on C4996?
The safest bet, however, would be to use a better compiler if possible, for example gcc or clang, both can be used with Visual Studio.
C6031 - It complains about the lack of verification of scanf return value, and that's good advice, the function returns the number of read elements, in this case it shoud return 1, so you could use, for example:
if(scanf("%19s", name) != 1){
//handle error
}
//otherwise continue normal execution
This would make sure it works as expected.
The error C4566 is about character encoding, I suspect it may be a false positive or related to your encoding settings, anyway, fix the other problems and see if it still happens. You can then post a more specific question, if it remains.
Final notes - By clicking on the errors you'll navigate to the Microsoft docs of the respective error, that may help you understand the issue. Granted it's not always ver helpful. I would also advise, in the future, to post the errors as text, it's easier for users who want to help to find a possible solution by making research easier.

fscanf() cannot read without using '&' to the int data type [duplicate]

This question already has answers here:
When should I use ampersand with scanf()
(3 answers)
Closed 2 years ago.
I am having problem with a specific part of the code which I cant find any answer to yet. Here the fscanf() was not able to read the value of file until I added an '&' sign before add.age variable in this section. I got the problem solved but still cant figure out how it works. I mean why do I need to provide address of an integer data type and not of any string. Can any one explain please?
while(fscanf(fp, "%s %d %s", add.name, &add.age, add.dept)!=EOF)
{
printf("%s\t\t %d\t\t %s\n", add.name, add.age, add.dept);
}
This is the full code that I wrote for reference if you want
#include<stdio.h>
#include<stdlib.h>
void add_user(void);
void see(void);
void see_all(void);
struct student
{
char name[50];
char dept[50];
int age;
}add, check;
int main()
{
int choice;
printf("1. Add \n2. See \n3. See All \nEnter choice:");
scanf("%d", &choice);
switch(choice)
{
case 1:add_user();
break;
case 2:see();
break;
case 3:see_all();
break;
default:printf("Wrong Input");
}
}
void add_user()
{
FILE *fp;
printf("Enter name : ");
fflush(stdin);
gets(add.name);
printf("Enter age : ");
scanf("%d", &add.age);
printf("Enter department : ");
fflush(stdin);
gets(add.dept);
fp=fopen("Creating a file with multiple records and reading it.txt", "a+");
if(fp==NULL)
{
printf("file pointer is null");
exit(0);
}
fprintf(fp, "%s %d %s\n", add.name, add.age, add.dept);
fclose(fp);
main();
}
void see()
{
}
void see_all()
{
FILE *fp;
fp=fopen("Creating a file with multiple records and reading it.txt", "r");
if(fp==NULL)
{
printf("file pointer is null");
exit(0);
}
printf("Name\t\t Age\t\t Department\n");
while(fscanf(fp, "%s %d %s", add.name, &add.age, add.dept)!=EOF)
{
printf("%s\t\t %d\t\t %s\n", add.name, add.age, add.dept);
}
fclose(fp);
}
A "string" in C (in your case a character array) already decays to a pointer indicating the address in memory of the first character. There's no such mechanism for a single int, and as a result you need to explicitly pass an address that holds an int to scanf, which is done by prefixing a variable or lvalue expression with &. scanf needs pointers so that it can write the data it scanned into memory you control and can use.
fscanf (and other scanf variants) take pointers so they can assign the read values to them. In the case of strings, you already have a char * (read: char pointer), so you don't need and additional &).

How to search specific data in structure arrys using file in c

fp= fopen("Quiz.txt", "r");
fflush(stdin);
printf("Enter Name To Search:");
gets(srch);
if(srch==std[i].name)
{
printf("\n Student Name: %s", std[i].name);
printf("\n Roll Number :%d", std[i]. roll);
printf("\n First Quiz Marks :%d", std[i]. quiz1);
printf("\n Second Quiz Marks :%d", std[i]. quiz2);
printf("\n Third Quiz Marks :%d", std[i]. quiz3);
printf("\n Fourth Quiz Marks :%d", std[i]. quiz4);
printf("\n Fifth Quiz Marks :%d", std[i]. quiz5);
}
else{
printf("No Data Of %s", srch);
}
getchar();
fclose(fp);
I am not getting data related to search that user search suppose if user search their name if the name is available in a file then it returns with users name roll number and 5 quiz marks if not then return no data available
for string comparison, you have the possibility to use the function int strcmp(const char *s1, const char *s2);. The strcmp function returns 0 if and only if the two strings are identical. The returned value is negative if the first string is greater than the second and positive if it is not.
(don't forget to include the header #include <string.h>)

If(int IDnumvariable == structname[counter].IDnumber) Not working [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Im stuck on a situation with my book borrow function, The problem is when i have to compare user entered teacher id with an existing id in the teacherfile.
my id data types for both are integer so i used:
void tborrow() //2.1
{
int bksb=0;
int tbid2 =0;
struct books book[50];
struct teachers teach[50];
int x=0;
int c=0;
int i=0;
int tid=0;
int tid2=0;
int tbid=0;
FILE *teacherp;
FILE *bkbp;
teacherp= fopen("TeacherFile.txt", "r+");
if(teacherp!=NULL) //Checks if Teacher File was created successfully
{
printf("Teacher File Successfully Opened\n\n\n");
printf("Enter Teacher's ID# :");
scanf("%d",&tid);
while(1) // Loop till end of file
{
fflush(stdin);////flushes buffer
fscanf(teacherp,"%s %d %s %s %d ",teach[i].Teachname,&teach[i].IDnum,teach[i].contactnum,teach[i].Faculty,&teach[i].bksborrowed);
tid2= tid2 + teach[i].IDnum;
if (tid == tid2)
{
system("cls");
printf("Teacher ID Confirmed\n\n");
printf("\n\n----Teacher Information-----"); //check if correctly entered
printf("\nName: %s ", teach[i].Teachname);
printf("\nID #: %d " ,teach[i].IDnum);
printf("\nContact #: %s ", teach[i].contactnum);
printf("\nFaculty: %s " ,teach[i].Faculty);
printf("\nBooks Borrowed: %d " ,teach[i].bksborrowed);
printf("\n-----------------------------\n");
printf("\nIs your account? 1-Yes 0=No : ");
scanf("%d",&c);
fflush(stdin);//flushes buffer after scanf
if (c==1)//if yes find and borrow book
{
bksb = bksb+teach[i].bksborrowed;
if (bksb < 2)// if teacher has less than 2 books borrowed
{
printf("\nThis account currently has %d books borrowed",teach[i].bksborrowed);
bkbp = fopen("BookFile.txt","r+");
if(bkbp!=NULL) //Checks if Book File was created successfully if yes search for book and borrow
{
printf("Enter Book ISBN # :");
scanf("%d",&tbid);
while(1)
{
fscanf(bkbp,"%s %s %d %d %s %d %d-%d-%d %d-%d-%d ",book[x].Title, book[x].Author, &book[x].Accessionnum, &book[x].ISBN, book[x].Available, &book[x].bid, &book[x].bdate->m, &book[x].bdate->d, &book[x].bdate->y, &book[x].rdate->m, &book[x].rdate->d, &book[x].rdate->y);
tbid2 = tbid2 + book[x].ISBN;
if (tbid == tbid2)
{
printf("\n\n-------Book Information-------"); //check if correct book found
printf("\nTitle: %s", book[x].Title);
printf("\nAuthor: %s" ,book[x].Author);
printf("\nAccession#: %d" ,book[x].Accessionnum);
printf("\nISBN#: %d", book[x].ISBN);
printf("\nAvailability(Y-N): %s" ,book[x].Available);
printf("\nBorrowers ID#: %d ",book[x].bid);
printf("\nBorrow Date: %d-%d-%d ",book[x].bdate->m,book[x].bdate->d,book[x].bdate->y);
printf("\nReturn Date: %d-%d-%d ",book[x].rdate->m,book[x].rdate->d,book[x].rdate->y); //Prints user entry to screen for confirmation
printf("\n------------------------------\n");
printf("\nIs this the book you are looking for? 1-Yes 0=No : ");
scanf("%d",&c);
fflush(stdin);//flushes buffer after scanf
if (c==1)//if yes print into file
{
book[x].bid=tid2;
bksb++;
teach[i].bksborrowed=bksb;
printf("\n Book %s has been borrowed by %s %d",book[x].Title,teach[i].Teachname,teach[i].IDnum);
fclose(bkbp);
printf("\n\nReturning to previous account");
_getch();
break;
TeacherAcc();
}
/*else
{
fclose(bkbp);
system("cls");
printf("\nStarting over book borrowing!");
break;
tborrow();
}*/
}
else
//if we encountered the end of the file on the last attempt
//to read data then break out of the read loop
if( feof(bkbp) ) //If end of file is reached break out of loop
{
break;
}
++x;
}
}else // if book file failed to open
{
printf("Error!, Restarting Teacher Book Borrowing System. Press Enter to continue");
getchar();
tborrow();
}
}else if (teacher[i].bksborrowed == 2) // if teacher has already borrowed 2 books
{
printf("\nThis account already has %d books borrowed",teach[i].bksborrowed);
printf("\nGoing back to previous menu");
_getch();
system("cls");
TeacherAcc();
}
}
else if (c==0) //runs the Teacher borrow function if wrong account
{
system("cls");
printf("\nRe-Enter Teacher ID!");
tborrow();
}
}else // else if teacher id not found
{
printf("\nID %d not found, Please re-enter a valid ID \n Press enter to try again",tid);
_getch();
system("cls");
tborrow();
}
if( feof(teacherp) ) //If end of file is reached break out of loop
{
break;
}else
i++;
}//end of continuous loop
fclose(teacherp); //close the file when done
} //if file created successfully
else //Teacher file failed to load, restarts function to correctly open Teacher
{
printf("Error!, Restarting Teacher System. Press Enter to continue");
getchar();
system("cls");
}
printf("\n\nReturning to previous menu, Press Enter to continue \n");
fflush(stdin);//flushes buffer so getchar works properly
getchar();
system("cls");
TeacherAcc();
}//borrow function end
but it is not correctly comparing or storing the id i read from the file, and the file exists and the has the stored id for tests
attached is the block of code from my teacher borrow function
any help would be appreciated
i was thinking of making the id datatypes char and use strcmp(userentered,struct[count].idnum)
(form the comments)
Remove tid2= tid2 + teach[i].IDnum;.
Yes, you can use if (tid == teach[i].IDnum)
However, look at what your while(1) loop in tborrow is doing:
while(1)
read a teacher from the file
is the teacher the right one?
yes - do something
no - print an error and recursively call tborrow again.
Think about how you would do this if you were looking for a teacher by hand in a list on paper - would you look at the first teacher in the list, then give up and start again if it wasn't the right one?

How to implement dynamic arrays in C?

I am writing this code using dynamic memory allocation, for student records as indicated, this code suppose to be simple , I am obviously allocating elements in their correct places the right way, but when it comes to printing them, it gives me a "core dumped" error ! what is wrong ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
char **firstname;
char **lastname;
float *score;
int number_of_records,i,j,ctr=1,row=15,col=20;
/*ctr is to keep track of the student's number (makes it easier to
the user), it starts with (1)*/
firstname=malloc(row*sizeof(char*));
for(i=0;i<row;i++)
{
firstname[i]=malloc((col+1)*sizeof(char));
}
lastname=malloc(row*sizeof(char*));
for(i=0;i<row;i++)
{
lastname[i]=malloc((col+1)*sizeof(char));
}
printf("\nPlease indicate number of records you want to enter (min 2, max 15): ");
scanf("%d",&number_of_records);
score=malloc(row*sizeof(float));
printf("\nPlease input records of students\n(enter a new line after"
"each record), with following format:\nfirst name last name score ");
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",firstname[i],lastname[i],score[i]);
ctr++; /*ctr is to keep track of student number
(makes it easy to the user) */
}
for (i=0;i<number_of_records;i++)
{
printf("%s %s %f\n",firstname[i],lastname[i],score[i]);
}
}
Please change this:
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",&firstname[i],&lastname[i],&score[i]);
ctr++; /*ctr is to keep track of student number (makes it easy to the user) */
}
to this
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",firstname[i],lastname[i],&score[i]);
ctr++; /*ctr is to keep track of student number (makes it easy to the user) */
}
And it will work. The reason is that firstname[i] and lastname[i] are already pointers; you do not need to use & operator for them.
P.S. Also, since you are using C, do no cast the returning values from malloc or realloc. It will be done automatically.

Resources