Возникли трудности с разыменованием указателя в C

Мне поручено написать программу, которая спрашивает пользователя, сколько денег ему нужно потратить, а затем спрашивает пользователя, сколько билетов он хочет купить. У меня должна быть функция main() и функция PurchaseTickets(). Я новичок в указателях и совершенно не понимаю, как их использовать для назначения локальных переменных и использования этих локальных переменных в вычислениях. Могу ли я получить некоторое представление о том, где я ошибаюсь, и как превратить это в полезную программу?

Обновлено: должно быть две функции: основная и покупка билетов. необходимо использовать указатель для переменной оставшихся денег, и программа должна вернуть 0, если у пользователя недостаточно денег для покупки билетов.

#include <stdio.h>

#define ADULT_TICKET_PRICE 69.00                                                    //define constants
#define CHILD_TICKET_PRICE 35.00

int PurchaseTickets(double *pRemainingCash, int adultTickets, int childTickets);    //declare function PurchaseTickets()

int main(void)
{
    double funds;
    int childTickets;
    int adultTickets;

    printf("How much money do you have to purchase tickets?\n");
    if (scanf("%lf", &funds) != 1)                        //check for errors in user input
    {
        printf("Invalid input, exiting program.\n");
        return 1;                                       //will exit program if invalid characters are entered
    }

    printf("How many child tickets would you like to purchase?\n");
    if (scanf("%d", &childTickets) != 1)                 //check for errors in user input
    {
        printf("Invalid input, exiting program.\n");
        return 1;                                       //will exit program if invalid characters are entered
    }

    printf("How many adult tickets would you like to purchase?\n");
    if (scanf("%d", &adultTickets) != 1)                 //check for errors in user input
    {
        printf("Invalid input, exiting program.\n");
        return 1;                                       //will exit program if invalid characters are entered
    }

    double *pfunds = &funds;

    PurchaseTickets(pfunds, adultTickets, childTickets);

    return 0;
}

/*****************************************************************************************
 *
 *  Function:  PurchaseTickets()
 *
 *  Parameters:
 *
 *      pRemainingCash - points to a variable containing the amt of cash from user
 *      adultTickets - specifies the number of adult tickets the user wants to buy
 *      childTickets - specifies the number of child tickets the user wants to buy
 *
 *  Description: 
 *
 *      The function will determind if the user has enough money to purchase the
 *      specified number of tickets. If they do, the function deducts the proper funds
 *      from their remaining cash and returns the total number of tickets purchased.
 *      if they do not the function returns 0.
 *
*****************************************************************************************/

int PurchaseTickets(double *pRemainingCash, int adultTickets, int childTickets)
{
    double adultCost = (adultTickets * ADULT_TICKET_PRICE);
    double childCost = (childTickets * CHILD_TICKET_PRICE);
    double totalCost = adultCost + childCost;

    int totalTickets = adultTickets + childTickets;

    double remainingCash = *pRemainingCash;
    pRemainingCash = &remainingCash;

    pRemainingCash = remainingCash - totalCost;


    if (*pRemainingCash >= totalCost)
    {
        printf("You have purchased %d tickets, and you have %.2f remaining.",totalTickets, pRemainingCash);
    }

    else
    {
        printf("You do not have enough money to purchase the tickets.");
        return 0;
    }

    return 1;
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
82
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Я просмотрел ваш код и, судя по тому, что я видел как желаемое решение, указатели действительно не нужны для контекста цели этой программы. Во-первых, поскольку функция «PurchaseTickets» на самом деле не возвращает никакой необходимой информации, имеет смысл настроить ее с помощью возвращаемой записи void. Во-вторых, поскольку все необходимые входные переменные для функции можно просто передать как значения, в отправке ссылок на указатели действительно нет необходимости.

Чтобы минимально внести минимальные изменения в ваш код, следующие операторы можно закомментировать в вашей функции вместе с рефакторингом оператора printf.

    //double remainingCash = *pRemainingCash;           // Not needed
    //pRemainingCash = &remainingCash;

    //pRemainingCash = remainingCash - totalCost;


    if (*pRemainingCash >= totalCost)
    {
        printf("You have purchased %d tickets, and you have %.2f remaining.",totalTickets, *pRemainingCash - totalCost);    // Note remainder calculation
    }

Это привело к следующему тестовому выводу на терминале.

craig@Vera:~/C_Programs/Console/TicketPurchase/bin/Release$ ./TicketPurchase 
How much money do you have to purchase tickets?
800
How many child tickets would you like to purchase?
4
How many adult tickets would you like to purchase?
4
You have purchased 8 tickets, and you have 384.00 remaining.

Принимая во внимание наблюдения за кодом и упрощая ситуацию, ниже приведена реорганизованная версия вашей программы.

#include <stdio.h>

#define ADULT_TICKET_PRICE 69.00                                                    //define constants
#define CHILD_TICKET_PRICE 35.00

void PurchaseTickets(double pRemainingCash, int adultTickets, int childTickets);    //declare function PurchaseTickets()

int main(void)
{
    double funds;
    int childTickets;
    int adultTickets;

    printf("How much money do you have to purchase tickets? ");
    if (scanf("%lf", &funds) != 1)                       //check for errors in user input
    {
        printf("Invalid input, exiting program.\n");
        return 1;                                       //will exit program if invalid characters are entered
    }

    printf("How many child tickets would you like to purchase? ");
    if (scanf("%d", &childTickets) != 1)                 //check for errors in user input
    {
        printf("Invalid input, exiting program.\n");
        return 1;                                       //will exit program if invalid characters are entered
    }

    printf("How many adult tickets would you like to purchase? ");
    if (scanf("%d", &adultTickets) != 1)                 //check for errors in user input
    {
        printf("Invalid input, exiting program.\n");
        return 1;                                       //will exit program if invalid characters are entered
    }

    PurchaseTickets(funds, adultTickets, childTickets);

    return 0;
}

/*****************************************************************************************
 *
 *  Function:  PurchaseTickets()
 *
 *  Parameters:
 *
 *      pRemainingCash - points to a variable containing the amt of cash from user
 *      adultTickets - specifies the number of adult tickets the user wants to buy
 *      childTickets - specifies the number of child tickets the user wants to buy
 *
 *  Description:
 *
 *      The function will determind if the user has enough money to purchase the
 *      specified number of tickets. If they do, the function deducts the proper funds
 *      from their remaining cash and returns the total number of tickets purchased.
 *      if they do not the function returns 0.
 *
*****************************************************************************************/

void PurchaseTickets(double pRemainingCash, int adultTickets, int childTickets)
{
    double adultCost = (adultTickets * ADULT_TICKET_PRICE);
    double childCost = (childTickets * CHILD_TICKET_PRICE);
    double totalCost = adultCost + childCost;

    int totalTickets = adultTickets + childTickets;

    pRemainingCash -= totalCost;

    if (pRemainingCash >= 0.00)
    {
        printf("You have purchased %d tickets, and you have %.2f remaining.\n",totalTickets, pRemainingCash);
    }

    else
    {
        printf("You do not have enough money to purchase the tickets.\n");
    }

    return;
}

Обратите внимание на следующие уточнения:

  • Возвращаемое значение функции «PurchaseTickets» было изменено на «void», поскольку целочисленное возвращаемое значение, похоже, бесполезно.
  • Все переменные передаются как значения вместо использования указателей на переменные.
  • Ненужные переменные были удалены для упрощения расчетов и сравнений.

После этих доработок последовала серия дополнительных тестов программы и функции покупки билетов.

craig@Vera:~/C_Programs/Console/TicketPurchase/bin/Release$ ./TicketPurchase 
How much money do you have to purchase tickets? 300.00
How many child tickets would you like to purchase? 4
How many adult tickets would you like to purchase? 4
You do not have enough money to purchase the tickets.
craig@Vera:~/C_Programs/Console/TicketPurchase/bin/Release$ ./TicketPurchase 
How much money do you have to purchase tickets? 600
How many child tickets would you like to purchase? 4
How many adult tickets would you like to purchase? 4
You have purchased 8 tickets, and you have 184.00 remaining.

Напомним, что будут веские причины для передачи адресов переменных вместо значений переменных внутри функций, но всегда следует учитывать контекст функции, чтобы определить, необходимо это или нет. Вероятно, было бы разумно поискать дополнительные руководства по определению функций и тому, когда указатели полезны.

Да, для присваивания необходим указатель на оставшуюся переменную Cash, прошу прощения за путаницу! Я отредактирую основной пост, чтобы сделать требования к заданию более понятными. Я по-прежнему ценю ваш вклад, поскольку он дает мне лучшую отправную точку для дальнейших попыток выяснить указатели!

Leila Jones 18.09.2023 05:03

Это путаница. Не повторяя комментарии @NoDakker, ниже приведена сокращенная версия кода, показывающая необходимые операции. Обратите внимание, что некоторые переменные были переименованы (а комментарии удалены) для большей ясности.

// heading stuff omitted for brevity
int main(void)
{
    double funds;
    int childTickets;
    int adultTickets;

    /* Get funds */ // omitted for brevity

    /* Get # of Child tickets */

    /* Get # of Adult tickets */

    int totTckts = PurchaseTickets( &funds, adultTickets, childTickets );

    // Notice that the function performs its task.
    // Reporting those results belongs in the calling function
    if ( totTckts )
        printf( "%d tickets, and you have %.2f remaining.", totTckts, funds );
    else
        printf( "Insufficient funds to purchase those tickets." );

    return 0;
}

int PurchaseTickets( double *pFunds, int nAdult, int nChild )
{
    double Cost
        = (nAdult * ADULT_TICKET_PRICE)
        + (nChild * CHILD_TICKET_PRICE);

    if ( *pFunds < Cost ) // Insufficient available funds?
        return 0; // no show

    *pFunds -= Cost; // subtract cost from "double funds;" variable in main()

    return nAdult + nChild; // return # of purchased tickets
}

Я ценю ваш вклад! Я новичок в C и определенно все еще учусь. Спасибо вам за помощь! Я думаю, что мой код запутался, когда из-за неправильного понимания указателей я создал переменные, которые использовались неправильно/не были нужны.

Leila Jones 18.09.2023 05:10

Однажды я работал с парнем, который, кажется, думал, что ему «платят фунтами» за количество набранного им кода... Добавление дополнительных переменных, использование длинных имен и бесполезных комментариев (например, «выйдем из программы, если она недействительна»). вводятся символы") только усложнят чтение вашего кода (и для нас, и для вас...) Правильный, чистый, четкий и понятный — вот искомые прилагательные.

Fe2O3 18.09.2023 05:14

Большое спасибо! Я понимаю, насколько излишни мои комментарии, лол. Все мои преподаватели напоминают нам (студентам) о необходимости постоянно комментировать наш код, что, я думаю, заставило меня слишком много комментировать, и я не учел, какое влияние это оказало на общую чистоту программы. Впредь буду более избирательным в своих комментариях!

Leila Jones 18.09.2023 05:19

В «Элементах стиля программирования» авторы приводят пример в программе на Фортране, где комментарий из 4 строк объясняет отсутствие «END», обозначающего конец исходного кода некоторой программы... Предположим, что ваши читатели знакомы с C, но, возможно, захочется узнать, почему в коде были сделаны определенные выборы... Почему, а не что. Наилучшие пожелания вам в будущем... (PS: Выбор 4 строк комментария вместо "КОНЕЦ" был плохим выбором...)

Fe2O3 18.09.2023 05:30

@LeilaJones Чем больше вы пишете кода, тем лучше вы будете комментировать. Я склонен много писать во время написания кода, потому что я делаю своего рода набросок, чтобы разбить задачу, а затем кодирую ее, но мне лучше это очистить, когда я закончу. Вы узнаете, какие из них важны, когда возвращаетесь к написанному ранее коду и не понимаете, почему вы сделали что-то определенным образом. Объяснять, почему вы что-то сделали, — это хорошо, но кода должно быть достаточно, чтобы объяснить, как это сделать. К счастью, чем больше вы пишете кода, тем лучше вы будете давать последовательные имена вещам.

Retired Ninja 18.09.2023 05:34

@RetiredNinja Слышишь, слышишь!! :-)

Fe2O3 18.09.2023 05:34
Ответ принят как подходящий

В функции PurchaseTickets есть несколько проблем.

double remainingCash = *pRemainingCash;
pRemainingCash = &remainingCash;

Этот код создает копию значения pRemainingCash, на которое указывает, а затем указывает на локальную копию. Этот код правильный, но кажется, что это неправильно.

pRemainingCash = remainingCash - totalCost;

Здесь вы столкнетесь с ошибкой из-за синтаксиса. Он пытается присвоить указателю значение с плавающей запятой, а не то, на что указывает указатель. Для этого вам нужно *pRemainingCash = remainingCash - totalCost;

Это решит ошибку, но не проблему, поскольку изменяется локальная копия, а не переданное значение.

Другая проблема заключается в том, что вам следует проверить, могут ли они позволить себе билеты, прежде чем вычитать стоимость. Я ожидаю, что если стоимость превысит доступные средства, вы оставите доступные средства без изменений.

Вот очищенная версия:

int PurchaseTickets(double *pRemainingCash, int adultTickets, int childTickets)
{
    double adultCost = (adultTickets * ADULT_TICKET_PRICE);
    double childCost = (childTickets * CHILD_TICKET_PRICE);

    double totalCost = adultCost + childCost;
    int totalTickets = adultTickets + childTickets;

    if (*pRemainingCash >= totalCost)
    {
        // Subtract cost here
        *pRemainingCash -= totalCost;
        // Note *pRemainingCash in the next line. 
        // You need to dereference to obtain the value pointed at.
        printf("You have purchased %d tickets, and you have %.2f remaining.",
            totalTickets, *pRemainingCash);

        // Return success
        return totalTickets;
    }
    // This code won't be reached in the success case because of the return.
    // Removing the else avoids the possibility of the compiler warning that
    // all paths do not return a value.
    printf("You do not have enough money to purchase the tickets.");
    return 0;
}

Еще одно небольшое предложение в main.

Вместо double *pfunds = &funds; просто вызовите функцию, например PurchaseTickets(&funds, adultTickets, childTickets);

То, что у вас есть, работает, но я думаю, что лучше не создавать дополнительную переменную только для этого. Если бы после этого был еще код, можно было бы запутаться, какой из них использовать.

Другие вопросы по теме