Make a 2D array in a struct, store strings inside array - arrays

I have to make a library system using structs and pointers, that registers a person with their name, ID, phone number, and the name of the books (maximum 3). I have created a struct for every borrower, and I am trying to store input taken by the user, specifically at the part of getting the book titles, to store into an array of other structs (for other borrowers). I have to be able to free the locations of the borrowers once they return all books, so I'd have to use dynamic memory for that.
This is the code I have so far, not sure how exactly I would go about storing every borrower using pointers.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_NAME_SZ 256
#define CLEAR() system("CLS")
struct borrower
{
char name[20];
char lastName[20];
char id[7];
char phoneNumber[10];
char titleOfBook[3][20];
};
int main(void)
{
struct borrower b;
char op;
do
{
puts("\n1) Register borrower");
puts("2) Find by ID");
puts("3) Show All");
puts("4) Erase by ID");
puts("0) Exit");
printf("Option:");
setbuf(stdin, 0);
opc=getchar();
switch(op)
{
case '1':
RegisterBorrower(&b);
break;
case '2':
//showID();
break;
case '3':
//showAll();
break;
case '4':
//erase();
break;
case '0':
break;
}
}while (op!=48);
return 0;
}
void RegisterBorrower(struct borrower *b)
{
CLEAR();
setbuf(stdin,0);
printf("ID: "); gets(p->id);
printf("Name: "); gets(p->name);
printf("Last Name: "); gets(p->lastName);
setbuf(stdin,0);
printf("Phone Number: "); gets(p->phoneNumber);
int numberOfBooks=0, cont=0, i;
char bookTitle[20];
printf("How many books do you want to take out?(max 3): ");
scanf("%d", &numberOfBooks);
setbuf(stdin,0);
if(numberOfBooks<=3 && numberOfBooks>0)
{
for(i=0; i<numberOfBooks; i++)
{
setbuf(stdin,0);
printf("Book Title: "); gets(bookTitle);
strcpy(p->titleOfBook[i][0], bookTitle);
}
}else
{
printf("You cannot take out this amount of books.");
}
}
Everything "works" (doesn't crash) up until the part I ask for the book titles, it only runs once. Any help would be greatly appreciated.
EDIT:
My problem was that I used
strcpy(p->titleOfBook[i][0], bookTitle);
which only copies to one character because of the [0]. I changed it to
strcpy(p->titleOfBook[i], bookTitle);
and it worked fine.

Related

Understanding references to members in a struct within a struct, as well as how to dynamically allocate memory for struct members

I've looked at a few different questions with regards to the problem I am facing and while I feel like I've gained some insight I definitely have questions that I could use help with, so I wanted to solve a problem and get some help with the issues I'm facing in solving it.
I have an employee registry, I want to create a structure "Employee" that contains the data fields that I need for each employee. Within those fields I want another structure for their "Date of Birth" which has 3 ints within the struct - referring to month/date/year of birth. (See below)
typedef struct DOB {
int month;
int day;
int year;
} Birthdate;
typedef struct EmployeeInfo {
int empID;
char *firstName;
char *lastName;
Birthdate date;
double salary;
} Employee;
Now I want my program to output a menu of choices and prompt the user for input that could lead to several options those being:
Insert a new employee
Update/change info about an employee
Search for a specific employee
Display all information about all employees
int main() {
//create the array of Items
Employee * employeeRecord = (Employee * ) malloc(N * sizeof(Employee));
Birthdate * birthRecord = (Birthdate * ) malloc(N * sizeof(Birthdate));
int empID;
double salary;
Employee Employee;
Birthdate Birthdate;
char opt;
while (1) {
dispayMenu();
printf("Enter your Choice: ");
scanf(" %c",&opt);
switch(opt) {
case 'i':
printf("\nEnter empID: ");
scanf("%d", & Employee.empID);
printf("Enter firstName: ");
scanf("%s", Employee.firstName);
printf("Enter lastName: ");
scanf("%s", & Employee.lastName);
printf("Enter Date of Birth (month/day/year format): ");
scanf("%d-%d-%d", &Employee.date.month,&Employee.date.day,&Employee.date.year);
printf("Enter Employee salary: ");
scanf("%lf", & Employee.salary);
insertItem(employeeRecord, Employee);
break;
case 'u':
printf("\nEnter empID to update: ");
scanf("%d", & empID);
updateItem(employeeRecord, empID);
break;
case 's':
printf("\nEnter empID to search: ");
scanf("%d", &empID);
searchItem(employeeRecord, empID);
break;
case 'd':
printData(employeeRecord);
break;
case 'q':
quit(employeeRecord);
break;
default:
printf("%c is not a valid choice", opt);
}
}
}
The first question I have is - how can I dynamically update the size of the array that contains all the employees? I get a segmentation fault currently; I don't want to globally create the size of the array; but I know I only need to update it when I have to add an Employee to the registry - so when I call the insert function - but I don't know how to keep a count for a variable in main that updates when insert is called.
The second question is in regards to changing the date of birth - I know I have to use -> operator somewhere so that I can access the fields within the second structure, but when I use it currently it tells me that the type is mismatched - its an int but expects type char*. So how do I access data within the structures to change from the update() function.
void updateItem(Employee * employeeRecord, int empID) {
int i;
char chng;
for (i = 0; i < current_size; i++)
{
if (employeeRecord[i].empID == empID)
{
printf("What data do you wish to update?: ");
scanf(" %c", &chng);
switch (chng)
{
case '1':
printf("\nEnter new First Name: ");
scanf("%s", &Employee.firstName);
break;
case '2':
printf("\nEnter new Last Name: ");
scanf("%s", &Employee.lastName);
break;
case '3':
printf("\nEnter new Date of Birth: ");
// scanf("%d", &empID);
// searchItem(employeeRecord, empID);
break;
case '4':
printf("\nEnter new salary: ") break;
case '5':
printf("\nReturning to main menu.");
break;
default:
printf("%c is not valid, try it again.", opt);
}
}
break;
}
else{
printf("Employee Not Found");
}
}
I've described it above, but essentially can't seem to reference the items within a struct correct and am having trouble correctly calling functions from main - says the implicit declaration doesn't match the type of the function, but that might have to do with errors within those functions themselves.
You store your Employees in a dynamically allocated array, then use realloc() to resize the array:
void insertItem(Enployee **employees, size_t *n, Employee e) {
Employee *tmp = realloc((n+1) * sizeof(Employee));
if (!tmp) {
// fail
}
*employees = tmp;
memcpy(*employees + *n, e, sizeof(Employee));
(*n)++;
}
int main(void) {
// ...
Employee *employees = NULL;
size_t n = 0;
// ...
case 'i': {
Employee *e = malloc(sizeof(Employee));
scanf("%d", e->empID);
// ...
insertItem(&employees, &n, e);
}
// ...
}
As employees and n belong together it would make sense to create a struct to hold them.
Within the Employee struct Birthdate date is also a struct. You use . to access members of a struct via a value, and -> if you have a pointer. In updateItem() you pass in an Employee *employeeRecord and use it as an array so you you either do:
employeeRecord[i].date.month = ...
// or
(employeeRecord + i)->date.month = ...
You can only reference functions already declared so you want main() last. The other good option is to add declarations for your functions at the top.

Passing and returning a struct from a function

I have a function with a book struct array, but when i try to return it to my main it does not return the values and store them in the array. If the addBook function has to be void how would i work around that so that i can access the array elements later.
void addBook(struct Book book[], int *size) {
if (*size == MAX_BOOKS) {
printf("The inventory is full\n");
}
else {
printf("ISBN:");
scanf("%d", &book[*size]._isbn);
printf("Title:");
scanf("%s", book[*size]._title);
getchar();
printf("Year:");
scanf("%d", &book[*size]._year);
printf("Price:");
scanf("%f", &book[*size]._price);
printf("Quantity:");
scanf("%d", &book[*size]._qty);
*size++;
printf("The book is successfully added to the inventory.\n");
}
return book;
}
int main(void) {
struct Book book[MAX_BOOKS];
int size = 0;
int i;
int option;
printf("Welcome to the Book Store\n");
printf("=========================\n");
do {
menu();
printf("Select: ");
scanf("%d", &option);
switch (option) {
case 0:
printf("Goodbye!\n");
break;
case 1:
displayInventory(book, size);
break;
case 2:
addBook(book, &size);
break;
case 3:
//checkPrice();
break;
default:
printf("Invalid input, try again:\n");
}
} while (option != 0);
}
Your return statement isn't going to do what you're intending as the addBook's function signature says it returns void. I'm surprised that the code as is actually compiled without an error about this.
Anyways, the book data can be returned from the same way it was passed in - as an input and output parameter.
Essentially your code could look like the following (which is only meant to be an example of code that compiles and works to save info entered in from standard input into the book):
#include <stdio.h>
struct Book {
int value;
};
#define MAX_BOOKS 2
void addBook(struct Book book[], int *size) {
if (*size == MAX_BOOKS) {
printf("The inventory is full\n");
}
else {
printf("Value:");
scanf("%d", &book[*size].value);
(*size)++;
printf("The book is successfully added to the inventory.\n");
}
}
int main(void) {
struct Book book[MAX_BOOKS];
int size = 0;
addBook(book, &size);
printf("Book 1: Value=%d\n", book[0].value);
}
And here's how this looks when run:
$ ./main
Value:9
The book is successfully added to the inventory.
Book 1: Value=9
Hope this answers your question.
I think your problem is in the line *size++;. You should use parenthesis, otherwise you are modifying the pointer to size, not the value. It should be (*size)++.
Also, the addBook function should not return anything, since it is void, and it is changing the content of the array book already.

So many errors and not sure how to fix it

I'm currently still practicing my c programming skills but there are so many errors here that I'm confuse on what is wrong and how to fix it. It's for a database program that I was practicing on.
It keeps showing:
new2.c:86: error: request for member ‘previousreading’ in something not a structure or union
and
new2.c:94: error: ‘Break’ undeclared (first use in this function)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int custid;
char custname;
float currentreading;
float previousreading;
double charge;
int choice;
unsigned cust;
int revenue, meterdifference, BILL;
printf("----------------------------------\n");
printf("Electricity Management System\n");
printf("----------------------------------\n");
printf("\n1. Record Usage");
printf("\n2. Add Customer");
printf("\n3. Edit Customer");
printf("\n4. Delete Customer");
printf("\n5. Show Customer");
printf("\n6. Show Total monthly income");
printf("\n7. Exit");
scanf("%d",&choice);
if(choice >=1 || choice <=7)
{
switch(choice)
{
case 1: //Record Usage
printf("Enter Customer ID\n");
FILE *cfPtr;
if ((cfPtr = fopen("customer.txt", "r"))== NULL)
puts("This file could not be opened");
else
{
puts("Enter the customer ID, name.");
scanf("%d%29s", &cust.custid, cust.custname);
puts("Enter the current reading in kWh");
scanf("%d", cust.currentreading);
if(cust.currentreading < cust.previousreading)
puts("Input invalid");
else
{
if (cust.currentreading>=200)
{
cust.charge = (cust.currentreading - cust.previousreading)*21.80;
printf("\nThe charge is RM%f\n", &cust.charge);
}
else
{
if (cust.currentreading>=300)
{
cust.charge= ((cust.currentreading - cust.previousreading)*33.40)+21.80;
printf("\nThe charge is RM%f", &cust.charge);
}
else
{
if (cust.currentreading>=600)
{
cust.charge= ((cust.currentreading - cust.previousreading)*51.60)+21.80;
printf("\nThe charge is RM%f", &cust.charge);
}
else
{
if (currentreading>=900)
{
cust.charge = ((cust.currentreading - cust.previousreading)*54.60)+21.80;
printf("\nThe charge is RM%f", &cust.charge);
}
else
{
cust.charge = ((cust.currentreading - cust.previousreading)*57.10)+21.80;
printf("\nThe charge is RM%f", &cust.charge);
}
}
}
}
}
}
Break;
case2: //Add Customer
puts("This option allows user to add new customer");
printf("Enter Customer ID and name.");
scanf("%d%c", &cust.custid, cust.custname);
puts("To return to menu");
Break;
case 3: //Edit Customer
puts( "This option allows user to edit customer info");
Break;
case 4: //delete customer
puts( "This option allows user to delete customer");
Break;
case 5: //Show Customer
printf("To show customer information\n");
FILE*tPtr;
char custid[100],custname[100];
int previousreading,currentreading;
double charge;
printf("\n Show Customer\n");
if((tPtr= fopen("customer.txt","r"))==NULL){
puts("File not found");
}
else{
printf("%-15s%-25s%-20s%-15s%-15s\n","ID","Name","Previous Reading","Current Reading","Charges");
while(!feof(tPtr)){
fscanf(tPtr,"%[^;];%[^;];%d;%d;%lf",cust.custid,cust.custname,&cust.previousreading,&cust.currentreading,&cust.charge);
printf("%s\t\t%-25s%-20d%-15d%-15.2lf",cust.custid,cust.custname,cust.previousreading,cust.currentreading,cust.charge);
}
fclose(tPtr);
}
printf("\n\n");
Break;
case 6: //Show total income(monthly)
puts("To show monthyly income");
printf("total usagekWh, meterdifference");
printf("%-15s%-35.2d\n", "Total UsagekWh","meterdifference");
scanf("%-16dtotal usage(kWh)%-24d: %.2f",&meterdifference);
printf("%-13dtotal revenue%-24d: %.2f",BILL);
revenue=BILL;
printf("revenue is %.2f", BILL);
Break;
case 7: //Exit
Break;
}
}
else
printf("\nError. Number not in choices.");
return 0;
}
typedef struct{
int custid[50];
char custname[100];
int previousreading;
int currentreading;
float charges;
}cust;
Put the typedef before main. typedefs must occure before you use them just as vaiables.
Replace unsigned cust; by cust cust;. unsigned cust; is the same as unsigned int cust; and declares an unsigned integer, you want to declare a cust.
Replace float charges; by float charge; in the typedef
Replace Break; by break;. Case matters in C. Break is not Break, just as Int is not int.
Then it compiles.
Now if it it runs correctly or not is another story.
There is not a single structure in your code, not in the form of a variable declaration nor as a type definition1, and you are treating cust which is simply an unsigned int as if it was a structure, perhaps you mean
struct {
float previousreading;
float currentreading;
/* And so on */
} cust;
Also, there is no Break keyword in c, it's break, all lower case.
But,
Don't do it, create a new struct so that you can use declare variables of type struct Costumer for example. Like at the end of your code, except that the compiler needs to know about it before using it, and the cust variable should have it's type.
A char is not a string type, if you want a string you need an array of char, so char custname; is not going to work for the name string.
Use meaningful names for your variables, and the members if your structure and the type name too. Like costumer instead of cust.
Additional NOTE
See Why while (!foef(file)) is always wrong. Your code will always attempt a read with fscanf() that will fail but it proceeds to print the data, it's very likely that your last row is printed twice once you make the code compile.
Instead, check the return value of fscanf(), if you don't know what it returns and don't fully understand it you can always read fscanf(3) documentation.
1At least not before you attempt to use it.

Why does this give junk value?

I am getting garbage / junk values as output when my program is run and the data displayed.
Why is it so?
Can someone help me to understand how to properly pass by pointers and not get junk values?
This program is about stack creation of struct books type variables.
By default shouldn't the variable bks pass by pointer and change when b is changed?
bks is still storing garbage value.
Here is my code:
#include<stdio.h>
#include<stdlib.h>
struct books
{
int yrpub;
char name[100],author[50];
};
int top=-1;
int push(struct books b[],int top,int n)
{
if(top==n-1)
return -1;
else
{
++(top);
printf("Enter books info: \n");
printf("Enter name: ");
gets(b[top].name);
printf("Enter author: ");
gets(b[top].author);
printf("Enter Year of publish: ");
scanf("%d",&b[top].yrpub);
return top;
}
}
void display(struct books b[],int top)
{
int i;
if(top==-1)
printf("No books in the stack...");
for(i=0;i<=top;i++)
{
printf("Details of book %d: \n",i+1);
printf("Name: %s\nAuthor: %s\nYear of publish: %d\n",b[i].name,b[i].author,b[i].yrpub);
}
system("pause");
}
int main()
{
struct books bks[10];
int ch;
system("cls");
printf("Select an option:\n");
printf("1. Push book\n2. Pop book\n3. Peep book\n4. Display all books info\n5. Exit\n");
printf("Enter a choice: ");
scanf("%d",&ch);
fflush(stdin);
switch(ch)
{
case 1:
system("cls");
top=push(bks,top,10);
break;
case 4:
system("cls");
display(bks,top);
break;
case 5: exit(0);
default: printf("\nWrong choice...Please retry.");
long i,j;
for(i=0;i<1000000;i++)
for(j=0;j<100;j++);
}
main();
}
Each time you recursively call main(), you create a new array bk.
The information you entered in the previous invocation of main() is hidden from the new one.
To iterate is human; to recurse, divine.
In this context, give up divinity for humanity. Use iteration — in this context it is better.
This is your primary problem; there may also be other off-by-one or other errors.
push:
if(top==n-1)
return -1;
main:
top=push(bks,top,10);
top is reset when the stack is full
Edit:
And the second problem is main being called again, struct books bks[10] is reset in the next main, it is a recursion. Declare bks as global or go with a while loop instead of recursion.
while (1) {
getChoices();
if (exit)
/* exit from here */
process();
}

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.

Resources