So this is a program that calculates the sum of all monthly subscriptions. But the problem is that the values of netflixBill, disneyBill etc. are 0 at the function call so the sum is only the struct elements. I have tried everything I know but I don't understand why it does not work.enter image description here
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct Subscription {
char name[100];
float price;
};
int check_login(char *, char *);
void askSubscriptionQuestions(bool *, bool *, bool *, bool *);
struct Subscription ask_subscription();
float total_price(struct Subscription subscriptions[], int num_subscriptions, float netflixBill, float disneyBill, float hboBill, float spotifyBill);
struct Subscription ask_subscription(void) {
struct Subscription subscription;
printf("What is the name of the subscription? ");
scanf("%s", subscription.name);
printf("How much do you pay every month for it? ");
scanf("%f", &subscription.price);
return subscription;
}
int main()
{
float netflixBill = 0.0f, disneyBill = 0.0f, hboBill = 0.0f, spotifyBill = 0.0f;
char id[20];
char password[20];
bool hasPassed;
bool hasNetflix;
bool hasDisneyPlus;
bool hasHBO;
bool hasSpotify;
char response;
struct Subscription subscriptions[100];
int num_subscriptions = 0;
while (1) {
printf("Enter your ID: ");
scanf("%s", id);
printf("Enter your password: ");
scanf("%s", password);
if (check_login(id, password)) {
printf("Access granted.\n");
hasPassed = true;
break;
} else {
hasPassed = false;
printf("Access denied.\n");
}
}
printf("Do you have any monthly subscriptions? (y/n) ");
char c;
while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
scanf("%s", &c);
if (c != 'y' && c != 'Y' && c != 'n' && c != 'N'){
printf("Invalid input. Please enter 'y' or 'n': ");
}
}
printf("%f %f %f %f", netflixBill, disneyBill, hboBill, spotifyBill);
if (c == 'y' || c == 'Y') {
askSubscriptionQuestions(&hasNetflix, &hasDisneyPlus, &hasHBO, &hasSpotify);
} else if (c == 'n' || c == 'N') {
printf("OK, thank you for your answer.\n");
}printf("%f %f %f %f", netflixBill, disneyBill, hboBill, spotifyBill);
printf("Do you have any other monthly subscriptions (Y/N)? ex: YT Premium, iCloud, etc.\n");
scanf("%s", &response);
while (response == 'Y' || response == 'y') {
subscriptions[num_subscriptions] = ask_subscription();
num_subscriptions ;
printf("Do you have any other monthly subscriptions (Y/N)? ");
scanf("%s", &response);
}
if (num_subscriptions > 0) {
printf("Your subscriptions are:\n");
for (int i = 0; i < num_subscriptions; i ) {
printf("- %s: $%.2f\n", subscriptions[i].name, subscriptions[i].price);
}
} else {
printf("You do not have any other monthly subscriptions.\n");
}
float total = total_price(subscriptions, num_subscriptions, netflixBill, disneyBill, hboBill, spotifyBill);
printf("The total cost of all your subscriptions is $%.2f\n", total);
return 0;
}
int check_login(char *id, char *password) {
if (strcmp(id, "admin") == 0 && strcmp(password, "pass123") == 0) {
return 1;
} else {
return 0;
}
}
void askSubscriptionQuestions(bool *hasNetflix, bool *hasDisneyPlus, bool *hasHBO, bool *hasSpotify) {
char c;
int netflixPlan, spotifyPlan;
float netflixBill = 0.0f, disneyBill = 0.0f, hboBill = 0.0f, spotifyBill = 0.0f;
printf("Do you have a subscription to Netflix? (y/n) ");
scanf("%s", &c);
if (c == 'y' || c == 'Y') {
*hasNetflix = true;
printf("Which monthly plan do you have? Here is a list: \n");
printf("\t 1 for Minimum = 7.99$/month\n");
printf("\t 2 for Standard = 9.99$/month\n");
printf("\t 3 for Premium = 11.99/month\n");
scanf("%d", &netflixPlan);
if(netflixPlan == 1){
netflixBill = 7.99;
}
else if(netflixPlan == 2){
netflixBill = 9.99;
}
else
netflixBill = 11.99;
} else {
*hasNetflix = false;
printf("You don't have a Netflix subscription. \n");
}
printf("Do you have a subscription to Disney ? (y/n)\n ");
scanf("%s", &c);
if (c == 'y' || c == 'Y') {
*hasDisneyPlus = true;
disneyBill = 5.99;
printf("The subscription for Disney is 5.99$/month.\n");
} else {
*hasDisneyPlus = false;
printf("You don't have a Disney subscription. \n");
}
printf("Do you have a subscription to HBO? (y/n)\n ");
scanf("%s", &c);
if (c == 'y' || c == 'Y') {
*hasHBO = true;
hboBill = 4.99;
printf("The subscription for HBO is 4.99$/month.\n");
} else {
*hasHBO = false;
*hasHBO = false;
printf("You don't have a HBO subscription. \n");
}
printf("Do you have a subscription to Spotify? (y/n) ");
scanf("%s", &c);
if (c == 'y' || c == 'Y') {
*hasSpotify = true;
printf("Which monthly plan do you have? Here is a list: \n");
printf("\t 1 for Premium = 4.99$/month\n");
printf("\t 2 for Premium for students = 2.49$/month\n");
scanf("%d", &spotifyPlan);
if(spotifyPlan == 1)
spotifyBill = 4.99;
else
spotifyBill = 2.49;
} else {
printf("You don't have a Spotify subscription. \n");
*hasSpotify = false;
}
}
float total_price(struct Subscription subscriptions[], int num_subscriptions, float netflixBill, float disneyBill, float hboBill, float spotifyBill) {
float total = netflixBill disneyBill hboBill spotifyBill;
for (int i = 0; i < num_subscriptions; i ) {
total = subscriptions[i].price;
}
return total;
}
i've tried using pointers(idk if i did it right). tried using chatgpt but it does not know what the problem is either.
CodePudding user response:
Uninitialised Variable:
char c;
while (c != 'y' && c != 'Y' && c != 'n' && c != 'N')
This loop invokes undefined behaviour as c
was never initialised.
Incorrect format specifier:
scanf("%s", &c);
The call to scanf
also invokes Undefined Behaviour, as c
has been declared as a char
, and the %s
format specifier is for strings.
I counted 7
other instances where you made the same mistake.
Once the abstract state machine reaches an undefined state, no further assumption about the continuation of the execution of the program can be made.
Variable scope:
The variables defined in main
are local to main
only. You declared another instance of spotifyBill ...
in askSubcriptionQuestions
, these variables are local to askSubcriptionQuestions
only. They're not visible in main
, and the variables declared in main
aren't visible in other functions.
Identifiers only have visibility inside their scope, starting at their declarations.
Objects have a lifetime outside of which they can't be accessed.
Referring to an object outside of its lifetime has Undefined Behaviour.
Unless they are
VLA
or temporary objects, automatic variables have a lifetime corresponding to the execution of their block of defination
If you want to work with the same variables declared in main, you'd have to pass them by reference
to other functions. That way, the changes made to those variables will be permanent.
CodePudding user response:
Your problem is related with the scope of the variables.
Essentially what is happening is that you are using local variables for assigning the values that you want inside the function askSubscriptionQuestions, but when you terminate this function, all the local variables are lost. Don't be confused because you named them the same way as the variables declared in the main. That doesn't matter. What matter is the scope of the variables.
Once you have declared your netflixBill variable in the main, you need to pass it by-reference, that means, passing the address of the variable instead of the value. You do this using "&". That way, if you properly modify value to which this address points to inside the function, when it finishes you won't loose the value of your variable.
You need to do several changes:
Re-write your function so the header includes these variables (to define the arguments as addresses):
void askSubscriptionQuestions(..., *netflixBill, *disneyBill, *hboBill, *spotifyBill)
Call your function as (to send the address instead of the value):
askSubscriptionQuestions(..., &netflixBill, &disneyBill, &hboBill, &spotifyBill)
Inside your function, every time you want to change the value of these variables, you need to call the "value" that the address is pointing to. So, the change would be to add always a "*" before each time you call these variables inside this function. For example:
*netflixBill = 7.99;
Remove the local declaration that you are doing of the netflixBill variable and similar inside your function.
I highly recommend you study and understand the concept of passing variables by-reference and by-value to the functions, it is essential coding in C.