【问题标题】:This program passed my university's grader (all test cases) but segfaults in my pc该程序通过了我大学的评分器(所有测试用例),但在我的电脑中出现了段错误
【发布时间】:2015-01-14 13:56:38
【问题描述】:

该程序使用限制 (low,up) 在 int 数组 (Kseek) 中进行二进制搜索。请忽略一些看起来很奇怪的指令,我还没有完成所有必须做的事情。

奇怪的是,我的代码在我的大学评分器中完美运行,但在我的电脑中的大型测试用例出现了段错误。我不明白错误在哪里,对于具有 N>4000 个元素的输入,它会崩溃。

我没有使用任何指针或任何内存分配,我认为 scanf 可能会出现段错误并尝试更改某些属性但它仍然崩溃。

gcc 是否有可能在编译过程中有“内存分配边界”,然后当我尝试运行程序时它无法分配我需要的内存大小??

如果你有时间请检查我的代码,可能有一个我无法发现的错误。

提前致谢!

   #include <stdio.h>  


int main()  
{  
    int N, K, up, low, pos, flag=1 ;  
    scanf("%d %d\n", &N, &K);  
    int s[N], f[N], i=0;  
    while( scanf("%d %d\n", &s[i], &f[i]) != EOF)  { i++; }  
    i=0;  
    up=f[0];  
    low=s[0];  
    while(i < N )  
        {  
        if ( f[i] > up) up=f[i];  
        if ( s[i] < low) low=s[i];  
        i++;  
    }  
    int Kseek[up];  
    i=0;  
    while( flag )  
    {  
        pos = ( low + up ) / 2;  
        i=0;  
        Kseek[pos]=0;  
        while ( i < N)  
        {  
            if ( pos >=  f[i] )  
                        {  
                                Kseek[pos]=f[i]-s[i]+1+Kseek[pos];  
                        }  
                        else if ( pos >= s[i] && pos <f[i])  
                        {  
                                Kseek[pos]=pos-s[i]+1+Kseek[pos];  
                        }  
                        i++;  
                }  
        if ( Kseek[pos] == K ) flag=0;  
        else if ( Kseek[pos] > K )  
        {  
            i=0;  
            Kseek[pos-1]=0;  
            while ( i < N)  
                        {  
                             if ( (pos-1) >=  f[i] )  
                             {  
                                     Kseek[pos-1]=f[i]-s[i]+1+Kseek[pos-1];  
                             }  
                             else if ( (pos-1) >= s[i] && (pos-1) <f[i])  
                             {  
                                     Kseek[pos-1]=(pos-1)-s[i]+1+Kseek[pos-1];  
                             }  
                             i++;  
                    }  
            if ( Kseek[pos] > K && Kseek[pos-1] < K) flag=0;  
            else if ( Kseek[pos-1] == K ) {  pos-=1; flag=0; }  
            up = pos - 1;   

        }  
        else if ( Kseek[pos] < K)  
        {  
            i=0;  
            Kseek[pos+1]=0;       
            while ( i < N)  
                        {  
                             if ( (pos+1) >=  f[i] )  
                             {  
                                     Kseek[pos+1]=f[i]-s[i]+1+Kseek[pos+1];  
                             }  
                             else if ( (pos+1) >= s[i] && (pos+1) <f[i])  
                             {  
                                     Kseek[pos+1]=(pos+1)-s[i]+1+Kseek[pos+1];  
                             }  
                             i++;  
                }  
                if ( (Kseek[pos+1] > K && Kseek[pos] < K) || Kseek[pos+1] == K) {  flag=0; pos+=1; }  
            low = pos + 1;  



                }  


    }         
    printf("%d\n", pos);  
    return 0;  

}    

输入文件看起来总是这样。条目从 10 到 50000 不等:

    200 50536
    369 732
    595 644
    460 500
    548 975
    270 546
    662 766
    358 767
    719 929
    284 354
    411 949
    169 210
    488 679
    103 462
    180 188
    364 487
    407 477
    234 586
    23 775
    504 698
    79 906
    ......
    ...

第一行总是 K 和 N,接下来是 s[i], f[i] 用于接下来的 N 行。

【问题讨论】:

  • 我正在使用 gcc。它编译良好,没有警告。
  • 哦,我明白了,这不是 C90 标准功能。
  • 我很难理解这个二分搜索在搜索什么?
  • 它正在搜索数字 K。K == Kseek[pos] 或者 Kseek[pos] > K > Kseek[pos+1]。这个练习叫做巧克力工厂,嗯,在一个工厂里有N个巧克力来源和一个大罐子。您正在寻找罐中正好有 K 升巧克力的那一刻。每个源在时间 si 开始倒巧克力,在时间 fi 停止(均为整数)。我的目标是快速找到那个时间(pos),所以我写的算法是使用复杂度为Θ(nlogn)的二进制搜索。边界是一个源开始倾倒(低)的第一个时刻和最后一个
  • @Anonymous VLA(可变长度数组)功能自 90 年代初就作为扩展提供,并在 c99 中标准化并在 c11 中扩展。

标签: c segmentation-fault


【解决方案1】:

我认为这真的是微不足道的事情。 使用 GCC 和默认选项编译您的代码,然后使用 VC 中的 dumpbin 转储 a.exe 信息:

OPTIONAL HEADER VALUES
             10B magic # (PE32)
            2.23 linker version
            2E00 size of code
            4800 size of initialized data
             200 size of uninitialized data
            1570 entry point (00401570)
            1000 base of code
            4000 base of data
          400000 image base (00400000 to 0041BFFF)
            1000 section alignment
             200 file alignment
            4.00 operating system version
            1.00 image version
            4.00 subsystem version
               0 Win32 version
           1C000 size of image
             400 size of headers
           183F2 checksum
               3 subsystem (Windows CUI)
               0 DLL characteristics
>>        200000 size of stack reserve
>>          1000 size of stack commit
          100000 size of heap reserve
            1000 size of heap commit
               0 loader flags
              10 number of directories

这两个东西不是太小而无法将您的 s[] 和 f[] 放在堆栈上吗? 我建议重新编译: gcc -Wl,--stack, ... Increase Stack Size on Windows (GCC)

我还制作了另一个源代码模块:只需将 VLA 更改为固定大小的模块(足够大) - 不再有堆栈溢出:

         1000000 size of stack reserve
            1000 size of stack commit

好的,我对这个问题的最后更新是确保传入足够的输入数据。当 EOF 在扫描输入所有 f[] 和 s[] 值之前出现时,您可以简单地忽略这种情况。 我的建议是将阅读 while() 改为 for()。

int i=0;  
for (i=0; i<N; i++) 
    scanf("%d %d\n", &s[i], &f[i]);

【讨论】:

  • 非常感谢您的回答!我使用的是 Ubuntu,gcc 标志是否与 Windows 相同?
  • 我不怕,也许这不值得谷歌搜索。
  • 好的,使用 ulimit -s unlimited 我修好了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-03
  • 2021-11-15
  • 2021-12-31
  • 2022-12-21
  • 2023-02-10
相关资源
最近更新 更多