我正在编写一个使用指针进行摊销的小程序
#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循环中的int变量i或为什么IDE会处理错误,所以干净地请教育!
答案 0 :(得分:2)
您的代码存在大量问题,这些问题正等待引起问题。如您所知,您无法通过使用ptr += i
来增加指针来保护数组边界,从而导致您无法访问并写入数组存储之外的内存来调用 Undefined Behavior 。
以interest
和ipoint
为例:
double interest[7] = {0};
ipoint = &interest[0];
因此,您在interest
数组中的索引如下,并且ipoint
初始化为指向interest
中的第一个元素:
+---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
+---+---+---+---+---+---+---+
^
|
ipoint
在循环中,您前进ipoint += i
。在循环的第一次迭代中,您将ipoint
前进了一个:
+---+---+---+---+---+---+---+
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
当i = 4
前进ipoint
超出数组末尾时,当您为ipoint
分配值并尝试存储时调用未定义行为您不拥有的内存中的值:
+---+---+---+---+---+---+---+---+---+---+---+
interest | 0 | 1 | 2 | 3 | 4 | 5 | 6 | out of bounds |
+---+---+---+---+---+---+---+---+---+---+---+
^
|
ipoint
注意:当调用 Undefined Behavior 时,您的代码看起来可以正常工作,或者可以SEGFAULT
(或两者之间的任何内容)进行操作您的代码只是 Undefined ,从那时起就不能再依赖了。
您需要做的是将每个指针前进1
,而不是'i'
。这样可以确保您不会写超出数组范围的内容。您可以通过简单地将'i'
更改为1
,例如
ipoint += 1;
bpoint += 1;
ppoint += 1;
还有许多其他地方可能会导致您调用未定义行为。您无法检查scanf
的返回。如果您输入(偶然或键盘的敲击声)非数字值,则会发生匹配失败,将不会从stdin
中读取任何字符,并且会进一步提示将被跳过,然后您将继续使用不确定的值进行处理,这将调用未定义行为。
此外,如果您为7
输入大于number_of_payments
或小于零的值,则会调用未定义行为。 (对于number_of_payments = 0
,结果也很有趣)。在进行输入时,不仅要验证转换是否成功,而且还必须验证结果值是否在可用范围内-避免 Undefined Behavior ,例如
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;
}
最后,尽管您可以自由初始化ipoint = &interest[0];
,但这不是必需的。访问数组时,该数组将转换为指向其第一个元素的指针,因此ipoint = interest;
就足够了。下面的注释中还解决了其他问题,但总的来说,您可以执行以下操作以确保在整个代码中定义行为:
#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;
}
(注意:是从i=1
到i <= number_of_payments
还是从i=0
到i < number_of_payments
进行循环,但这取决于您循环变量跟踪有效数组索引以保护数组边界的标准。如上所述,付款编号的输出只需通过i + 1
进行调整即可产生所需的{{ 1}})
(另请注意:在实践中,您想避免使用浮点数作为货币。当您由于舍入错误而亏损时,人们会感到非常沮丧。消除了这个问题)
仔细检查一下,如果还有其他问题,请告诉我。
答案 1 :(得分:0)
这归因于您在+= i;
中的for-loop
语句,将其更改为'++'
。当您使用+= i;
时,您的指针 发生了太多的增量(不是增加 1 而是增加了 i )
修改后的for-loop
:-
for (i = 1; i <= number_of_payments; i++)
{
ipoint ++; // not +=i
bpoint ++; // not +=i
ppoint ++; // not +=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 ++; //Iterates after logic for next calculation. not +=i
}
因为+=i
消耗大量内存(增量过多),导致 堆栈粉碎 错误。
输出:-
Enter amount of loan : $ 2000
Enter Interest rate per year : 7.5
Enter number of payments : 6
Monthly payment should be $ 340.662858
# Payment Principal Interest Balance
1 340.66 328.16 12.50 1671.84
2 340.66 330.21 10.45 1341.62
3 340.66 332.28 8.39 1009.35
4 340.66 334.35 6.31 674.99
5 340.66 336.44 4.22 338.55
6 340.66 338.55 2.12 0.00