SigSegv when passing array element to a recursive function in a loop in Pascal

Viewed 97

So in this program we ceate an array Tab1 with Random values in its 10 elements then we get the factorial of each Tab1 element and put it in Tab2, using two methods the iterative and the recursive one. When using the iterative function Tab2 is filled with factorials with no problems but when I use the recursive function the program quits immediately. If you can help me understanding the problem in depth I would be so much appreciated...I read about segmentation fault on Wikipedia which said that it's because the program is trying to get to a memery location that it doesn't have the permission to enter but the problem is when I choose a special element from Tab1 for example Tab1[5] and pass it to factorielleRecursive in Calc2 it works just as fine, any thoughts?

Program recursive;
Type
T = array [1..10] of LongInt;
Var
Tab1, Tab2 : T;
num : integer;

Function FactorielleIterative(N : integer) : integer;
Var
F, i : integer;
Begin
    F := 1;
    for i:=1 to N Do
        F := F*i;
    FactorielleIterative := F;
End;

Function FactorielleRecursive(N : LongInt) : LongInt;
Begin
        if (N=1) Then
            FactorielleRecursive := 1
        Else
        FactorielleRecursive := N * FactorielleRecursive(N-1);
End;

Procedure Fill(var Tab : T);
Var
i : Integer;
Begin
    Randomize;
    For i:=1 to 10 Do
    Begin
            Tab[i] := Random(10);
    End;
    For i:=1 to 10 Do
        Write('[', Tab[i], '] ');
End;

Procedure Calc1(Tab1 : T; var Tab2 : T);
Var
i : integer;
Begin
    For i:=1 to 10 Do
    Begin
            Tab2[i] := FactorielleIterative(Tab1[i]);
    End;
    For i:=1 to 10 Do
        Write('[', Tab2[i], '] ');
End;

Procedure Calc2(Tab : T; var Tab2 : T);
Var
i : integer;
Begin
    For i:=1 to 10 Do
    Begin
            Tab2[i] := FactorielleRecursive(Tab[i]);
    End;
    For i:=1 to 10 Do
        Write('[', Tab2[i], '] ');
End;

Begin

        Write('Tab1 : ');
        Writeln;
        Fill(Tab1);
        Writeln;
        Writeln;
        Write('Tab2 : Iterative method');
        Writeln;
        Calc1(Tab1, Tab2);
        Writeln;
        Writeln;
        Write('Tab2 : Recursive method');
        Writeln;
        Calc2(Tab1, Tab2);

     Readln;
End.
2 Answers

You are not taking in consideration what happens if the Tab[] array contains a zero value. This situation is possible since you call Random(10) which will return a value in the range 0 .. 9.

In Function FactorielleIterative() an argument of zero is treated as a '1' value (because the for loop is not executed).

In Function FactorielleRecursive() an argument of zero is treated as a '0' value, with the consequence of the recursive call FactorielleRecursive(N-1); leading to range overflow.

The solution is simple so I leave it to you to fix, in order not to spoil your homework.

My thoughts:

  • I could not reproduce this issue in my setup:
bash$ fpc so.pas && ./so
Free Pascal Compiler version 3.2.0+dfsg-12 [2021/01/25] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling so.pas
so.pas(6,1) Note: Local variable "num" not used
Linking so
76 lines compiled, 0.1 sec
1 note(s) issued

NOTE: unused variable should be removed.

  • Can you provide more details about your compiler and its options at compile time and your OS?

  • Tab1[5] is just a random value: it changes run by run. How did you use it for verification? Do you know what was its current value? I called FactorielleRecursive(10); from the main block and I could not experience any issue with that. Is this issue intermittent in your runtime environment?

  • Your iterative function get and returns only Integer. I think you should change the return type to LongInt as you did in recursive way. Here a runtime difference between the two version (with some overflow: see the negative value(s)):

Tab2 : Iterative method
[5040] 
[720] 
[2] 
[1] 
[720] 
[5040] 
[24] 
[1] 
[-25216] <<<<<<<<<<<<<<<<< Integer overflow
[24] 
Tab2 : Recursive method
[5040] 
[720] 
[2] 
[1] 
[720] 
[5040] 
[24] 
[1] 
[40320] 
[24]

Minor notes:

  • You can extract repetitive code parts into a procedure/function. In this case the for loops repeated 3 times to write out contents of Tab array.
  • You can merge Write and WriteLn into a single statement. For example WriteLn('Tab2 : Iterative method'); - it is a more compact form.
Related