在 C 语言中取消引用指针时遇到困难

Having difficulties dereferencing a pointer in C

提问人:Leila Jones 提问时间:9/18/2023 最后编辑:Leila Jones 更新时间:9/18/2023 访问量:84

问:

我的任务是编写一个程序,询问用户他们必须花多少钱,然后询问用户他们想购买多少张票。我必须有一个 main() 函数和一个 PurchaseTickets() 函数。我是指针的新手,并且对如何使用它们来分配局部变量以及将这些局部变量用于计算感到非常困惑。我能深入了解我哪里出了问题,以及如何将其变成一个可用的程序吗?

编辑:必须有两个功能:主要和购买门票。使用变量 remaining cash 的指针是必要的,如果用户没有足够的钱来购买门票,程序必须返回 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;
}
C 函数 指针

评论


答:

1赞 NoDakker 9/18/2023 #1

我查看了您的代码,从我所看到的所需解决方案来看,该程序目的的上下文确实不需要指针。首先,由于“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.

总而言之,在函数中传递变量地址代替变量值是有正当理由的,但人们应该始终了解函数的上下文,以确定是否有必要这样做。寻找有关函数定义的其他教程,了解指针何时有益可能是明智的。

评论

0赞 Leila Jones 9/18/2023
是的,剩余现金变量的指针是分配所必需的,对于造成混淆,我深表歉意!我将编辑主帖子,使作业要求更加明确。我仍然感谢您的输入,因为它让我有一个更好的起点来继续尝试找出指针!
4赞 Fe2O3 9/18/2023 #2

这是一团糟。在不重复@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
}

评论

0赞 Leila Jones 9/18/2023
感谢您的输入!我对 C 很陌生,肯定还在学习。谢谢你的帮助!我认为,一旦我对指针的误解使我创建了错误使用/不必要的变量,我的代码就变得混乱了。
3赞 Fe2O3 9/18/2023
我曾经和一个家伙一起工作,他似乎认为他输入的代码量是“按英镑支付的”......添加更多变量、使用冗长的名称和无用的注释(例如“如果输入无效字符将退出程序”)只会使您的代码更难阅读(对我们和您来说......正确、干净、清脆和清晰是理想的形容词。
3赞 Fe2O3 9/18/2023
在“The Elements of Programming Style”一文中,作者引用了 Fortran 程序中的一个实例,其中 4 行注释解释了缺少“END”来标记某些程序源代码的结尾......假设你的读者熟悉 C,但可能想知道为什么在代码中做出了某些选择......为什么,不是什么。祝你未来一切顺利...(PS:选择 4 行评论而不是“END”是一个糟糕的选择......
4赞 Retired Ninja 9/18/2023
@LeilaJones 你编写的代码越多,你就越擅长评论。我倾向于在编写代码时写很多东西,因为我会制作一个大纲来分解任务,然后围绕它编写代码,但一旦我现在完成,我就更擅长清理它。当你回到你以前写的代码时,你就会知道哪些是重要的,并且不明白你为什么以某种方式做某事。解释你为什么做某事是好的,但代码应该足以解释如何做。幸运的是,你编写的代码越多,你就越能更好地一致地命名事物。
1赞 Fe2O3 9/18/2023
@RetiredNinja 听见,听见!!:-)
2赞 Retired Ninja 9/18/2023 #3

在函数中存在一些问题。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);

你所拥有的是有效的,但我认为最好不要为此创建一个额外的变量。如果之后有更多的代码,可能会混淆使用哪一个。