我正在写一个使用指针分期偿还的小程序
#include <stdio.h>
#include <string.h>
double power(double a, double b);
int main(void)
{
int loanAmount, number_of_payments, i = 0;
double interestRate, monthlyInterestRate, monthlyPayment;
printf("Enter amount of loan : $ ");
scanf(" %i",&loanAmount);
printf("Enter Interest rate per year : ");
scanf(" %lf",&interestRate);
printf("Enter number of payments : ");
scanf(" %i",&number_of_payments);
monthlyInterestRate = ((interestRate / 100) / 12); //AKA 'r' or rate.
monthlyPayment = (monthlyInterestRate) * (loanAmount/(1 - 1/(power((1 +
monthlyInterestRate), number_of_payments))));
double interest[7] = {0}; //Arbitrarily set to 7 - assuming less payments.
double principal[7] = {0};
double balance[7] = {0};
balance[0] = loanAmount;
double *ipoint,*ppoint,*bpoint,*bpointprev;
ipoint = &interest[0];
ppoint = &principal[0];
bpoint = &balance[0];
bpointprev = bpoint;
printf("Monthly payment should be $ %lf\n",monthlyPayment);
printf("# \t Payment \t Principal \t Interest \t Balance \n");
for (i = 1; i <= number_of_payments; i++) {
ipoint += i;
bpoint += i;
ppoint += i;
*ipoint = *bpointprev * monthlyInterestRate;
*ppoint = monthlyPayment - *ipoint;
*bpoint = *bpointprev - *ppoint;
printf("%i \t %.2f \t %.2f \t\t %.2f \t\t %.2f\n",i,monthlyPayment,*ppoint,*ipoint,*bpoint);
bpointprev += i; //Iterates after logic for next calculation.
}
return 0;
}
double power(double a, double b)
{
double i, sum = 1;
for (i = 0; i < b; i++) {
sum = sum * a;
}
return sum;
}
遇到一个问题,我正在编写的IDE可以很好地运行程序:
在Cloud9 IDE上:
但在Unix终端上,for循环中的增量变量在似乎是任意计数之后跳转:
在Unix终端上:
我很肯定它会处理所有的指针引用,但我不知道它为什么会影响for循环中的in t变量,也不知道IDE为什么会如此干净地处理错误。请教育!
最佳答案
您的代码中有大量的问题,这些问题正等待引起问题。正如您所发现的,您无法通过使用ptr += i
递增指针来保护数组边界,这会导致您通过访问和写入数组存储之外的内存来调用未定义的行为。
例如interest
和ipoint
:
double interest[7] = {0};
ipoint = &interest[0];
因此
interest
数组中的索引如下所示,ipoint
被初始化为指向interest
中的第一个元素: +---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
+---+---+---+---+---+---+---+
^
|
ipoint
在你的循环中,你正在前进。在循环的第一次迭代中,将
ipoint += i
向前推进一次: +---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
+---+---+---+---+---+---+---+
^
|
ipoint
你的第二次迭代,你前进两步:
+---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
+---+---+---+---+---+---+---+
^
|
ipoint
你的第三次迭代,你前进了三次:
+---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
+---+---+---+---+---+---+---+
^
|
ipoint
当
ipoint
您将i = 4
推进到数组末尾之后,并且当您将值赋给ipoint
并试图将该值存储在您不拥有的内存中时,调用未定义的行为: +---+---+---+---+---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 | out of bounds |
+---+---+---+---+---+---+---+---+---+---+---+
^
|
ipoint
注意:当调用未定义的行为时,您的代码可能看起来工作正常,或者它可以
ipoint
(或两者之间的任何内容),您的代码的操作只是未定义的,从那时起就不能依赖它。您需要做的是将每个指针向前推进
SEGFAULT
,而不是1
。这将确保你不会写超出你的数组界限。您可以通过简单地将每个的'i'
更改为'i'
来解决问题,例如。 ipoint += 1;
bpoint += 1;
ppoint += 1;
还有很多其他地方,您可能会调用未定义的行为。您无法检查
1
的返回。如果您输入(意外地,或键盘的cat步骤)数值以外的任何内容,则会发生匹配失败,不会从scanf
中读取任何字符,并且将跳过所有进一步的提示,然后您将继续使用不确定值进行处理,该值将调用未定义的行为。此外,如果为
stdin
输入的值大于7
或小于零,则调用未定义的行为。(对于number_of_payments
,结果也相当无趣)接受输入时,不仅要验证转换是否成功,而且必须验证结果值是否在可用范围内--以避免未定义的行为,例如。 printf ("Enter number of payments : ");
if (scanf (" %i", &number_of_payments) != 1) {
fprintf (stderr, "error: invalide no. of payments.\n");
return 1;
}
/* validate no. pmts in range */
if (number_of_payments < 1 || number_of_payments > MAXPMTS) {
fprintf (stderr, "error: no. of payments exceed MAXPMTS (%d)\n",
MAXPMTS);
return 1;
}
最后,虽然您可以自由初始化
number_of_payments = 0
,但这是不必要的。访问数组时,数组将转换为指向其第一个元素的指针,因此只需ipoint = &interest[0];
。下面的注释中还讨论了其他问题,但总而言之,您可以执行如下操作,以确保在整个代码中定义行为:#include <stdio.h>
#include <string.h>
#define MAXPMTS 32 /* if you need a constant, define one (or more) */
double power (double a, double b);
int main (void)
{
int loanAmount = 0, /* initialize all variables */
number_of_payments = 0,
i = 0;
double interestRate = 0.0,
monthlyInterestRate = 0.0,
monthlyPayment = 0.0;
/* numeric conversions consume leading whitespace (as does %s)
* the ' ' in the conversion doesn't hurt, but isn't required.
*/
printf ("Enter amount of loan : $ ");
if (scanf (" %i", &loanAmount) != 1) { /* validate conversion */
fprintf (stderr, "error: invalid loan amount.\n");
return 1;
}
printf ("Enter Interest rate per year : ");
if (scanf (" %lf", &interestRate) != 1) {
fprintf (stderr, "error: invalid interest rate.\n");
return 1;
}
printf ("Enter number of payments : ");
if (scanf (" %i", &number_of_payments) != 1) {
fprintf (stderr, "error: invalide no. of payments.\n");
return 1;
}
/* validate no. pmts in range */
if (number_of_payments < 1 || number_of_payments > MAXPMTS) {
fprintf (stderr, "error: no. of payments exceed MAXPMTS (%d)\n",
MAXPMTS);
return 1;
}
monthlyInterestRate = ((interestRate / 100) / 12); //AKA 'r' or rate.
monthlyPayment = (monthlyInterestRate) * (loanAmount/(1 - 1/(power((1 +
monthlyInterestRate), number_of_payments))));
double interest[MAXPMTS] = {0};
double principal[MAXPMTS] = {0};
double balance[MAXPMTS] = {0};
balance[0] = loanAmount;
double *ipoint = NULL,
*ppoint = NULL,
*bpoint = NULL,
*bpointprev = NULL;
ipoint = interest;
ppoint = principal;
bpoint = balance;
bpointprev = bpoint;
printf ("Monthly payment should be $ %lf\n", monthlyPayment);
printf ("# \t Payment \t Principal \t Interest \t Balance \n");
/* standard loop is from 0 to i < number_of_payments */
for (i = 0; i < number_of_payments; i++) {
ipoint += 1;
bpoint += 1;
ppoint += 1;
*ipoint = *bpointprev * monthlyInterestRate;
*ppoint = monthlyPayment - *ipoint;
*bpoint = *bpointprev - *ppoint;
/* adjust 'i + 1' for payment no. output */
printf ("%i \t %.2f \t %.2f \t %.2f \t\t %.2f\n",
i + 1, monthlyPayment, *ppoint, *ipoint, *bpoint);
bpointprev += 1; //Iterates after logic for next calculation.
}
return 0;
}
double power(double a, double b)
{
double i, sum = 1;
for (i = 0; i < b; i++) {
sum = sum * a;
}
return sum;
}
(注意:从
ipoint = interest;
循环到i=1
还是从i <= number_of_payments
循环到i=0
很大程度上取决于您,但循环变量跟踪有效数组索引以保护数组的边界是标准的。如上所述,只需通过i < number_of_payments
调整支付号码的输出,即可生成所需的i + 1
)(另请注意:在实践中,您希望避免对货币使用浮点数学。当你因为四舍五入错误而赔钱的时候,人们会很难过。整数数学消除了这个问题)
再看一遍,如果你还有问题,请告诉我。