1

我使用 C 编写自己的 shell 并处理流重定向(">" 和 "<") 我使用 strtok() 来获取它们并存储相关信息以供稍后在程序中使用。我不确定为什么在第一次调用时会出现分段错误。(目前代码非常混乱)。

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>

int main (){
    char *command, *mypath, *buffer, *arglist[1024], *pathlist[1024],
        **ap, *carrotfile1, *carrotfile2;
    char* tokenPtr = malloc(1024);
    buffer = malloc(1024);
    carrotfile1 = malloc(1024);
    carrotfile2 = malloc(1024);
    int loop = 1, code = 0, fail = 0;

    while (loop == 1){
        int argnum = 0, pathnum = 0;
        mypath = malloc(1024);
        if(getenv("MYPATH") == NULL)
            strcpy(mypath, "/bin#.");
        else
            strcpy(mypath, getenv("MYPATH"));
        printf("myshell$ ");
        command = readline("");

        if(strcmp(command, "exit") == 0 || strcmp(command, "quit") == 0)
            return 0;

        if(strcmp(command, "") == 0)
            continue;

        /*Tokenizes Command*/
        /*
          Code 1: > is present
          Code 2: < is present
          Code 3: Both Present
        */
        printf("seg?\n");
        tokenPtr = strtok(command, " "); /*Segfaults this line...*/
        printf("tokenPtr: %s", tokenPtr);
        while(tokenPtr != NULL){
            if(strcmp(tokenPtr, ">") == 0){
                if(code == 0)
                    code = 1;
                else if(code == 2)
                    code = 3;
                else{
                    printf("Error: Cannot have multiple equivalent redirects\n");
                    fail = 1;
                }
                tokenPtr = strtok(NULL, " ");
                strcpy(carrotfile1,tokenPtr);
                tokenPtr = strtok(NULL, " ");
                strcpy(arglist[argnum], tokenPtr);
                argnum++;
            }
            else if (strcmp(tokenPtr,"<") == 0){
                if(code == 0)
                    code = 2;
                else if(code == 1)
                    code = 3;
                else{
                    printf("Error: Cannot have multiple equivalent redirects\n");
                    fail = 1;
                }
                tokenPtr = strtok(NULL, " ");
                strcpy(carrotfile2, tokenPtr);
                tokenPtr = strtok(NULL, " ");
                strcpy(arglist[argnum], tokenPtr);
                argnum++;
            }
            else{
                tokenPtr = strtok(NULL, " ");
                strcpy(arglist[argnum], tokenPtr);
                argnum++;
            }
        }
    }
}
4

1 回答 1

4

在 OS X 10.6.5 下测试时,指定的行没有段错误。它坠毁的地方是:

strcpy(arglist[argnum], tokenPtr);

这是因为arglist(and pathlist) 被分配了空间,而不是它们指向的任何字符串。这是一个arglist指针数组(未初始化为原始代码,然后初始化为零)和数组数组的说明。

指针数组,未初始化 指针数组,已初始化 数组数组

当您从 调用strcpy未初始化的指针时arglist,您正在复制到一个随机内存位置(如第一张图片所示)。

要解决此问题,您应该创建一个列表类型和函数来对列表进行操作。

typedef struct list {
    ...
} list_t;

// Initialize a new list. Pass NULL to dynamically allocate list structure.
list_t* createList(list_t* list);
// Destroy a list when done with it. You must free the list* if it was
// dynamically allocated.
void discardList(list_t* list);
// return first item in list
void* first(void);
// return last item in list. Could also be called "top"
void* last(void);
// append item to list
void push(void* item);
// remove & return last item
void* pop(void);
// remove & return first item
void* shift(void);
// prepend item to list
void unshift(void* item);

如果您将列表实现为数组,createListarglist使用memset. 在原始代码中,您还可以在声明时选择分配{0}arglist

char *arglist[1024] = {0};

如果您只需要将字符串存储在列表中(创建string_list_t类型)并且不需要一些操作(例如shiftand ,则可以更改 API unshift。使用string_list_t,push可以为字符串分配空间,复制字符串项并将副本存储在列表结构。

于 2011-03-05T22:12:30.110 回答