【问题标题】:Segmentation fault while processing argv处理 argv 时出现分段错误
【发布时间】:2013-04-20 14:49:15
【问题描述】:

此过程应将包含一组用逗号分隔的双精度数(例如 7.2、9.5、-5.515)的字符串转换为双精度类型的向量。

  void ToDoubleVec(int d,const char* commaSeparated,double *result)
    {
        int i;      
        result[0]=atof(strtok(commaSeparated,","));
        for(i=1;i<d;i++)
            result[i]=atof(strtok(NULL,","));   
    }

这是调用它的程序的sn-p:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc,char** argv)
    {
    ...
        int i,dim=atoi(argv[1]);
        double *lower;
        lower = malloc(dim*sizeof(double));
        ToDoubleVec(dim,argv[2],lower);
    ...
    }

调试器的输出:

40      lower = malloc(dim*sizeof(double)); 
(gdb) s
42      ToDoubleVec(dim,argv[2],lower);
(gdb) s
ToDoubleVec (d=2, commaSeparated=0x7fffffffe9d3 "2.3,-62.1", result=0x603010) at testPSO.c:11
11      result[0]=atof(strtok(commaSeparated,","));
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff77f56bb in ?? () from /lib/x86_64-linux-gnu/libc.so.6

为什么它不起作用?我确信我已经为数组分配了足够的内存,而且参数似乎也被正确传递了。

【问题讨论】:

  • @JohnKugelman 是的,看看调试器的输出:ToDoubleVec (d=2, commaSeparated=0x7ffffffffe9d3 "2.3,-62.1", result=0x603010)
  • commaSeparated 应该声明为 char * 而不是 const char * 因为 strtok() 修改了它。你没有收到警告吗?
  • 勇敢的人将strtok() 的结果传递给atof() 而不检查空指针...当strtok() 返回null 时,我希望看到崩溃。
  • @JonathanLeffler 但如果您查看他传递给ToDoubleVec 的论点,我认为这不是他面临的问题。
  • 出于调试目的,您最好将崩溃行更改为三行,这样您就可以将错误分配给所涉及的三个函数调用/分配之一。

标签: c segmentation-fault


【解决方案1】:

您可以将您的代码缩减为这个 SSCCE (Short, Self-Contained, Correct Example),当您忽略 #include &lt;string.h&gt; 时它会很好地崩溃,而当您添加 #include &lt;string.h&gt; 时它不会干净地编译:

segv.c: In function ‘ToDoubleVec’:
segv.c:8:5: warning: implicit declaration of function ‘strtok’ [-Wimplicit-function-declaration]
segv.c:8:20: warning: initialization makes pointer from integer without a cast [enabled by default]
segv.c:14:20: warning: assignment makes pointer from integer without a cast [enabled by default]

代码:

#include <stdlib.h>
//#include <string.h>

static void ToDoubleVec(int d, const char* commaSeparated, double *result)
{
    int i;      
    result[0] = atof(strtok(commaSeparated, ","));
    for (i = 1; i < d; i++)
        result[i] = atof(strtok(NULL, ","));   
}

int main(void)
{
    int dim = 2;
    double *lower = malloc(dim*sizeof(double));
    char arg[] = "7.2,9.5,-5.515";
    ToDoubleVec(dim, arg, lower);
}

将返回值从诸如strtok()之类的函数传递给一个函数,例如atof(),它可以直接返回一个空指针,而不是容忍空指针是鲁莽的;它会导致崩溃。如果一切都是正确的,你会没事的;否则,你会崩溃和燃烧。

未经检查的内存分配是一个类似的问题;在原始内存分配之前,您甚至没有检查 dim 是否非零(且非负)。

#include <assert.h>
#include <string.h>
#include <stdlib.h>

static void ToDoubleVec(int d, char *commaSeparated, double *result)
{
    int i;      
    char *number = strtok(commaSeparated, ",");
    if (number != 0)
    {
        result[0] = atof(number);
        for (i = 1; i < d; i++)
        {
            number = strtok(NULL, ",");
            if (number != 0)
                result[i] = atof(number);
        }
    }
}

int main(void)
{
    int dim = 2;
    double *lower = malloc(dim*sizeof(double));
    char arg[] = "7.2,9.5,-5.515";
    assert(lower != 0);
    ToDoubleVec(dim, arg, lower);
}

如果number 上的测试失败,您可以(并且在我所做的代码的一个版本中)添加错误打印以报告。但是崩溃是由 strtok() 隐式声明为返回 int 而不是 char * 引起的。

【讨论】:

    【解决方案2】:

    我尝试编译您的代码,编译器警告我 strtok() 将 char* 而不是 const char* 作为输入。然后我尝试了这段代码,它工作正常:

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    void ToDoubleVec(int d, char* commaSeparated,double *result);
    
    
    int main(int argc,char** argv)
    {
        int i,dim=atoi(argv[1]);
        double *lower;
        lower = malloc(dim*sizeof(double));
        ToDoubleVec(dim,argv[2],lower);
        for (i=0; i<dim; ++i) {
            printf("%f\n", lower[i]);
        }
        return 0;
    }
    
    void ToDoubleVec(int d, char* commaSeparated,double *result)
    {
        int i;
        result[0]=atof(strtok(commaSeparated,","));
        for(i=1;i<d;i++)
            result[i]=atof(strtok(NULL,","));
    }
    

    因此尝试将 const char* 更改为 char*,并检查您传递给程序的输入,也许它不正确,这可能是问题所在。

    【讨论】:

      猜你喜欢
      • 2020-06-15
      • 2020-12-08
      • 1970-01-01
      • 2012-05-11
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 2022-06-15
      • 2020-12-12
      相关资源
      最近更新 更多