【问题标题】:magical segmentation fault?神奇的分段错误?
【发布时间】:2015-02-05 00:51:08
【问题描述】:

我查看了网站上的其他类似问题,但我仍然没有看到我缺少什么。 C 对我来说是一个新的和可怕的野兽,所以我确信它很简单,但是当代码到达 while 循环内的 fgets(); 行时,我遇到了分段错误(核心转储)。

我尝试直接将字符串写入currentInput,但仍然得到它,所以我认为我以某种方式访问​​了错误的字符串?

我的理解是分段错误是由访问(程序?)无权访问的内存引起的......

顺便说一句,有没有办法在 strcmp(); 中使用字符串文字?所以我可以与“END”进行比较?

void runCommands()
{
    char * currentInput = (char*)malloc(100); //100 char input buffer
    char * cmd = (char*) malloc(CMD_LENGTH);
    char * target = (char*) malloc(UID_LENGTH);
    char * key = (char*) malloc(KEY_LENGTH);
    char * endstr = "END";
    cmd = "UNDEF";
    target = "UNDEF";
    key = "UNDEF";
    ushort tokens;

    while (strcmp(cmd, endstr) != 0) //Run until command is "END"
    {
        printf("ENTER INSTRUCTION: ");
        fgets(currentInput, sizeof(currentInput), stdin); //FAULT OCCURS HERE
        tokens = sscanf(currentInput, "%[^,\n],%[^,\n],%s", cmd, target, key); //parse string for values
        if (tokens <= 3 && tokens >= 1) //ensure valid # of tokens passed
        {
            fprintf(stdout, "TOKENS:\nCMD: %s\ntarget: %s\nkey: %s\n", cmd, target, key);
            switch (tokens)
            //restore UNDEF for non-existent tokens
            {
            case 1:
                target = "UNDEF";
                /* no break */
            case 2: //intentional fallthrough
                key = "UNDEF";
                break;
            default:
                break;
            }
            /* handle commands */
            if (strcmp(cmd, endstr) == 0)
            {
                end(keyfile);
            } //write file and exit function
            else if (strcmp(cmd, "DELETE") == 0)
            {
                delete(target, key);
            } //delete specified key from UID
            else if (strcmp(cmd, "VALIDATE") == 0)
            {
                validate(target, key);
            } //valid/not valid based on key presence
            else if (strcmp(cmd, "ADD") == 0)
            {
                add(target, key);
            } //add key to target UID
            else if (strcmp(cmd, "PRINT") == 0)
            {
                print(target);
            } //print sorted keys for UID or all keys for ALL
            else
            {
                invalidCMD(cmd);
            } //error message for invalid command
        }
        else
        {
            invalidCMD(currentInput); //use whole input as bad command if invalid format
        }
    }
    free(currentInput);
    free(target);
    free(key);
    free(cmd);
}

【问题讨论】:

  • “旁白”:是的,你可以写strcmp(cmd, "END")
  • 您错误地使用了sizeof
  • 发布一个显示问题的完整程序,see here 发布指南
  • 另外,如果这些数组仅供本地使用,我怀疑,不要malloc() 他们就像你在做Java一样。只需char currentInput[100];

标签: c segmentation-fault


【解决方案1】:

您正在通过覆盖 malloc 返回的指针值导致内存泄漏以及未定义的行为:

char * currentInput = (char*)malloc(100); //100 char input buffer
char * cmd = (char*) malloc(CMD_LENGTH);
char * target = (char*) malloc(UID_LENGTH);
char * key = (char*) malloc(KEY_LENGTH);
//...
// This is where you cause the issue
char * endstr = "END";
cmd = "UNDEF";
target = "UNDEF";
key = "UNDEF";

由于您切断了代码,我无法评论您的其余代码以确定还有什么会导致问题。

有一件事是您肯定没有正确使用sizeof(),因为sizeof(currentInput) 等于sizeof(char*),而不是字符串的长度。

【讨论】:

  • 哦...我需要使用 strcpy() 来赋值对吗?
  • 是的,或者编写一个循环,或者其他将数组中的每个字符分配给一个值的东西。您不会覆盖指针值。随后对这些指针中的任何一个调用 free 也会导致未定义的行为。
  • @DanielBall:不,你可以像char * endstr = "END";一样直接赋值,但是这种情况下不要调用malloc(),因为你没有使用返回的内存。
  • 好的,但是如果我执行 char * endstr = "END",它只会分配 3 个正确的字符,所以如果我需要存储更长的时间,我需要重新分配指针吗?
  • @DanielBall 您必须定义一个字符缓冲区,无论它是char 的数组(不是字符串文字),还是使用malloc 或类似函数动态获取内存。然后您可以将字符写入缓冲区,更改缓冲区中的字符等。写入字符的一种方法是使用strcpy,或者只是使用[ ] 一次更改一个字符。
【解决方案2】:

当您编写cmd = "UNDEF" 时,您将指针(即cmd)设置为字符数组的位置。如果你想分配字符串(而不是指向它们的指针),你应该使用strcpy

C 编译器将自动为字符串常量分配空间,但是,它不允许重写它们,您可能正在尝试在您省略的代码部分中这样做。

【讨论】:

    【解决方案3】:

    您需要阅读一些关于 C 类型和指针的内容.. :) 考虑以下更改:

    #define CMD_LENGTH 100
    #define UID_LENGTH 100
    #define KEY_LENGTH 100    
    void runCommands()
        {
            char * currentInput = (char*)malloc(100); //100 char input buffer
            char * cmd = (char*) malloc(CMD_LENGTH);
            char * target = (char*) malloc(UID_LENGTH);
            char * key = (char*) malloc(KEY_LENGTH);
            char * endstr = (char *)malloc(sizeof(char) * 100);
            ushort tokens;
    
            strcpy(cmd, "UNDEF");
            strcpy(target, "UNDEF");
            strcpy(key, "UNDEF");
    
        while (strcmp(cmd, endstr) != 0) //Run until command is "END"
        {
            printf("ENTER INSTRUCTION: ");
            fgets(currentInput, sizeof(currentInput), stdin);
    

    您不能以这种方式使用简单的赋值将值放入指针中。这样做会有效地用任何“END”(例如)转换为十六进制的指针覆盖指针,这不是您的进程拥有的内存位置。事实上,如果您收到分段错误,通常意味着您尝试读取不属于您的内存,而访问冲突通常是尝试写入不属于您的内存。

    我认为您的大部分问题是由无意中覆盖指针造成的。

    使用“幻数”也是非常糟糕的做法......(例如,神奇地分配 100 个字节。你怎么知道它是 100?它总是 100?)你还应该验证 malloc 实际上返回了一个价值,而不是假设它确实如此。还说明了调用 Malloc 的更典型的方式,尽管我没有验证返回。最后, fgets 非常危险,因为它是无限读取。您更喜欢使用允许您指定要读取的最大大小的函数,以避免堆或堆栈上的溢出情况(取决于它是局部变量、全局变量还是指向堆的指针)。

    【讨论】:

    • char * endstr = "END";是完全有效的,它将 endstr 设置为指向常量“END”,它不是程序员想要的,而是完全有效的代码。他的意思是strcpy(正如你所说)
    • 我知道它总是小于 100。它实际上应该小于 .. 我想我已经计算了 57。我很想学习关于 c 的一切,但现在我已经当我 3 年没有写过 C++ 并且只有 java 和程序集之间的时候,用不到两天的时间基本上学习了 c 和 c++ 的所有区别。 无论如何 1) char[] 需要足够大以包含可能写入它的最大字符串(加上 \0)对吗? 2)fgets() 参数 2 是要读取的最大字符数
    • 你还在错误地使用sizeof,不要投malloc
    • 我还没有人说为什么你不使用malloc。而且我认为我看到了 sizeof 的问题......它应该是 sizeof(array)/sizeof(element) 来获取元素的数量,对吧?
    • 投它没有错,但没必要。 Malloc 返回一个 void *,它可以分配给任何东西。但是,调用中使用的 sizeof() 很重要,因为不能保证类型的大小,除非整数至少与 char 一样大并且可能更大,long 至少与 int 一样大并且可能更长等。
    猜你喜欢
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多