尝试将字符串分配给结构内的字符串变量时出错

Error when trying to assign a string into a string variable inside a struct

我正在编写词法分析器软件,但是当我尝试将字符串分配给结构内的字符串变量时遇到问题。

--common.h--
#define TEST printf("--TEST--\n")

struct Token {
    char* ID;
    char* string;          // String variable
};

struct Token* tokenizer(char* input);

void PrintToken(struct Token* token);

--lexer.c--
#include <stdio.h>
#include <string.h>
#include "common.h"

struct Token* tokenizer(char* input)
{
    struct Token* token;

    int toknum = 0;

    int i = -1;

    while (1) {
        char* string;

        for (i += 1; input[i] != ' '; i++) {
            string[i] = input[i];
        }

        strcpy(token[toknum].string, string);       // The problem is here.

        if (input[i] == '\n' || input[i] == '[=10=]')
            break;        

        toknum++;
    }

    return token;
}

void PrintToken(struct Token* token)
{
    for (int i = 0; i < 5; i++) {
        printf("%s\n", token[i].string);
    }
}

--main.c--
#include <stdio.h>
#include "common.h"

int main()
{
    char* input = "Hello there";

    struct Token* token = tokenizer(input);

    PrintToken(token);

    return 0;
}

在我用 gcc main.c lexer.c -o final.o 和 运行 final.o 编译上面的程序后,我得到一个错误,它说:

Segmentation fault

我试过用token[toknum].string = string;替换strcpy(token[toknum].string, string);,但结果是一样的。

有什么办法可以避免这个错误吗?

您正在使用未初始化的变量:

struct Token* token;

这只定义了一个指针变量,没有赋值任何有效内容。这意味着 indetermioned 中的内容和读取此变量的内容会导致未定义的行为。

此外,此变量未指向有效地址。通过 strcpy 写入“随机”地址也会导致未定义的行为。

您必须为此分配动态内存:

struct Token *token = malloc(sizeof(*token));
// don't forget error handling

然后当你想要更多条目时,扩大内存:

struct Token *temp = realloc(token, (toknum+1)*sizeof (*token));
if (NULL != temp) 
  token = temp;
else
// error handling

只需使用这样的数组:

struct Token token[x];

会保留内存,但您不能 return 函数末尾的地址,因为该对象的生命周期将同时结束,您可能无法在 returning 之后访问它。


同样的问题出现在string:

   char* string;

   for (i += 1; input[i] != ' '; i++) {
        string[i] = input[i];  // <<< string is uninitialized, does not point to valid memory.
   }

您没有为字符串提供任何内存。 在这里您可以使用本地数组来保存字符串。


同样的问题也出现在 token[toknum].string

您的结构仅包含指针。同样,您需要保留内存。 要么再次使用动态内存分配,要么使 token.string 成为固定长度的数组。

如果 token[toknum]string 都有效,那么您使用 token[toknum].string = string; 的尝试将有效。


同篇还有一个问题:

    for (i += 1; input[i] != ' '; i++) {
        string[i] = input[i];
    }

    strcpy(token[toknum].string, string); // << strcpy expects a nul-terminated string

你没有正确终止你的字符串。在这种情况下,strcpy 将愉快地遍历您的内存,超出内存分配的边界,直到意外找到终止 [=24=] 字节。


并且...如果 input 不包含另一个 space 字符会怎样?这个循环最终会到达 input 的终止 0 并继续...

还有两个原因等着你。


这只是我在 tokenizer 中第一眼看到的内容。

在函数 PrintToken 中,您还有另一个问题: 是什么让你想到,你可以打印 token 的 5 个元素?您永远不会为 5 个元素保留内存,即使您这样做了,您也不会将多余的元素初始化为包含一些空字符串。