Fortran Coder

标题: 求解释:用module里的变量和用数字定义数组为什么结果不同 [打印本页]

作者: Villain    时间: 2015-5-20 11:01
标题: 求解释:用module里的变量和用数字定义数组为什么结果不同
由于涉及到版权,我无法上传代码,情况大致是这样的:
在一个module里定义了一个integer::nx,
在一些子程序中调用这个module,并用nx作为一些数组的边界值。
nx在主程序刚开始就已经赋值,并且在程序中没有对其进行计算,是一个定值。在这里是146
在一个特定的子程序中,如果我在定义局部数组的时候要是用integer::njb_new(nx),则计算到后来会报错,报错的内容大致就是njb(i)=0导致数组越界,但是我用integer::njb_new(146)来定义的时候,则不会出现此错误。
在这一过程中其他部分的完全没改变。

先不管其他部分的代码的逻辑对不对,在nx=146的情况下,integer::njb_new(nx)和integer::njb_new(146)有什么区别?


愁屎了。


作者: 楚香饭    时间: 2015-5-20 11:08
如果 nx 的值确实从来没改变过。那么 integer::njb_new(nx) 和 integer::njb_new(146) 是一样的。
作者: Villain    时间: 2015-5-20 12:22
楚香饭 发表于 2015-5-20 11:08
如果 nx 的值确实从来没改变过。那么 integer::njb_new(nx) 和 integer::njb_new(146) 是一样的。 ...

还真是没变。
那个子程序只要输出一次我就让nx输出一次,整个计算过程中nx完全没变化,全都是146。但是只要用nx来设置数组就会报错。我已经无语了。

作者: 楚香饭    时间: 2015-5-20 12:53
debug调试,找到越界的位置,查看下标和数组定义。
作者: pasuka    时间: 2015-5-20 12:55
用了ivf吗?是的话,多半和save属性有关
既然nx事前确定,为啥不加parameter属性?
作者: Villain    时间: 2015-5-20 14:33
pasuka 发表于 2015-5-20 12:55
用了ivf吗?是的话,多半和save属性有关
既然nx事前确定,为啥不加parameter属性? ...

用的是microsoft visual studio 2008。
因为nx是从外部读入的,不同的case对应的nx不一样。
作者: pasuka    时间: 2015-5-20 15:19
本帖最后由 pasuka 于 2015-5-20 15:23 编辑
Villain 发表于 2015-5-20 14:33
用的是microsoft visual studio 2008。
因为nx是从外部读入的,不同的case对应的nx不一样。 ...

vs2008和ivf不是一码事情。。。不能排除在循环的时候变量i其实大于nx,所以报错

不妨把i的值打印出来看看

作者: Villain    时间: 2015-5-20 17:24
pasuka 发表于 2015-5-20 15:19
vs2008和ivf不是一码事情。。。不能排除在循环的时候变量i其实大于nx,所以报错

不妨把i的值打印出来看看 ...

打印了,完全没问题。
作者: Villain    时间: 2015-5-20 17:35
本帖最后由 Villain 于 2015-5-20 17:37 编辑

file:///C:/Users/i7-32/Desktop/Image%203.png

这是用winmerge把成功运算和不成功运算两者代码比较了一下,左边是成功运算的,右边是不成功运算的。
黄色表示有区别的位置。
下面还有一条黄色,那个是因为用了allocate所以下面有个deallocate的语句。
可以看出两者只是数组的定义方式不同而已。

报错的地方是另外一个子函数,数组下标越界。

然后根据pasuka所说的,把nx+3输出,结果全部都等于146
file:///C:/Users/i7-32/Desktop/Image%206.png

求解释。

Image 3.png (87.29 KB, 下载次数: 423)

Image 3.png

Image 6.png (13.05 KB, 下载次数: 414)

Image 6.png

作者: pasuka    时间: 2015-5-21 08:48
Villain 发表于 2015-5-20 17:35
这是用winmerge把成功运算和不成功运算两者代码比较了一下,左边是成功运算的,右边是不成功运算的。
黄 ...

循环的时候,数组下标呢?有一个或几个超过146了?
作者: Villain    时间: 2015-5-21 09:08
pasuka 发表于 2015-5-21 08:48
循环的时候,数组下标呢?有一个或几个超过146了?

没有,在这个子程序中,循环的范围是从1到nx,而nx的值是143,也就是说根本不影响。
如果因为下标超过nx之类的,那么用数字146定义的时候就会报错,然而用146定义数组的话完全没问题。
作者: pasuka    时间: 2015-5-21 11:08
Villain 发表于 2015-5-21 09:08
没有,在这个子程序中,循环的范围是从1到nx,而nx的值是143,也就是说根本不影响。
如果因为下标超过nx之 ...

那就爱莫能助了。。。
作者: fcode    时间: 2015-5-21 11:54
把错误提示给出来,完整的,不翻译,不截取。

尝试在越界的函数里下断点,debug 调试。
作者: Villain    时间: 2015-5-22 08:40
fcode 发表于 2015-5-21 11:54
把错误提示给出来,完整的,不翻译,不截取。

尝试在越界的函数里下断点,debug 调试。 ...

谢谢指点。
总算debug出来了。

原因是因为程序跳入了一个判断,并直接用cycle循环了do,对njb_new这个数组没有赋值,而njb_new将作为一个数组的下标,当它小于等于0的时候,导致程序出错。
而为什么用nx+3定义会出错而146出错不会,根据我的推测,原因根pasuka指点的一样,是因为save的属性。当用146定义的时候,编译器默认会使用save属性,也就是说上一次的值会保存下来直到重新赋值。而用使用变量(这个例子中是nx)赋值的时候,虽说它的值也是146,但是在每次调用子程序的时候,系统都会对其重置,从而导致出错。

得出结论:
也就是说用变量定义数组和用数字定义数组,性质虽说相同,但是计算机处理的方式不同。
初始化这种东西要时刻铭记于心。
allocate后的数组基本都不会为0,而用直接用integer或者real定义的变量都会自动为0?(这是编译器的效果么?或者编译器与编译器之间有区别?我用的vs2008)


作者: Villain    时间: 2015-5-22 08:40
pasuka 发表于 2015-5-21 11:08
那就爱莫能助了。。。

谢谢指点,正如你所说是因为save属性的问题~~~~~
作者: fcode    时间: 2015-5-22 09:23
如果你早点把“错误信息”给出来,我们知道是哪个数组越界,早就解决了。我一直以为是 njb_new 本身越界。

错误信息非常非常关键。单纯说“越界”没用,最好是完整的错误提示!

未初始化的变量,其值不确定。(认真理解这句话,理解什么叫“不确定”,老生都不想常谈了)
作者: pasuka    时间: 2015-5-22 12:48
fcode 发表于 2015-5-22 09:23
如果你早点把“错误信息”给出来,我们知道是哪个数组越界,早就解决了。我一直以为是 njb_new 本身越界。
...

你对lz期望值太高了,ivf好像可以统一给变量赋初值的




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2