【问题标题】:Segmentation fault when accessing memory location after allocating memory with malloc()使用 malloc() 分配内存后访问内存位置时出现分段错误
【发布时间】:2018-05-15 01:09:57
【问题描述】:

我目前正在使用 C++ 创建一个小型编译器。我定义了以下对象:

struct ValueNode
{
    std::string name;
    int value;
};

struct StatementNode
{
    StatementType type;

    union
    {
        struct AssignmentStatement * assign_stmt;
        struct PrintStatement * print_stmt;
        struct IfStatement * if_stmt;
        struct GotoStatement * goto_stmt;
    };

    struct StatementNode * next; // next statement in the list or NULL
};

我已经定义了一系列与语言中不同类型的语句相关的函数。这些函数之一称为 parse_assignment_stmt()。我遇到的分段错误发生在此函数中,在尝试为最近分配的内存分配值后立即发生。这是那个函数:

struct StatementNode* parse_assign_stmt() {

    //Object to be returned. Holds an object representing a statement
    //made within the input program.
    struct StatementNode* st = (struct StatementNode*)malloc(sizeof(struct StatementNode));

    st->type = ASSIGN_STMT;

    //First token should be an ID. Represents memory location we are assigning to.
    Token tok = lexer->GetToken(); 

    if(tok.token_type == ID) {

        //Second token in an assignment should be an equal sign
        Token tok2 = lexer->GetToken();

        if (tok2.token_type == EQUAL) {

            //This function reads the next token, makes sure it is of type NUM or ID, then creates and returns a ValueNode containing the relevant value.
            struct ValueNode* rhs1 = parse_primary();

            Token tok3 = lexer->GetToken();

            //Assignment format for this logical branch: "x = 5;"
            if(tok3.token_type == SEMICOLON) {
                //first type

                //Allocate memory for objects needed to build StatementNode st
                struct AssignmentStatement* assign_stmt = (struct AssignmentStatement*)malloc(sizeof(struct AssignmentStatement));

                struct ValueNode* lhs = (struct ValueNode*)malloc( sizeof(struct ValueNode));

                printf("Name: %s, Value: %d\n", lhs->name.c_str(), lhs->value);


                //PROBLEM ARISES HERE***
                //lhs->name = tok.lexeme;               

                //return the proper structure
                return st;
            }
            else if(tok3.token_type == PLUS || tok3.token_type == MINUS || tok3.token_type == DIV || tok3.token_type == MULT) {
                //second type

                //TODO
            }
            else {
                printf("Syntax error. Semicolon or operator expected after first primary on RHS of assignment.");
                exit(1);
            }
        }
        else {
            //not of proper form
            printf("Syntax error. EQUAL expected after LHS of assignment.");

            exit(1);
        }
    }
    else {
        //Not of proper form. Syntax error
        printf("Syntax error. ID expected at beginning of assignment.");

        exit(1);
    }
}

本质上,我正在为新的 ValueNode 分配内存以创建变量 lhs。我立即打印出名称和值字段,以确保不存在任何内容。在我的编译器输出中(顺便说一下,我使用的是 g++),它告诉我名称为 (null),值为 0,这是预期的。一旦我取消注释该行

lhs->name = tok.lexeme;

我遇到了分段错误。在这一点上,我不知道出了什么问题。我正在创建变量,使用 malloc 为该位置分配内存,确保那里没有存储任何东西,然后立即尝试写入一个值。它总是给我一个分段错误。

这是通过标准输入输入程序的输入程序(.txt 文件)。

i;
{
    i = 42 ; 
    print i;
}

我尝试使用 calloc() 代替,因为这应该确保在返回指针之前清除内存,但这并没有改变任何东西。任何建议都会很棒。谢谢!

【问题讨论】:

  • 不要在 c++ 代码中使用malloc()
  • 您可能需要考虑用适当的继承层次结构替换联合的struct。那么你就不会被认为是一个 C+ 程序员,那种从未完全从 C 过渡到 C++ 的奇怪品种 :-)
  • This question 还为您提供了一些提示,在 c++ 中的大多数情况下,如何以及为什么要完全放弃 手动动态内存分配

标签: c++ pointers memory memory-management


【解决方案1】:

如果线路出现问题:

lhs->name = tok.lexeme; 

那么我保证问题出在lhstok.lexeme

在此之前,您似乎已经确认 lhs 可以:

printf("Name: %s, Value: %d\n", lhs->name.c_str(), lhs->value);

那么代币结构出现问题的可能性就会飙升。

但是,我们不需要推测,您应该能够将代码加载到一个好的调试器中(或者甚至gdb,在紧要关头(a)),设置一个断点在违规行,实际上查看变量以查看它们是否符合预期。或者,至少在尝试使用之前打印出更多内容。


除此之外:我一直对在大学教授的第一门课程不是调试 101 感到困惑。这是我儿子一开始就教他的第一课做 Python 开发。


(a) Pax 鸭子作为掩护 :-)

【讨论】:

  • 旁白^2:我猜取决于大学。他们在 malloc 和 free 之后向我们展示的第一件事是 valgrind。在那之前他们也向我们展示了 gdb,但是对于大多数人来说那太可怕了
  • 嗨,帕克斯。我也希望在我的程序中调试是一个更全面的主题。我很欣赏使用断点的建议。为了更好地了解调试,您是否建议我阅读任何特定资源?
  • 嘿,Pax,我通过 gdb 运行程序,发现了一些新信息!我直接在这一行之前添加了一个断点:lhs->name = tok.lexeme;在那个时间点,两个有问题的结构似乎是 rhs1 和 lhs。在 gdb 中运行“p *rhs1”时,我得到: {name = , value = 42} 我得到的东西与“p *lhs”几乎相同,但内存地址不同不可访问,值为 0。这两个值都符合预期,但由于某种原因,两个名称的内存都无法读取。有什么想法吗?
  • 不知道lhs,因为你没有给出指针值,但是0xfff...fe8 (-24) not 看起来像一个有效的指针给我.建议您检查parse_primary() 以查看它是否/为什么返回它。但至少你在重新调试的路上很好:-)
【解决方案2】:

经过进一步调查,我发现在为我的 ValueNode 对象(由于某种原因,只有这些对象)分配内存(使用 malloc())时,malloc() 正在返回一个指向不可访问内存的指针。尝试打印我的 ValueNode 结构时,我在 gdb 中收到的错误是:

{name = 的内存,值 = 42}

不幸的是,我无法找到使用 malloc() 为该对象分配内存的方法。然而,我设法实现的一种解决方法是在 ValueNode 的结构定义中创建一个构造函数,然后使用“new”来创建对象并为我分配内存,而不是试图强制 malloc() 工作。回想起来,我可能应该从 malloc() 开始使用这种更简单的方法。

【讨论】:

  • 如果你出于某种原因需要在 C++ 中使用 malloc,谷歌“placement new”,它允许你在已经分配的内存上创建对象。
猜你喜欢
  • 2016-09-27
  • 2014-07-17
  • 2018-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多