【问题标题】:Trouble creating a shell in C (Seg-Fault and ferror)在 C 中创建 shell 时遇到问题(Seg-Fault 和 ferror)
【发布时间】:2012-10-03 20:22:13
【问题描述】:

我一直在学习如何制作自己的外壳的教程,但我已经卡了几天了。

两件事:

  1. 这段代码编译运行时,会随机出现分段错误,我不知道为什么。
  2. if 语句 `if (ferror != 0)` 似乎总是正确的。这很奇怪,因为我不明白为什么 fgets()ma​​in() 函数中失败。

非常感谢有关这些主题(或有关创建此 shell 的其他主题)的任何信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#define MAXSIZE 512

int parseCmd(char *cmd, char *args[])
{
    printf("LOGGER: parseCmd(cmd=%s, args=%p)\n", cmd, args);

    char cmdDelims[] = {' ','>'};

    char *cmdReader;
    cmdReader = strtok(cmd, cmdDelims);

    int i = 0;
    while (cmdReader != NULL)
    {       
        args[i] = strdup(cmdReader);

        printf("LOGGER: args[%d]=%s\n", i, args[i]);

        cmdReader = strtok(NULL, cmdDelims);
        i++;
    }
    return 0;
}

void printToLine(char *args[])
{
    int length;
    length = sizeof(args) / sizeof(char);

    int i = 0;
    while (i < length)
    {
        printf("%s\n", args[i]);
        i++;
    }
}

int main(int argc, char *argv[]) 
{   
    char *in;
    in = malloc(MAXSIZE);

    char *args[15];
    char *cmd = NULL;

    int errorBit = 0;
    int terminationBit = 1;
    char error_message[30] = "An error has occurred\n";

    char inDelims[] = "\n";

    while (terminationBit)
    {
        printf("mysh>");

        // get input from command line
        fgets(in, MAXSIZE, stdin);
        if (ferror != 0)
        {
            perror(error_message);
        }

        // get pointer to command line input w/o the newline
        cmd = strtok(in, inDelims);

        // parse the command into separate arguments
        errorBit = parseCmd(cmd, args);
        if (errorBit)
        {
            perror(error_message);
            exit(1);
        }

        printToLine(args);

        // check if the user wants to exit the shell
        if (strcmp(*args, "exit") == 0)
        {
            terminationBit = 0;
        }
    }
    return 0;
}

以下是一些输出:

**[ray@12] (6)$ mysh**
mysh>1 2 3
An error has occurred
: Success
LOGGER: parseCmd(cmd=1 2 3, args=0x7fff4a50b080)
LOGGER: args[0]=1
LOGGER: args[1]=2
LOGGER: args[2]=3
1
2
3
Segmentation fault (core dumped)
**[ray@12] (7)$ mysh**
mysh>1 2 3 4 5 6 7 8 9 10
An error has occurred
: Success
LOGGER: parseCmd(cmd=1 2 3 4 5 6 7 8 9 10, args=0x7fffba053d70)
LOGGER: args[0]=1
LOGGER: args[1]=2
LOGGER: args[2]=3
LOGGER: args[3]=4
LOGGER: args[4]=5
LOGGER: args[5]=6
LOGGER: args[6]=7
LOGGER: args[7]=8
LOGGER: args[8]=9
LOGGER: args[9]=10
1
2
3
4
5
6
7
8
mysh>1 2 3
An error has occurred
: Success
LOGGER: parseCmd(cmd=1 2 3, args=0x7fffba053d70)
LOGGER: args[0]=1
LOGGER: args[1]=2
LOGGER: args[2]=3
1
2
3
4
5
6
7
8

【问题讨论】:

  • 为什么不检查fgets的返回值呢?您无法通过检查 ferror(stdin) 来检测 EOF。
  • 仔细观察后,我假设我需要在重用它之前释放我的 args 变量。我不明白为什么我在解析只有 3 个元素的数组时会出现段错误。
  • 查看我的更新答案

标签: c segmentation-fault fgets ferror


【解决方案1】:

对于ferror 错误,您需要测试ferror(stdin),而不是ferror。后者是函数地址,永远不会为零:

if (ferror(stdin) != 0)
{
    perror(error_message);
}

对于至少某些段错误,这并没有按照您的想法进行:

length = sizeof(args) / sizeof(char);

这将告诉您用于存储指针的字节数,取决于 4 或 8,而 不是参数的数量。

因此,如果您有四个(或八个)参数,它将看起来起作用。如果你有更多,它似乎会忽略一些论点。如果你有更少,它会从整个 Void 中获取缺失的参数,从而导致(几乎可以肯定)分段错误。

您需要独立计算length 并将其传递,或者在args 中存储一些终止符,例如在您找到的最后一个有效参数之后添加一个NULL 参数:

        cmdReader = strtok(NULL, cmdDelims);
        i++;
    }
    args[i] = NULL;
    return 0;
}

void printToLine(char *args[])
{
    int i = 0;
    while (args[i])
    {
        printf("%s\n", args[i]);
        i++;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多