C程序给我分段错误11

时间:2015-11-21 18:46:53

标签: c arrays

所以我认为问题在于将ref数组中的引用号作为字符串并将其转换为整数以转换为复制到页数组的整数数组结果。因为我得到了一个分段错误11我正在越过一个数组的边界。只是不知道如何解决这个问题。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


int main()
{

  char ref[30];// array that holds reference string
  int frame_size;// maximum number of frames is 8
  // a frame holds a number thats in the reference stream.  
  int optimal_fault =0;
  int lru_fault =0;// least recently used faults
  int mfu_fault =0;// most frequently used faults
  int lfu_fault =0;// least frequently used faults    
  int pages = 0;//counts how many times you've looped
  //int page=0;//this will be the pages array 
  printf(" Please enter reference string: ");


  fgets(ref, 30, stdin);
  int num;

  //printf("reference: %c", &ref);
  printf(" Please enter the number of frames(no more than 8 allowed)\n");

  scanf("%d",&frame_size);

  int len = strlen(ref);
  int results[len];
  int page[len];
  int k=0;


  printf("len: %d:",len);
  for(int i=0; ref[i]!= '\0'; i++)
  { 
    if(isdigit(ref[i]))
    {
      num = sscanf(&ref[i], "%d", &results[i]);
      printf("results: %d\n", results[i]);
      page[k] = results[i];
      printf("page: %d\n", page[k]);
      k++;
      i++;
    }

  }
  return 0;
 }

1 个答案:

答案 0 :(得分:1)

我很乐意解决您的计划遇到的问题,但您需要保持开放的心态并愿意尝试解决我提出的问题。我会找出错误。你做了明显的改变,并测试它。我几乎可以肯定你的错误会在这个过程中消失。如果他们不这样做,请使用您所做的更改发布问题的更新并ping我,我们将从那里开始工作......

首先,让我们考虑在提供类似"0"

的字符串时如何执行此操作

预计i会为此字符串递增一次,因为其中只有一个字符,因此循环如下所示:for(int i=0; ref[i]!= '\0'; i++) ...没有理由相信此代码此时会多次增加i,对吗?

但是,您的代码在此处再次递增:

if(isdigit(ref[i]))
{
  /* SNIP */
  i++;    // <--- ERROR HERE!
}

您的代码会跳过字符串终止'\0'字节,因为它会递增太多次。它跳出数组的末尾,调用未定义的行为。期望这可能导致段错误是现实的,但是因为UB没有要求。

isdigit期望其参数为unsigned charEOF ;任何不是EOF might cause assertion errors的负值。也许你打算写:if(isdigit((unsigned char)ref[i]))

int len = strlen(ref);
int results[len];
int page[len];

首先,strlen会返回size_t。如果源值位于目标类型的范围之外,则从无符号整数类型到有符号整数类型的转换将导致实现定义的行为。实现定义的行为可能(理论上)包括陷阱表示,这可能会引发陷阱(即段错误)。

此外,您是否考虑过当len为0时(例如,您有一个空字符串),您是否声明0大小的数组?根据{{​​3}},这是未定义的行为。

  

...每次评估时,其值应大于零。

也许你打算写这样的东西:

size_t len = strlen(ref);
if (len == 0) {
    puts("ref is too small! This field must be at least one byte...");
    return 0;
}
int results[len];
int page[len];
printf("len: %zu:",len); // NOTE: %zu causes printf to print a size_t; don't use %d for that.

考虑将size_t用于表示大小的其他变量,例如ik,因为int可能会转换为负值(这是未定义的结果)行为,所以在技术上它可能会崩溃或更糟,相反)。您不希望results[i] i为负数,是吗? (不是ref可能有那么多字节,在这段代码中)

int main()不被视为标准C中的有效入口点。您应该使用int main(void),它指定主入口点不带参数,与您不同已经使用过,它指定主入口点采用未指定数量的未指定类型的参数。此错误偶尔会导致段错误,可以通过编译这两个程序来证明:

int main() {
    main(42, "hello", -1.0); // WHAT?! main() can accept three arguments?!
}

int main(void) {
    main(42, "hello", -1.0); // Note the compiler error...
}

同样,这是UB所以没有要求......不幸的是我在搜索的十分钟内找不到任何链接,但是我确定我已经看到了这个导致程序终止时出现段错误的实例

您应该(几乎)始终检查scanf的返回值。 scanf("%d",&frame_size);无法保证成功,因此无法保证frame_size将包含一个理智的价值。话虽如此,frame_size似乎没有在任何逻辑中使用。如果您需要阅读并放弃int中的stdin值,则可以使用scanf("%*d");执行此操作。这是您(最有可能)不需要检查返回值的唯一情况。

这也适用于sscanf我注意到您在此处保存了sscanf的返回值:num = sscanf(&ref[i], "%d", &results[i]); ...但是,你呢我没有做任何事情!因此,您无法保证results[i]包含合理的值。这样的耻辱......

num = sscanf(&ref[i], "%d", &results[i]);
if (num != 1) {
    continue;
}