2015-11-21 81 views
1

所以我认为问题在于获取ref数组中的参考数字作为字符串并将其转换为整数以转换为整数数组结果,并将其复制到页面数组。由于我得到了分段错误11,我正在经历一个数组的界限。不知道如何解决这个问题。C程序给我分段错误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

你正在循环体内再次增加'i ++'*两次*,一次在'for'语句中。如果字符串长度是奇数,那么你会错过控制循环的''\ 0''终止符。 –

+0

没有这不是问题的第二个i ++是那里的参考字符串格式。因为它可以是1 2 3 23,如果我把i ++取出来,它不会看到23它会看到1 2 3 2 3 @WeatherVane –

+0

如果你遇到了分段错误,用Valgrind或Dr. Memory运行它。这两个程序都会告诉你哪行代码非法访问内存。 –

回答

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;任何负值不是EOFmight 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大小的数组?根据the C standard这是未定义的行为。

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

也许你的意思是写这样的事:

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似乎并没有在这里的任何逻辑中使用。如果您需要读取并丢弃stdinint值,则可以使用scanf("%*d");来完成。这是您(很可能)不需要检查返回值的唯一情况。

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

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