C语言 这个发布的三次样条极值代码是否有错误?



我正在尝试实现1996年发布的幺方样条极值算法。

我不是一个有成就的程序员,很明显作者是,而且比我聪明一两个数量级。 但是,当我尝试编译它时,它会在简单的越界数组访问上出错。 我发现很难相信这个算法是带着在我看来是一个微不足道的错误发布的。因此,我的结论是误解可能是我的,而不是作者。(例如,也许他正在使用一个我不知道的技巧,可能在 20 年前在 c 中起作用......

第一个段错误发生在这里,尝试访问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);}

而且,如果我修复上面的 for 循环以从1开始,那么出于类似的原因,下一个循环将发生另一个段错误,(diag[i-2]-->diag[-1])

for (i = 1; i < num_pnts - 1; i++)
right[i-1] = 6.0 * ((y[i+1]-y[i])/diag[i-1]-(y[i]-y[i-1])/diag[i-2]);

完整源代码的链接在这里

所以我的问题是,这个算法是由一个非常有成就的人发布的,而不是一年级的CS学生。 因此,虽然这些对我来说看起来像错误(事实上,在 2019 年的系统上是段错误),但我错过了其他事情吗?例如,这个 OOB 错误是否会在 1996 c 编译器或其他东西上产生不同的结果?

问题:这些真的是错误吗?

是的,这些都是实际的错误。数组diag是使用malloc()分配的。指针指向已分配区域的开头。当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]);
}

越界访问并不一定会导致分段错误,它只是未定义的行为。这取决于编译器和malloc()分配内存边界之外的内存是否有效实现。即使内存是可访问的,diag[i - 2]也在除法运算符的右侧,因此如果该位置的内存包含零,也会导致除以零。因此,它可能也会与 1999 年的编译器一起崩溃。

最好能弄清楚应该实现哪些公式,然后检查代码是否正确。

相关内容

  • 没有找到相关文章

最新更新