I'm trying to write a program that reads a maximum of 8 bank account information and store them dynamically in a linked list. I wrote a function to calculate the average of all the entered bank accounts' balances but when I try to call that function no output is produced. can you please help me figure out where the problem is?
#include <stdio.h>
#include <stdlib.h>
//node structure
typedef struct node {
int no;
char name[20];
float total;
struct node * nextptr;
}
account;
//int for division of total to find the average
static int t;
//adding accounts function
account * addaccount(account * temp) {
fflush(stdin);
printf("Enter the account name: \n");
gets(temp -> name);
printf("Enter the account number: \n");
scanf("%d", & temp -> no);
printf("Enter the account balance: \n");
scanf("%f", & temp -> total);
t++; // used for finding the average
return temp;
}
// function for calculating the average
float sum(account * temp) {
float average = 1.0, sum = 0.0;
int i;
account * start;
temp = start;
for (i = 0; i < t; i++) {
sum += temp -> total;
temp = temp -> nextptr;
}
average = sum / t;
return average;
}
int main() {
int selection;
account * start = NULL;
account * save, * temp;
account * ptr;
ptr = (account * ) malloc(sizeof(account) * 8);
do {
//Menu
printf("\n1.Adding account\n");
printf("2.Find the average of the added accounts' balances\n");
printf("3.Exit\n");
scanf("%d", & selection);
switch (selection) {
case 1: {
if (ptr == NULL)
ptr = (account * ) realloc(ptr, sizeof(account));
save = addaccount(ptr);
if (start == NULL) {
start = save;
start -> nextptr = NULL;
} else {
temp = start;
while (temp -> nextptr != NULL)
temp = temp -> nextptr;
temp -> nextptr = save;
save -> nextptr = NULL;
}
break;
}
case 2: {
float avg;
avg = sum(temp);
printf("%f", avg);
break;
}
case 3: {
temp = start;
while (temp != NULL) {
free(temp);
temp = temp -> nextptr;
}
break;
}
}
} while (selection != 4);
return 0;
}
Look here
// function for calculating the average
float sum(account* temp) {
float average = 1.0, sum = 0.0;
int i;
account* start; <<<==== a random value
temp = start; <<<=== over write the parameter of this function with a random value
for (i = 0; i < t; i++) {
sum += temp->total;
temp = temp->nextptr;
}
average = sum / t;
return average;
}
Not sure what you are trying to do here - but that is for sure wrong
There are quite a number of problems with your code:
you say you want a maximum of 8 accounts, but there is no such limit being imposed by the code.
in sum() (which is misnamed, BTW), you are not looping through the nodes correctly, because the temp = start; assignment is backwards. start is uninitialized, and then temp is used inside the loop, thus invoking undefined behavior. You don't actually need the start variable at all, since you can simply increment the account* temp parameter.
in main(), you are initially pointing ptr to an array of 8 accounts, but if the user enters 1 on your menu, and ptr is NULL (which it would not be unless that initial malloc() failed), then you are pointing ptr to a single account. If your goal is to allow the user to enter an arbitrary number of accounts, your list management is all wrong.
Worse, every time the user enters 1 on your menu, you are calling addaccount() on the 1st account in the array, and addaccount() simply populates the specified account with data. So, you are not actually creating a new account and adding it to the list, at all. You are just linking the 1st account back to itself, over and over.
if the user enters 2 on your menu, you are calling sum() on the last account created by 1. If no account has been created yet, your code will crash since temp is uninitialized at that point. You need to call the function on the first account instead, so it can iterate the whole list.
if the user enters 3 on your menu, the code tries to free() individual accounts, but you did not actually malloc() individual accounts to begin with. You are trying to store accounts in an array instead, so you would just need to free() the array instead.
Also, your loop is checking for selection != 4, but your menu doesn't have an option 4. You should be checking for selection != 3 instead.
With that said, try something more like this:
#include <stdio.h>
#include <stdlib.h>
//node structure
typedef struct node {
int no;
char name[20];
float total;
struct node * nextptr;
}
account;
//adding accounts function
account* addaccount() {
account *temp = malloc(sizeof(account));
if (temp == NULL) {
printf("Unable to create new account\n");
return NULL;
}
fflush(stdin);
printf("Enter the account name: \n");
gets(temp->name);
printf("Enter the account number: \n");
scanf("%d", &temp->no);
printf("Enter the account balance: \n");
scanf("%f", &temp->total);
temp->nextptr = NULL;
return temp;
}
// function for calculating the average
float average(account* start) {
if (start == NULL) return 0.0;
float sum = 0.0;
int t = 0;
do {
sum += start->total;
start = start->nextptr;
++t;
}
while (start != NULL);
return sum / t;
}
int main() {
int selection;
account *start = NULL, *last = NULL, *temp;
do {
//Menu
printf("1.Adding account\n");
printf("2.Find the average of the added accounts' balances\n");
printf("3.Exit\n");
scanf("%d", &selection);
switch (selection) {
case 1: {
if ((temp = addaccount()) == NULL) break;
if (start == NULL)
start = temp;
else
last->nextptr = temp;
last = temp;
break;
}
case 2: {
printf("%f\n", average(start));
break;
}
}
} while (selection != 3);
temp = start;
while (temp != NULL) {
free(temp);
temp = temp -> nextptr;
}
return 0;
}
Related
I'm incredibly new to this and have a school assignment I have to write a gradebook program that uses a custom struct to hold student IDs and grades. I have been trying unsuccessfully for days to figure out why it will not print properly, or when it does print (after a lot of shifting things around) it only prints the second set of input.
The gradebook.h section is the custom structure.
// gradebook.h
struct gradeID
{
int id;
char grades[25];
};
// Gradebook.h is a header file to define
// a global structure.
#include "gradebook.h"
#include <stdio.h>
#include <stdlib.h>
void sort(struct gradeID *, int);
int main(void)
{
// Variables and structure definitions
int ctr;
char contInput;
int i;
struct gradeID grade;
struct gradeID *identifier;
int *temps;
// Allocates 10 integers worth of memory for the program to use.
// If there is not enough memory, the program will print an error
// statement and terminate the program.
temps = (int *) malloc(10 * sizeof(int));
if (temps == 0)
{
printf("Not enough memory!\n");
exit(1);
}
// Prints basic instructions for the program
printf("\t\tGradebook Recorder\n");
printf("Input student IDs and grades.\n");
printf("These will be sorted by ID and printed.\n");
/* Creates a for loop that will continue until the program
hits the designated number of array elements. For the sake
of expediency, I have set this amount to 10, but it can be
changed as necessary.*/
for(i = 0; i < 10; i++)
{
printf("Input student ID:\n");
scanf(" %d", &grade.id);
printf("Input grade:\n");
scanf(" %s", grade.grades);
// This allows early exit of the program
printf("Do you have more grades to enter?\n");
printf("Y/N\n");
scanf(" %c", &contInput);
if(contInput == 'N' || contInput == 'n')
{
printf("Finalizing and printing input-\n\n");
break;
}
ctr++;
}
printf("Grades Sorted by Student ID:\n\n");
printf("\tStudent ID: Student Grade: \n");
for(i = 0; i < ctr; i++)
{
printf("\t%d", grade.id );
printf("\t%s", grade.grades);
}
identifier[i] = grade;
return(0);
free(temps);
}
void sort(struct gradeID identifier[], int counter)
{
int inner;
int outer;
struct gradeID temp;
// Loops for sorting
for(outer = 0; outer < counter - 1; ++outer)
{
for(inner = outer + 1; inner < counter; ++inner)
{
if(identifier[inner].id < identifier[outer].id)
{
temp = identifier[inner];
identifier[inner] = identifier[outer];
identifier[outer] = temp;
}
}
}
return;
}
The pointer identifier is uninitialized
struct gradeID *identifier;
So this statement
identifier[i] = grade;
independent on the value of i invokes undefined behavior.
In this for loop
for(i = 0; i < 10; i++)
{
printf("Input student ID:\n");
scanf(" %d", &grade.id);
printf("Input grade:\n");
scanf(" %s", grade.grades);
// This allows early exit of the program
printf("Do you have more grades to enter?\n");
printf("Y/N\n");
scanf(" %c", &contInput);
if(contInput == 'N' || contInput == 'n')
{
printf("Finalizing and printing input-\n\n");
break;
}
ctr++;
}
you are entering new data in the same object grade of the structure type. So the new data overrides the previous data stored in the object.
Moreover the variable ctr was not initialized
int ctr;
So this statement in the above for loop
ctr++;
also invokes undefined behavior.
The variable temps that points to a dynamically allocated array
temps = (int *) malloc(10 * sizeof(int));
is not used.
This statement
free(temps);
never gets the control because before it there is the return statement
return(0);
free(temps);
What you need is to define an array of the type struct gradeID as for example
struct gradeID grades[10];
and fill it with values.
I am trying to delete a "user" from the struct on my code.
For example, this is the struct I have:
struct clients {
char name[30];
int year;
float amount;
};
And this is the two outputs I have:
Name: Victor
Birth Year: 1998
Amount: 1000.00
Name: John
Birth Year: 1996
Amount: 1500.00
What I want to do is to delete John and all his information from my struct.
I am trying to learn dynamic memmory allocation, so I used this command:
clt = (struct clients*) malloc(n * sizeof(struct clients));
In my case I wish to write a command on case 3 that delete john from the struct, but I really can't figure out how to do that, I guess maybe using realloc? But I didn't even get close to write something it would work.
Here is my entire code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct clients {
char name[30];
int year;
float amount;
};
int main() {
struct clients *clt;
int option, n, d = 0;
char name[30];
printf("Welcome, Choose an option to begin:");
do {
printf("\n1 - Create a new list;\n");
printf("2 - Find a person in the list;\n");
printf("3 - Delete a person from the list.\n");
printf("4 - End the program.\n");
scanf("%d", &option);
switch (option) {
case 1:
printf("\nType how many clients you want to register:");
scanf("%d", &n);
// allocating memory for n numbers of struct person
clt = (struct clients*) malloc(n * sizeof(struct clients));
for (int i = 0; i < n; i++) {
printf("Type the name and the birth year:");
// To access members of 1st struct person,
scanf("%s %d", (clt + i)->name, &(clt + i)->year);
printf("\nType the amount:");
scanf("%f", &(clt + i)->amount);
}
break;
case 2:
printf("Type the name you want to find:");
scanf("%s", name);
for (int i = 0; i < n; i++) {
if (strcmp(&clt[i].name, name) == 0) {
printf("\nThats the name:");
printf("\nName: %s\n", (clt + i)->name);
printf("Birth Year: %d\n", (clt + i)->year);
printf("Amount: %.2f\n", (clt + i)->amount);
d++;
}
}
if (d == 0)
printf("This name doesn't exist\n");
break;
case 3:
break;
case 4:
break;
}
} while (option != 4);
return 0;
}
You need to discard the element from its location in the list by moving the contents in the remainder of the list up , and overwriting the target element.
for(int i = 0; i < n; i++) {
if (strcmp(&clt[i].name, name)==0)
{
printf("\nThats the name:");
printf("\nName: %s\n", (clt+i)->name);
printf("Birth Year: %d\n", (clt+i)->year);
printf("Amount: %.2f\n", (clt+i)->amount);
d++; // This seems to be your sentinel value?
}
if ( 1 == d && i+1 != n ) // if the sentinel is set, but we're not off the end of the list yet
{
memcpy(clt+i, clt+i+1, sizeof( struct clients ));
}
}
n--; // reduce the list length
You could do this in one memmove call if you prefer. As #Neil says in the comments, memmove is tolerant of overlapping source and destination.
if ( 1 == d && i != n-1 ) // if the sentinel is set, but we're not off the end of the list yet
{
memmove(clt+i, clt+i+1, (n-i-1) * sizeof( struct clients ));
break; // break for i
}
You are describing almost a dynamic array such as C++'s std::vector. It is static, but it could be a dynamic array without that much extra work. You could create a container, and split n into the container's capacity and size.
struct clients_array {
size_t size, capacity;
struct clients *data;
};
Instead of having multiple pointers, one could create a struct clients_array for each list. Sample code to deal with the struct clients_array.
#include <inttypes.h>
#include <assert.h>
#include <errno.h>
/** `a` constructor with `n` spots. Returns true or false depending on whether
it could be constructed. */
static int clients_array_reserve(struct clients_array *const a,
const size_t n) {
assert(a && n);
if(n > SIZE_MAX / sizeof *a->data) return errno = ERANGE, 0;
if(!(a->data = malloc(sizeof *a->data * n))) return 0;
a->capacity = n;
a->size = 0;
return 1;
}
/** `a` destructor; call this when `a` has been successfully constructed. */
static void clients_array_(struct clients_array *const a)
{ if(a) { free(a->data); a->data = 0; a->capacity = a->size = 0; } }
/** Extract a new uninitialized entry out of constructed `a`. Returns null if
there is no more space. */
static struct clients *clients_array_new(struct clients_array *const a) {
assert(a);
return a->capacity > a->size ? a->data + a->size++ : 0;
}
/** Remove index `rm` from `a`. */
static void clients_array_delete(struct clients_array *const a,
const size_t rm) {
assert(a && rm < a->size);
memmove(a->data + rm, a->data + rm + 1,
sizeof *a->data * (a->size - rm - 1));
a->size--;
}
Then one can have different, independent arrays at once. If you want to update the code, say to allow realloc to increase the size of the object, you only need to modify the container.
I'm making a program where I'm entering an activity hours for dogs and then sums the hour for each activity and after that the program print each dog one after another from the dog with higher sum of hours of activites to the lowest
now I did sort the list and made a print function , but still doesn't work , it prints either 2 of them if the first dog I entered has the highest sum of hours and the seconde is the lowers in the right order, but if there first dog was the one with the lowest and the seconde one was the one with the highest it just prints the first dog ( the loswet one) and doesn't even print the seconde dog.
input:
2
any1
6
6
6
any2
3
3
3
Actual output:
any1 6 6 6
Expected output:
any2 3 3 3
any1 6 6 6
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_LENGTH 30
#define GRADE 100.0
#define AVG_SLEEP 12
#define AVG_WALK 1.25
#define AVG_PLAY 2
#define TEN 10.0
#define EIGHT 8.0
typedef struct dog* dogPtr;
typedef struct dog
{
char name[MAX_NAME_LENGTH]; /*30*/
double sleep;
double walk;
double playtime;
dogPtr next;
} Dog;
double calculateGrade (dogPtr dog);
void addDog(dogPtr* fitBarkList);
void printDogList(dogPtr fitBarkList);
void freeList (dogPtr list);
int main()
{
int amount_of_dogs;
int i;
dogPtr list = NULL;
printf("Welcome to FitBarkList\n");
printf("Enter the amount of dogs: \n");
if(!scanf("%d", &amount_of_dogs))
{
printf("Input Error\n");
return 0;
}
while (amount_of_dogs <1)
{
printf("Enter the amount of dogs: \n");
if(!scanf("%d",&amount_of_dogs))
{
printf("Input Error\n");
return 0;
}
}
for(i = 0; i < amount_of_dogs; i++)
{
printf("Enter dog number %d\n", i+1 );
addDog(&list);
}
printDogList(list);
freeList(list);
return 0;
}
/**this function frees the allocated memory*/
void freeList (dogPtr list)
{
if(list != NULL)
{
freeList(list->next);
free(list);
}
}
void addDog(dogPtr* fitBarkList)
{
dogPtr tmp=*fitBarkList,tmp2=NULL,curr;
dogPtr p = (dogPtr)malloc(sizeof(Dog));
if(p == NULL )
{
printf("allocation failed\n");
exit(1);
}
printf("Enter the dog's name: \n");
scanf("%s", p->name);
printf("Enter the dog's average sleeping time: \n");
scanf("%lf", &p->sleep);
printf("Enter the dog's average walking time: \n");
scanf("%lf", &p->walk);
printf("Enter the dog's average play time: \n");
scanf("%lf", &p->playtime);
p->next=NULL;
if (*fitBarkList == NULL)
{
*fitBarkList=p;
return ;
}
curr=p;
while (tmp!=NULL)
{
if (calculateGrade(curr) < calculateGrade (tmp))
{
tmp2=tmp;
tmp=tmp->next;
}
else
{
return ;
}
}
if (tmp != NULL)
{
curr=tmp2->next;
tmp->next=curr;
}
if (tmp == NULL)
{
tmp2->next=curr;
curr->next=NULL;
}
}
/**this function prints the grade of the dog then shows the total grade*/
void printDogList(dogPtr fitBarkList)
{
dogPtr curr=fitBarkList;
if(curr == NULL)
{
return ;
}
while(curr!=NULL)
{
printf("%s \n", curr->name);
printf("Sleeping grade %.2f \n", curr->sleep);
printf("Play time grade: %.2f \n", curr->playtime);
printf("Walking grade: %.2f \n", curr->walk);
printf("Total grade: %.2f \n", calculateGrade(curr));
curr=curr->next;
}
}
/**this function to calculate the grades for each activity*/
double calculateGrade(dogPtr dog)
{
double sleep = dog->sleep,
walk = dog->walk,
playtime = dog->playtime;
if (sleep == 12.0)
sleep = GRADE;
else if (sleep < AVG_SLEEP)
sleep = GRADE - ((12.0 - sleep) * TEN);
else if (sleep > AVG_SLEEP)
sleep = GRADE - ((sleep - AVG_SLEEP) * TEN);
if (walk == AVG_WALK&& walk>=0.25)
walk = GRADE;
else if (walk > AVG_WALK )
walk = GRADE - ((walk - AVG_WALK) * EIGHT);
else if (sleep <= 0.25)
walk = GRADE - GRADE;
else if (walk < AVG_WALK && walk > 0.25)
walk = GRADE - ((AVG_WALK - walk) * GRADE);
if (playtime == AVG_PLAY)
playtime = GRADE;
else if (playtime > AVG_PLAY)
playtime = GRADE - ((playtime - AVG_PLAY) * EIGHT);
else if (playtime < AVG_PLAY)
playtime = GRADE - 60.0;
else if (AVG_PLAY>playtime && playtime>1.0)
playtime=GRADE-(GRADE*(AVG_PLAY-playtime));
return sleep + walk + playtime;
}
When you find the new place where to insert the new dog, you walk the list if there is a next dog and if the new dog's grade is below the current dog's grade. (I've renamed the two iterators curr and prev for clarity.)
When you insert the new dog, p, the next dog is the current dog, p->next = curr. If the current dog's grade is the smallest of if the list was empty, curr is NULL, which is fine. You don't need to treat an empty list as special case.
Now, if prev == NULL, your new dog ist the current best. There is no previous node, so update the head pointer via *fitBarkList. Otherwise, update the next field of the previous node:
dogPtr p = create_node(...); // alloc and read stuff
dogPtr curr = *fitBarkList; // p goes before this ...
dogPtr prev = NULL; // ... and after this
while (curr && calculateGrade(p) < calculateGrade (curr)) {
prev = curr;
curr = curr->next;
}
p->next = curr;
if (prev == NULL) { // first node
*fitBarkList = p;
} else { // subsequent nodes
prev->next = p;
}
i have a problem with my realloc in the func add order its crash every time
someone can help me here
typedef struct
{
char carname[30]; //car names
int price; //the price of the car
}Vehicle;
typedef struct {
int number; // מספר הזמנה
char *name; // שם המזמין
char ID[10]; // מספר זהות שלו
int number_vehicles; // מספר הרכבים בהזמנה
Vehicle * list;
int sum_order;
}Order;
Order * add_orders(Order * firma, int * ordersize)// adding one more order
{
int i, j;
char temp[80];
int newstart; // because we need to add one more order we need new start and it will be the old size of the number of orders
newstart = *ordersize; //we just did it
(*ordersize)++; // now we have new size +1 for the one more order
for (i = newstart; i < *ordersize; i++) //same as the input function but this one start and finish from the new start and finish
{
printf("enter the ID of order number: %d\n", i + 1);
scanf("%d", &firma[i].number);
while (getchar() != '\n');
printf("enter the name of the client:\n");
gets(temp);
firma[i].name = (char*)malloc(strlen(temp) + 1 * sizeof(char));
if (!firma[i].name)
{
printf("error\n");
return 0;
}
strcpy(firma[i].name, temp);
printf("enter the ID of client (length can only be 10):\n");
gets(firma[i].ID);
printf("enter how many vehicles you want in this order\n");
scanf("%d", &firma[i].number_vehicles);
firma[i].list = (Vehicle*)malloc(firma[i].number_vehicles * sizeof(Vehicle));
if (!firma[i].list)
{
printf("error\n");
return 0;
}
for (j = 0; j < firma[i].number_vehicles; j++)
{
while (getchar() != '\n');
printf("enter the name of the vehicle number %d (only 30 chars):\n", j + 1);
gets(firma[i].list[j].carname);
printf("enter the price of the vehicle\n");
scanf("%d", &firma[i].list[j].price);
}
}
firma = (Order*)realloc(firma, (*ordersize * sizeof(Order))); //after we added the new order we do realloce for the new size for the struct
if (!firma)//if failed
{
printf("error\n");
return 0;
}
}
int main()
{
int i, j;
char temp[80];
char *str = NULL;
int num, x, y;
int number;
int ordersize;
int exit1 = 0;
int exit2 = 0;
int exit3 = 0;
int flag = 0;
int choose;
Order *data = NULL; //pointer to the struct Order
printf("\nenter how many orders you want\n");
scanf("%d", &ordersize); //enter size of orders
data = (Order*)malloc(ordersize * sizeof(Order));//we allocte memory for the struct Order with pointer data
add_orders(data, &ordersize); //send it
return 0;
}
i have a problem with my realloc in the func add order its crash every time
someone can help me here
i have a problem with my realloc in the func add order its crash every time
someone can help me here
i have a problem with my realloc in the func add order its crash every time
someone can help me here
You access out of bound for firma.
data = (Order*)malloc(ordersize * sizeof(Order));//we allocte memory for the struct Order with pointer data
add_orders(data, &ordersize); //send it
As you allocated memory of size orderSize and you access firma[newstart].
newstart = *ordersize; //we just did it
(*ordersize)++; // now we have new size +1 for the one more order
for (i = newstart; i < *ordersize; i++) //same as the input function but this one start and finish from the new start and finish
{
printf("enter the ID of order number: %d\n", i + 1);
scanf("%d", &firma[i].number);
while (getchar() != '\n');
.....
}
Thus first allocate more memory and access.
newstart = *ordersize; //we just did it
(*ordersize)++; // now we have new size +1 for the one more order
firma = (Order*)realloc(firma, (*ordersize * sizeof(Order))); //after we added the new order we do realloce for the new size for the struct
if (!firma)//if failed
{
printf("error\n");
return 0;
}
for (i = newstart; i < *ordersize; i++) //same as the input function but this one start and finish from the new start and finish
{
printf("enter the ID of order number: %d\n", i + 1);
scanf("%d", &firma[i].number);
while (getchar() != '\n');
.....
}
Note:: firma is local variable and allocating memory using realloc
in addOrder function has no effect on data variable in main
function. You may need to pass data using reference or return
updated value from function and assign it to data.
I have created a function that is supposed to take the numbers in my linked list and determine which one is the smallest number and which one is the largest number. I created a while loop that is supposed to take each number and compare it to the next. 'newNumber' is the current number and 'next' should be the number next in the list. I am having trouble understanding how to call the current and next number. My while loop is also infinite is it because, I am referring to the numbers again in determine?
double NumberSize(NewNumber *start){
NewNumber *determine = start;
double SecondNumber =0;
double FirstNumber = 0;
while(determine != NULL){
FirstNumber = determine->newNum;
SecondNumber = determine->next;
if(FirstNumber < SecondNumber){
printf("The biggest number is:\n", SecondNumber);
}else{
printf("The smallest number is:\n", FirstNumber);
}
}
You forgot to step through the list. Using on of the solutions for the average:
void NumberSize(NewNumber * start)
{
double num = 0.0;
double biggest;
double smallest;
int flag = 0;
NewNumber *temp = start;
// set start values
if(tmp != NULL){
biggest = temp->newNum;
smallest = temp->newNum;
tmp = tmp->next;
flag = 1;
}
// while temp is not NULL
while (temp) {
// get number from current node
num = temp->newNum;
// if that number is bigger than "biggest"
if (num > biggest) {
// exchange "biggest" with "num"
biggest = num;
}
// do it the same way for the smallest number
else if (num < smallest) {
smallest = num;
}
// here is the forgotten line:
// go to the next node
temp = temp->next;
}
if(flag){
// no returns, just printing
printf("The smallest number is: \n", smallest);
printf("The biggest number is: \n", biggest);
} else {
puts("list empty");
}
}