c++ 为什么我在使用带散列字符串的switch case语句时会遇到分段错误?[已关闭]

gg58donl  于 2022-12-24  发布在  其他
关注(0)|答案(1)|浏览(132)

**已关闭。**此问题需要debugging details。当前不接受答案。

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将有助于其他人回答问题。
昨天关门了。
Improve this question
我正在尝试创建一个CLI(命令行界面)。我目前还不清楚我想从中得到什么。

注意:当我使用带hash-string的switch-case语句运行命令时,错误开始出现。另外,编译时没有错误。错误可能从任何地方开始,因为我已使用printf在运行cli时打印表示argc和argv的消息。

下面是我使用的代码:

代码目录. cpp

#include <map>
#include <iostream>

using namespace std;

static enum Functions {
    undef,
    comm_test,
    comm_commands
} functions;

static map<string, Functions> mapStringValues;

static void Initialize();

bool samestr(const char *svar, const char *str)
{
    if (strcmp(svar, str) == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

string construct_version(int major, int minor, int patch)
{
    string strmajor = to_string(major);
    string strminor = to_string(minor);
    string strpatch = to_string(patch);

    string version = strmajor + "." + strminor + "." + strpatch;

    return version;
}

int test(string command)
{
    int code = system(command.c_str());
    return code;
}

void commands()
{
    printf("(test, commands)\n");
}

int main(int argc, char *argv[])
{
    string doc = "Usage: codeycat [options...] [function] [args...]\n"
                 "Options:\n"
                 "\t--help -h: Show this message and exit\n"
                 "\t--version -v: Show version and exit\n";

    string version = construct_version(1, 0, 0);

    printf("arg count: %d, args: %s %s %s", argc, argv[0], argv[1], argv[2]);

    if (argc < 2)
    {
        printf("%s", doc.c_str());

        return 1;
    }

    const char command[PATH_MAX] = {*argv[2]};

    switch (mapStringValues[command])
    {
    case undef:
        printf("Command not found: %s", command);

    case comm_test:
        test(argv[3]);

    case comm_commands:
        cout << "Hello" << endl;
        // commands();
    }

    return 0;
}

void Initialize()
{
    mapStringValues["undef"] = undef;
    mapStringValues["test"] = comm_test;
    mapStringValues["commands"] = comm_commands;
}

当然,运行% ./codeycat会返回一个返回代码1(错误),但是使用--help--version-h-v选项运行% ./codeycat或者运行它的函数是无效的。
以下是输出:
一个一个二个一个x一个二个一个x一个三个一个x一个四个一个x一个x一个x一个x一个x一个x一个x一个x一个

6ie5vjzr

6ie5vjzr1#

如果不首先检查argc,就不能读取argv。argv是一个长度为argc的数组,所以任何大于或等于argc的索引都是越界的。

printf("arg count: %d, args: %s %s %s", argc, argv[0], argv[1], argv[2]);

不会崩溃,因为如果您向%s说明符传递一个null指针,则某些printf实现会打印“(null)”。如果您不传递任何参数,则会提前返回,因为argc为1,并且您打印文档并返回1。
然而,当你传递一个参数时,你不会提前返回,这意味着你到达了这一行

const char command[PATH_MAX] = {*argv[2]};

这会崩溃,因为当argc小于2时,您从argv[2]阅读。如果传递2个CLI参数,此行将不会崩溃。此外,这不会创建字符串,而是创建大小为PATH_MAX的数组,其中元素0是argv[2]的第一个字符。如果要使用argv[2]为mapStringValues创建索引,则需要创建std::string。此外,argv[2]是第二个参数,因此如果希望第一个参数是命令(通常是这种情况),则应从argv[1]读取。

string command = argv[1];

Switch语句的大小写不会自动中断,这意味着在“case undef:“的末尾,您将输入“case comm_test”。

switch (mapStringValues[command])
{
case undef:
    printf("Command not found: %s", command);
    // this will fall through to case comm_test, 
case comm_test:
    test(argv[3]);

case comm_commands:
    cout << "Hello" << endl;
    // commands();
}

即使初始case是undef,也会调用test(argv[3])。您需要添加break语句以防止case失败

switch (mapStringValues[command])
{
case undef:
    printf("Command not found: %s", command);
    // add break to prevent fallthrough
    break;
case comm_test:
    test(argv[3]);
    break;
case comm_commands:
    cout << "Hello" << endl;
    break;
    // commands();
}

最后,您从未调用过Initialize(),因此map始终为空,这意味着每个命令都将导致找不到Map。

相关问题