C编程分段错误

时间:2017-05-15 10:39:20

标签: c segmentation-fault

这是查找第n个斐波纳契数的最后一位数的代码

#include <stdio.h>

int main() {
    long i, j, fib[1000];
    fib[0] = 0;         
    fib[1] = 1;         

    scanf("%li", &j);     

    for(i = 2; i != 1000; i++)     
    {
        fib[i] = (fib[i - 2] + fib[i - 1]) % 10;
    }
    printf("%li", fib[j]);
    return 0;
}

显示分段错误。我该如何解决?

3 个答案:

答案 0 :(得分:1)

我能看到这个不起作用的唯一原因是你输入的数字超出范围0 <= j <= 999。这是由于数组变量的限制:long fib[1000]

这可以通过两种方式之一修复,具体取决于您的需求:

  1. 您可以添加一项检查以确保输入值j在范围内,如果不是则请求另一个数字。
  2. 您可以停止使用数组变量,并且只使用三个变量:一个用于存储当前值,另外两个用于存储前两个值。这些会在您计算时更新。这种方法仍然使用循环。
  3. #1是最简单的实现,如下所示:

    while (1)
    {
        printf("j > ");
        scanf(" %li", &j);
    
        if (0 <= j <= 999)
        {
            break;
        }
    }
    

    #2有点复杂,但它有效地消除了j必须小于1000的任意限制(并更改了限制,以使j必须小于LONG_MAX ):

    // num_cache[0] is the number before the previous number
    // num_cache[1] is the previous number to the current number
    long num_cache[2] = { 0, 0 };
    long current_fib = 1;
    
    for (i = 2; i < j; i++)
    {
        // Push back the numbers
        num_cache[0] = num_cache[1];
        num_cache[1] = current_fib;
    
        // Calculate the new number
        current_fib = (num_cache[0] + num_cache[1]) % 10;
    }
    

    其中一个解决方案应该可以解决您的问题。

答案 1 :(得分:1)

由于输入值检查不充分,似乎发生了分段错误。

  1. 如果程序的输入不是有效数字,则j的调用后scanf()的值将保持不变。由于此变量未初始化,因此当您尝试访问fib[]数组的第j个元素时,这将导致未定义的行为。

  2. 如果j的值小于零或大于999,则在退出fib[]循环时,您将访问for()的不存在的成员。在继续之前,您的代码应检查j是否有效。

  3. 这是您的代码,通过一些修改来实现这些安全措施,并将“幻数”1000移动到#defined值。

    #include <stdio.h>
    #define FIBONACCI_LIMIT 1000L
    
    int main(){
      long i, j, fib[FIBONACCI_LIMIT];
      fib[0] = 0;
      fib[1] = 1;
      if (scanf("%li", &j) != 1)
      {
        fprintf(stderr, "Invalid input\n");
        return 1;
      }
      if (j<0 || j>=FIBONACCI_LIMIT)
      {
        fprintf(stderr, "Number must be in range 0 <= n < %li\n", FIBONACCI_LIMIT);
        return 2;
      }
      for(i=2; i!=1000; i++)
      {
        fib[i] = (fib[i-2] + fib[i-1])%10;
      }
      printf("%li\n", fib[j]);
      return 0;
    }
    

    可以通过完全删除fib[]数组来改进代码,因为当您只需要计算一个值时,不需要存储1000个值。此外,Fibonacci序列中数字的最后数字形成60个值的重复模式,因此您的第一步应该是用j替换j % 60。以下是代码的改进版本,可以使用任何能够适合long整数的非负输入:

    #include <stdio.h>
    
    int main() {
      long i, j, t, f0=0, f1=1;
      if (scanf("%li", &j) != 1)
      {
        fprintf(stderr, "Invalid input\n");
        return 1;
      }
      if (j < 0)
      {
        fprintf(stderr, "Number must be non-negative\n");
        return 2;
      }
      j %= 60;
      for (i=0; i<j; i++)
      {
        t = f0;
        f0 = f1;
        f1 = (f1 + t) % 10;
      }
      printf("%li\n", f0);
      return 0;
    }
    

答案 2 :(得分:0)

您没有显示输入变量j的值。

考虑到下一个Fibonacci数在循环中计算错误。

如果要使用整数类型unsigned long long,则此类型的对象只能容纳93个Fibonacci数。

程序看起来像

#include <stdio.h>

#define N   100

int main(void) 
{
    while ( 1 )
    {
        unsigned long long fib[N] = { 0, 1 };

        unsigned int n;

        printf( "Enter a sequantial number of a fibonacci number (0 - exit): " );
        if ( scanf("%u", &n) != 1 || n == 0 ) break;

        unsigned int i = 2;
        for (; i < N && i <= n && fib[i-1] <= fib[i-2] + fib[i-1]; i++)
        {
            fib[i] = fib[i - 2] + fib[i - 1];
        }

        if (n < i)
        {
            printf("#%u: %llu %llu\n", n, fib[n], fib[n] % 10);
        }
        else
        {
            puts("Too big fibonacci number");
        }
    }

    return 0;
}

它的输出可能看起来像

Enter a sequantial number of a fibonacci number (0 - exit): 1
#1: 1 1
Enter a sequantial number of a fibonacci number (0 - exit): 2
#2: 1 1
Enter a sequantial number of a fibonacci number (0 - exit): 3
#3: 2 2
Enter a sequantial number of a fibonacci number (0 - exit): 93
#93: 12200160415121876738 8
Enter a sequantial number of a fibonacci number (0 - exit): 94
Too big fibonacci number
Enter a sequantial number of a fibonacci number (0 - exit): 0