处理argv时出现分段错误

时间:2013-04-20 14:49:15

标签: c segmentation-fault

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

  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,","));   
    }

以下是调用它的程序片段:

#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

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

2 个答案:

答案 0 :(得分:3)

您可以将代码缩减到此SSCCE(Short, Self-Contained, Correct Example),当您遗漏#include <string.h>时,该代码会很好地崩溃,并且在您添加#include <string.h>时无法完全编译:

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 *

答案 1 :(得分:1)

我试图编译你的代码,编译器警告我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 *,并检查传递给程序的输入,可能是不正确的,这可能是问题所在。