0

Having lots of issues with my code, and have had people try explaining it to me but I still can't understand what I'm doing wrong... it all seems right in my head. As far as I understand, my char is not scanning correctly. I also have issues with returning values, and my "int * differs in levels of indirection from int". How can I fix my code? I'm completely lost.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define PAUSE system("pause")
#define CLS system("cls")
#define FLUSH flush()

// PROTOTYPE FUNCTIONS
void displayMenu();
void flush();
char getUserChoice();
int newSale(int *price, char *firstTime, char *veteran, char *student, char *lastDay);
int outputPrice(int carSales[], int *carsSold, int *avgCarPrice, int *totalRevenue);

// MAIN
main() {
    int carSales[500] = { 0 };
    int price = 0,  avgCarPrice = 0, totalRevenue = 0, carsSold = 0;
    char firstTime = 'n', veteran = 'n', student = 'n', lastDay = 'n';


    char userSelection;
    do {
        userSelection = getUserChoice();
        switch (userSelection) {
        case  'A': // ENTER A NEW SALE
            newSale(&price, &firstTime, &veteran, &student, &lastDay); // call function to ask questions
            printf("\nPRICE OF CAR: %i\n", price);
            carsSold++; // will add to +1 to the amount of cars sold
            carSales[carsSold] = price; // add the car to carSales array
            PAUSE;
            break;
        case  'B': // OUTPUT STATS
            outputPrice(&carSales[500], &carsSold, &avgCarPrice, &totalRevenue);
            PAUSE;
            break;
        case  'Q': //  Quit Program
            printf("Thanks....\n");
            break;
        default: // Invalid Selection
            printf("Invalid selection...try again!\n");
            PAUSE;
            break;
        } // end switch
    } while (userSelection != 'Q');
    PAUSE;
} // end of main

  // DISPLAY THE MENU
void displayMenu() {
    CLS;
    printf("========== MAIN MENU ==========\n");
    printf("A. ENTER NEW CAR\n");
    printf("B. OUTPUT STATS\n");
    printf("Q. QUIT\n");
    printf("Enter your choice: ");
} // end displayMenu

  // FLUSH
void flush() {
    while (getchar() != '\n');
} // end flush

  // GET THE USER CHOICE
char getUserChoice() {
    char result;
    displayMenu();
    scanf("%c", &result); FLUSH;
    result = toupper(result);
    return result;
} // end getUserChoice

int newSale(int *price, char *firstTime, char *veteran, char *student, char *lastDay) {

    // ASK QUESTIONS

    printf("What is the sticker price of the car?\n"); 
    scanf("%i", &price);

    printf("Are you a first time buyer? (y/n)\n");
    scanf("%s", firstTime);

    printf("Are you a veteran? (y/n)\n");
    scanf("%s", veteran);

    printf("Are you a student (y/n)\n");
    scanf("%s", student);

    printf("Is it the last day of the month? (y/n)\n");
    scanf("%s", lastDay);

    // CALCULATE PRICES

    if (*lastDay == 'y') { // car is discounted by 3% if user said yes
        *price = *price - (((int)(*price) * 3) / 10); // (int) is added to keep the cocmpiler from complaining due to an implicit cast to floating point. 
    }

    if (*firstTime == 'y') {  // if it's the user's first time buying, $100 is given in credit
        *price = *price - 100;
    }

    if (*student == 'y' && firstTime == 'y') { // car is discounted by $200 if user is a student and first time buyer- they also recieve the other discounts
        *price = *price - ((int)(*price) - 200);
    }

    if (*veteran == 'y') { // veterans recieve 2% off the final price of the car
        *price = *price - (((int)(*price) * 2) / 10);
    }

    return price;
}

int outputPrice(int carSales[ ], int *carsSold, int *avgCarPrice, int *totalRevenue) {
    printf("The total cars sold is: %i", carsSold); // Display the amount of cars sold

    for (int i = 0; i < 500; ++i) { // add all the prices in carSales 
        *totalRevenue = *totalRevenue + carSales[i];
    }

    printf("The Average car sold price: %i", avgCarPrice); // Display the avg price of the cars
    printf("Total revenue: %i", totalRevenue); // Display total revenue
    return;
}
canineheart
  • 13
  • 1
  • 4
  • The `PAUSE`, `CLS`, and `FLUSH` macros seem a bit useless. – yano Jan 26 '18 at 04:31
  • 1
    `scanf("%i", &price);` this is too much indirection. `scanf` requires a pointer to scan in .. `price` already is a pointer, it's an `int*`. Writing `&price` is an `int**`, not what `scanf` wants. – yano Jan 26 '18 at 04:34
  • thank you that helps me better understand that part, I had fixed it a few minutes ago. – canineheart Jan 26 '18 at 04:36
  • 2
    `scanf("%s", firstTime);`.. `%s` is the wrong format specifier for inputting a `char`. `%s` is used for strings, `%c` is used for singular `char`s like you have. Btw, here you have the correct level of indirection since `firstTime` is a `char*`. I suggest reading the [`scanf`](https://linux.die.net/man/3/scanf) manpage. Also, be wary of your whitespace when using `scanf`: https://stackoverflow.com/questions/13542055/how-to-do-scanf-for-single-char-in-c – yano Jan 26 '18 at 04:37
  • you return `price` from your `newSale` function. First of all, that should be `return *price;` or you compiler will complain; you're returning an `int*` when the function signature calls for `int`. But you don't capture the return in `main` anyway.. you do pass the address of `price` into that function and manipulate it using the pointer.. might as well make it `void newSale(...)`. Compile with `-Wall -Wextra` to get a lot of warnings .. read and understand them! You should be able to google just about all of them. Ask here in another question if there's one you don't understand. – yano Jan 26 '18 at 04:43
  • oh nevermind about the compiler flags, looks like you're on Windows,, not sure how to crank up the warnings there, but you should be getting some. Does `outputPrice(&carSales[500], &carsSold, &avgCarPrice, &totalRevenue);` even compile? Change that to `outputPrice(carSales, &carsSold, &avgCarPrice, &totalRevenue);` – yano Jan 26 '18 at 04:50
  • it does compile, but it seems like nothing is scanning in or somethings not passing but I'm seeing if I can figure it out now – canineheart Jan 26 '18 at 04:52
  • I've honestly been working on this code for at least 6 hours and still haven't figured it out. I'm going to bed for now. – canineheart Jan 26 '18 at 04:58
  • probably the white space.. check the SO question I linked a few comments ago. More importantly... there are a lot of bugs in your code. Reduce and simplify. I'd comment a lot of this out until it was down to barebones minimal functionality. Get that working with _no warnings_, and then gradually add back. The only way to get better at coding (like everything else) is to suffer through it, which takes a lot of time. And learn how to use the debugger! It is very helpful for seeing where reality diverges. Take a look at this: https://ericlippert.com/2014/03/21/find-a-simpler-problem/ – yano Jan 26 '18 at 05:16
  • 1
    6hours! Don't I wish I could have worked on any code, in the real world, and be done in 6 hours. All to often, especially if I have 'inherited' the code, and the project has any real complexity then 6months would be more realistic, with some 100,000 lines of code to write, test, document. – user3629249 Jan 26 '18 at 05:21
  • since your on windows, (probably using visual studio) suggest reading: [options](https://msdn.microsoft.com/en-us/library/9s7c9wdw.aspx) for how to enable the warnings. – user3629249 Jan 26 '18 at 05:29
  • when writing the prototypes for functions that do not take any parameters, place `void` between the parens in the prototype – user3629249 Jan 26 '18 at 05:31
  • there are only a very few valid signatures for the `main()` function, (regardless of what visual studio allows) and the ALL have a return type of `int` – user3629249 Jan 26 '18 at 05:33
  • for ease of readability and understanding: 1) follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* 2) separate code blocks (`for` `if` `else` `while` `do...while` `switch` `case` default` ) via a single blank line. 3) separate functions by 2 or 3 blank lines (be consistent). – user3629249 Jan 26 '18 at 05:36
  • regarding this function: `void flush() { while (getchar() != '\n'); }` the input can also be EOF, so suggest: `void flush() { int ch; while ( (ch = getchar()) != '\n' && EOF != ch); } – user3629249 Jan 26 '18 at 05:38
  • regarding: `scanf("%c", &result); FLUSH;` 1) only one statement per line 2) when calling any of the `scanf()` family of functions, alway check the returned value (not the parameter values) to assure the operation was successful. – user3629249 Jan 26 '18 at 05:41
  • regarding: `result = toupper(result);` the `toupper()` returns an `int`, not a `char`. to avoid the implicit conversion and to avoid the resulting compiler warning, suggest: `result = (char)toupper(result);` – user3629249 Jan 26 '18 at 05:42
  • regarding: `scanf("%i", &price);` 1) always check the returned value. 2) the variable `price` is already a `pointer to int` so the statement should be: `scanf("%i", price);` so it is not trying to take the address of an address – user3629249 Jan 26 '18 at 05:45
  • regarding: `scanf("%s", firstTime); ... scanf("%s", veteran); ... scanf("%s", student);` These should be request a single character, so the input format specifier should be: `%c`, not `%s` Also, the original variables in `main()` are single characters, not arrays of characters, so using the `%s` will ALWAYS result in input buffer overflow (resulting in undefined behavior) because the `%s` input format specifier will always append a NUL byte to the input and not having a MAX CHARACTERS modifier means the user to enter a book at each of the prompts – user3629249 Jan 26 '18 at 05:49
  • the posted code contains several non-portable statements, like `CLS`. So the code will not compile nor run under OSs – user3629249 Jan 26 '18 at 05:56
  • the function: `printf()` is rather expensive in CPU cycles, Suggest condensing into a single call to `printf()` – user3629249 Jan 26 '18 at 05:58
  • regarding: `if (*student == 'y' && firstTime == 'y')` this is comparing the pointer value for `firstTime` to the char 'y'. That will not work. Suggest: `if (*student == 'y' && *firstTime == 'y')` as this will compare the contents of `firstTime` with the char `y` – user3629249 Jan 26 '18 at 06:02
  • regarding: `printf("The total cars sold is: %i", carsSold);` this is trying to print the address of the pointer for `carsSold`. But the format string is expecting an `int` Suggest: `printf("The total cars sold is: %i", *carsSold);` Similar considerations exist for: `printf("The Average car sold price: %i", avgCarPrice);` and `printf("Total revenue: %i", totalRevenue);` – user3629249 Jan 26 '18 at 06:03
  • regarding the function: `int outputPrice(...) { ... return; }` The signature says the returned value is an `int`, but the `return` statement is missing the needed `int` variable name. Actually, since the function that calls this one ignores any returned value, so the function signature (and prototype) should have a return type of `void`, not `int` – user3629249 Jan 26 '18 at 06:07
  • regarding this call: `outputPrice(&carSales[500], &carsSold, &avgCarPrice, &totalRevenue);` This is passing the address of the 501th entry in the array `carSales[]` That is NOT what you want, amongst other things, this is passing the address past the end of the array `carSales[]` Suggest: `outputPrice(&carSales, &carsSold, &avgCarPrice, &totalRevenue);` ` – user3629249 Jan 26 '18 at 06:13

1 Answers1

0

First of all, the outputPrice function should have return type void rather than int; this gave me an error when I tried to compile your code originally.

Next, in the newSale function, the line

scanf("%i", &price);

should be changed to

scanf("%i", price);

because price is already a pointer. In the other four scanf calls, %s should be changed to `%c; e.g.

scanf("%s", firstTime);

should be changed to

scanf("%c", firstTime);

%s is the format specifier for a string; %c is for characters. Also note that the arguments still do not need to be referenced by prepending a & to their names, because they are also already pointers. The first line of the third if statement should be changed from

if (*student == 'y' && firstTime == 'y') {

to

if (*student == 'y' && *firstTime == 'y') {

Notice the & prepended to firstTime. This is necessary because firstTime is a pointer, not a character, and so comparing it to the character literal 'y' is going to yield incorrect results. However, firstTime is a pointer to a character, and so dereferencing it with * returns a character, which can then be compared to the character literal without a problem. The return statement also has a problem:

return price;

should be

return *price;

because the return type of the function is int, and price is an int pointer.

In the outputPrice function, the arguments in all of your printf statements need to be dereferenced. E.g.

printf("The total cars sold is: %i", carsSold);

should be

printf("The total cars sold is: %i", *carsSold);

because carsSold is an int pointer, not an int itself.

Also, main needs to be given a return type of int to avoid a compiler warning.

Jared Cleghorn
  • 551
  • 5
  • 8