Segfault при использовании Strtok () в C - PullRequest
2 голосов
/ 06 марта 2011

Я использую C для написания своей собственной оболочки и для обработки потоковых перенаправлений (">" и "<"). Я использую strtok (), чтобы получить их и сохранить соответствующую информацию для последующего использования в программе. Я не уверен, почему я получаю ошибку сегментации при первом вызове. (Код сейчас довольно грязный). </p>

#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++;
            }
        }
    }
}

1 Ответ

4 голосов
/ 06 марта 2011

При тестировании в OS X 10.6.5 указанная строка не имеет ошибки.Там, где произошел сбой, было:

strcpy(arglist[argnum], tokenPtr);

, потому что arglistpathlist) - это выделенное пространство, но ни одна из строк, на которые они указывают.Вот иллюстрация arglist в виде массива указателей (неинициализированных как ваш исходный код, затем инициализированных нулями) и массива массивов.

array of pointers, uninitialized array of pointers, initialized array of arrays

Когда вы вызываете 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);

Если вы реализуете списки как массивы, createList обнулит arglist, используя memset.В исходном коде вы также можете назначить {0} на arglist при объявлении:

char *arglist[1024] = {0};

Вы можете изменить API, если вам нужно только хранить строки в списках (делаяstring_list_t type) и не требует некоторых операций (например, shift и unshift. С string_list_t, push может выделить место для строки, скопировать строковый элемент и сохранить копию в спискеструктура.

...