C-指针在运行时更改



我有以下文件 test.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LEXER_INC(l) ( (l)->pos++ )
#define isCidstart(c) (isalpha(c) || (c)=='_')
#define isCident(c) (isalnum(c) || (c)=='_')
typedef struct LexerState
{
    const char *fileName;
    const char *sourceText;
    int sourceLength;
    const char *pos;
    const char *end;
    int line;
} LexerState;
typedef enum LexerToken
{
    TokenHalt,
    TokenPush,
    TokenPop,
    TokenEndOfLine,
    TokenEOF,
    TokenNone
} LexerToken;
typedef struct ReservedWord
{
    const char *word;
    LexerToken token;
} ReservedWord;
static ReservedWord reservedWords[] =
{
    {"halt", TokenHalt},
    {"push", TokenPush},
    {"pop", TokenPop}
};
void lexerInit(LexerState *lexer)
{
    lexer->fileName = "test.s";
    lexer->sourceText = "poprnpushrnhaltrn"; // read from file
    lexer->sourceLength = strlen(lexer->sourceText); // 17
    lexer->pos = lexer->sourceText; // pointing to first char of lexer->sourceText
    lexer->end = lexer->sourceText + lexer->sourceLength; // end of lexer->sourceText string, i.e. ''
    lexer->line = 1;
}
LexerToken lexerCheckReservedWord(const char *word)
{
    for (int count = 0; count < (sizeof(reservedWords) / sizeof(ReservedWord)); count++)
    {
        if (!strcmp(word, reservedWords[count].word))
            return reservedWords[count].token;
    }
    return TokenNone;
}
LexerToken lexerGetWord(LexerState *lexer)
{
    const char *startPos = lexer->pos;
    LexerToken token = TokenNone;
    char *word;
    int len;
    do
    {
        LEXER_INC(lexer);
    }
    while (lexer->pos != lexer->end && isCident(*lexer->pos));
    len = lexer->pos - startPos;
    word = malloc(len + 1); /* (len + 1) for '' ending */
    strncpy(word, startPos, len);
    word[len] = '';
    token = lexerCheckReservedWord(word);
    return token;
}
LexerToken lexerGetToken(LexerState *lexer)
{
    char thisChar;
    /* Skip white characters */
    while (lexer->pos != lexer->end && isspace(*lexer->pos))
    {
        if (*lexer->pos == 'n')
        {
            /* New line found */
            lexer->line++;
            LEXER_INC(lexer);
            return TokenEndOfLine;
        }
        LEXER_INC(lexer);
    }
    if (lexer->pos == lexer->end || *lexer->pos == '')
    {
        return TokenEOF;
    }
    thisChar = *lexer->pos;
    if (isCidstart(thisChar))
    {
        return lexerGetWord(lexer);
    }
    return TokenEOF;
}
int main(int argc, const char *argv[])
{
    LexerState *lexer;
    LexerToken token;
    lexer = malloc(sizeof(lexer));
    lexerInit(lexer);
    while ((token = lexerGetToken(lexer)) != TokenEOF)
    {
        printf("token %dn", token);
    }
    return EXIT_SUCCESS;
}

使用gdb调试函数lexerGetWord时,我意识到执行该行word = malloc((len + 1) * sizeof(char));后,lexer->pos指针地址更改为某个数字(在我的情况下0x23):

82              len = lexer->pos - startPos;
(gdb) next
83              word = malloc(len + 1);   // (len + 1) for '' ending
(gdb) print len
$1 = 3
(gdb) print lexer->pos
$2 = 0x60003b1b3 "rnpushrnhaltrn"

在这里lexer->pos从字符串lexer->sourceText"poprnpushrnhaltrn"

获取Word "pop"后指向此地址

(gdb) next
84              strncpy(word, startPos, len);
(gdb) print lexer->pos
$3 = 0x23 <error: Cannot access memory at address 0x23>

但是在执行malloc后,指针更改了地址,稍后在Segmentation fault中产生。

$ gcc test.c -o test
$ ./test
token 2
Segmentation fault (core dumped)

我做错了什么?

编辑

这仅发生在Cygwin GCC。我尝试了mingw和所有工作都很好

$ uname -a
CYGWIN_NT-6.3 Stepan 2.9.0(0.318/5/3) 2017-09-12 10:18 x86_64 Cygwin

问题在main中:

lexer = malloc(sizeof(lexer));

您正在为指针分配足够的空间,而不是指向的。结果,您最终会在分配的内存的末尾编写。这调用了未定义的行为。

您需要lexer指向的空间:

lexer = malloc(sizeof(*lexer));

相关内容

  • 没有找到相关文章

最新更新