神奇的分段错误?

magical segmentation fault?

我查看了该站点上的其他类似问题,但我仍然看不出我遗漏了什么。 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);
}

您通过覆盖 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*),而不是字符串的长度。

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

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

您需要阅读一些关于 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" (例如)转换为十六进制的任何内容覆盖指针,这不是您的进程拥有的内存位置。事实上,如果您收到分段错误,这通常意味着您试图读取不属于您的内存,而访问冲突通常是试图写入不属于您的内存。

我想你的大部分麻烦都是由于无意中覆盖指针造成的。

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