C 此已发布的三次样条极值代码是否有错误?
我正试图实施1996年公布的《公约》 我不是一个有造诣的程序员,作者显然是,而且比我聪明一两个数量级。然而,当我尝试编译这个程序时,它会在一个简单的越界数组访问上出现错误。我发现很难相信这个算法是在我看来是一个小错误的情况下发布的。因此,我认为误解可能是我的,而不是作者。(例如,可能他使用了一个我不知道的技巧,20年前可能在c中工作过…) 第一个SEGFULT发生在此处,试图访问C 此已发布的三次样条极值代码是否有错误?,c,cubic-spline,C,Cubic Spline,我正试图实施1996年公布的《公约》 我不是一个有造诣的程序员,作者显然是,而且比我聪明一两个数量级。然而,当我尝试编译这个程序时,它会在一个简单的越界数组访问上出现错误。我发现很难相信这个算法是在我看来是一个小错误的情况下发布的。因此,我认为误解可能是我的,而不是作者。(例如,可能他使用了一个我不知道的技巧,20年前可能在c中工作过…) 第一个SEGFULT发生在此处,试图访问diag[-1]: float *diag; /* ptr to matrix diagonal array
diag[-1]
:
float *diag; /* ptr to matrix diagonal array */
for (i = 0; i < num_pnts - 1; i++){
diag[i-1] = x[i+1] - x[i];
assert(diag[i-1] > 0);}
所以我的问题是,这个算法是由一个非常有成就的人发布的,而不是CS一年级的学生。所以,虽然这些在我看来像是错误(事实上,2019年系统上的SEGFULT),但我是否还遗漏了其他一些东西?e、 这个OOB错误在1996年的c编译器上会有不同的结果吗
问题:这些真的是错误吗?是的,这些是实际的错误。使用
malloc()
分配数组diag
。指针指向所分配区域的开始。当i
等于0
时,通过计算diag[i-1]
,它可以访问所分配数组的边界之外
正如您正确尝试的那样,这段代码的for循环从1开始。事实上,那么diag[i-2]
也是错误的。由于main_diag[]
数组是从索引0
开始填充的,因此我认为这也是次要对角线的目的。所以我认为第二个和第三个循环应该是:
for (i = 0; i < num_pnts - 1; i++) {
diag[i] = x[i + 1] - x[i];
assert(diag[i] > 0);
}
/* compute right hand side of equation */
for (i = 1; i < num_pnts - 1; i++) {
right[i - 1] = 6.0 * ((y[i + 1] - y[i]) / diag[i] - (y[i] - y[i - 1]) / diag[i - 1]);
}
for(i=0;i0);
}
/*计算方程的右侧*/
对于(i=1;i
越界访问不一定会导致分段错误,它只是一种未定义的行为。它取决于编译器和malloc()
的实现,取决于所分配内存边界之外的内存是否有效。即使内存是可访问的,diag[i-2]
位于除法运算符的右侧,因此如果该位置的内存包含一个零,它将导致被零除法。因此,它也可能与1999年的编译器一起崩溃
如果您能够找出应该实现哪些公式,然后检查代码是否正确,那将是最好的。在出现6个完全错误和高度可疑的代码位(即使是90年代中期)后,我停止了计算。我不会用这个例子来说明如何写C。谢谢,你的评论和第二眼。奇怪的是,这本书似乎写得这么好,表达得这么好!我想我会选择统一的
(I=1;I
作为循环控件。谢谢。这样一个(显然)经过深思熟虑、记录良好的算法会伴随着如此糟糕的编码,这看起来确实很奇怪。每个人都会犯错误,即使是比你我聪明两个数量级的人。编码风格现在总体上看起来很糟糕,但在90年代后期非常典型。这是你会在广泛出版的书籍中找到的,比如。非常浓缩。再加上20年前编译器没有那么严格的事实,它实际上可能已经在作者的计算机上运行并产生了合理的结果。
for (i = 0; i < num_pnts - 1; i++) {
diag[i] = x[i + 1] - x[i];
assert(diag[i] > 0);
}
/* compute right hand side of equation */
for (i = 1; i < num_pnts - 1; i++) {
right[i - 1] = 6.0 * ((y[i + 1] - y[i]) / diag[i] - (y[i] - y[i - 1]) / diag[i - 1]);
}