Значение моей структуры не обновляется при передаче неправильного указателя - PullRequest
0 голосов
/ 30 марта 2020

Я работаю над реализацией истории для оболочки. У меня есть структура, которая хранит команду, и массив этих структур хранит историю.

typedef struct command {
    char **arg;
    int num;
} cmd;

Код ниже корректно обновляет историю, распечатывая

Cmd # 1 : ls -l

Cmd # 1: pwd

Cmd # 2: ls -l

int main() {
    char *arguments[3] = {"ls", "-l", NULL};
    cmd *history = startHist();
    history = updateHist(arguments, history);
    printHistory(history);
    char *arg2s[2] = {"pwd", NULL};
    history = updateHist(arg2s, history);
    printHistory(history);
    free(history);
}

cmd* startHist() {
    cmd *ret = malloc(20*sizeof(cmd));
    for(int i=0;i<20;i++){
        ret[i].arg = NULL;
        ret[i].num = -1;
    }
    return ret;
}

cmd* updateHist(char **args, cmd *hist) {
    for(int i = 19;i>0;i--) {
        hist[i] = hist[i-1];
    }
    hist[0].arg = args;
    if(hist[1].arg!=NULL) {
        hist[0].num = hist[1].num+1;
    } else {
        hist[0].num = 1;
    }
    return hist;
}

void printHist(cmd *hist) {
    int pos = 0;//index for iterating through commands
    while(hist[pos].arg!=NULL) {
        char* prstr = malloc(INIT_BUFFER*sizeof(char));//the string that will be printed
        *prstr = '\0';
        int index = 0;//index for iterating through arguments
        printf("Cmd #%d: ", pos+1);
        while(hist[pos].arg[index] != NULL) {
            printf("%s ", hist[pos].arg[index]);
            strcat(prstr, hist[pos].arg[index]);//concatenate the argument strings
            index++;
        }
        printf("\n");
        pos++;
        free(prstr);
    }
}

Однако следующий код не работает. Вместо этого строковое значение каждой записи cmd заменяется самой последней командой, хотя значение int работает правильно.

Редактировать: код был изменен по рекомендации. Теперь он должен запустить 3 цикла ввода. Пример вывода:

?: ls

Cmd # 1: ls

?: ls -a

Cmd # 1: ls -a

Cmd # 2: ls -a

?: выход

Cmd # 1: выход

Cmd # 2: выход

Cmd # 3: выход

Обратите внимание, что startHist (), printHist () и updateHist () такие же, как указано выше.

#include "stdio.h"//get from and print to console
#include "stdlib.h"//free and malloc
#include <string.h>//strtok

//Initial input buffer size. Will be expanded in getLine if needed.
const int INIT_BUFFER = 256;

typedef struct command {
    char **arg;
    int num;
} cmd;

//Function Declarations
char * getLine();//gets the input from the console and returns it
char ** splitLine(char *a);//splits the passed string into argument substrings
cmd* updateHist(char **args, cmd *hist);
void printHist(cmd *hist);
cmd* startHist();

void main() {
    //declare primary variables
    char *input;
    char **args;
    int retVal=3;
    cmd *history = startHist();
    do {//primary execution loop
        printf("?: ");//prompt for input
        input = getLine();
        args = splitLine(input);
        history = updateHist(args, history);
        printHist(history);
        retVal--;
        free(input);
        free(args);
    } while(retVal);
    free(history);
}

char ** splitLine(char *input) {
    //variables for finding the number and length of the arguments
    int numArgs=1;//the number of args in the input(starts at 1, increases per space).
    int pos = 0;//the position as the input is iterated through
    //loop to find the number and length of the arguments
    while(input[pos]!='\0'){//until the end of the input is reached
        if(input[pos]==' '){//if the end of the argument is reached
            numArgs++;//increment argument counter
        }
        pos++;//increment the position counter
    }
    pos=0;//reset pos to reiterate through the input
    //create an array of arguments
    char* *argArray = malloc((1+numArgs)*sizeof(char*));
    char *temp = strtok(input, " \n\r\t");//get the first token from the string
    while(temp!=NULL) {
        argArray[pos] =temp;
        pos++;
        temp=strtok(NULL, " \n\r\t");
    }
    argArray[pos]=NULL;
    return argArray;
}

char * getLine() {
    int buffspace = INIT_BUFFER;
    char *buffer = malloc(sizeof(char)*INIT_BUFFER);
    int pos = 0;
    int c;//input 

    if(!buffer) {
        fprintf(stderr, "Shell: Allocation Error\n");
        exit(EXIT_FAILURE);
    }

    do {
        c=getchar();//get the next character

        if(c==EOF || c=='\n'||c=='\r') {
            buffer[pos]='\0';
            return buffer;
        } else {
            buffer[pos] = c;
        }
        pos++;

        if(pos>=buffspace) {
            buffspace += INIT_BUFFER;
            buffer = realloc(buffer, buffspace);
        }
    } while(c!=EOF);

    //the buffer should be returned before this point.
    //Print out an error and exit
    fprintf(stderr, "Shell: Assignment Error\n");
    return buffer;
}

cmd* startHist() {
    cmd *ret = malloc(20*sizeof(cmd));
    for(int i=0;i<20;i++){
        ret[i].arg = NULL;
        ret[i].num = -1;
    }
    return ret;
}

cmd* updateHist(char **args, cmd *hist) {
    for(int i = 19;i>0;i--) {
        hist[i] = hist[i-1];
    }
    hist[0].arg = args;
    if(hist[1].arg!=NULL) {
        hist[0].num = hist[1].num+1;
    } else {
        hist[0].num = 1;
    }
    return hist;
}

void printHist(cmd *hist) {
    int pos = 0;//index for iterating through commands
    while(hist[pos].arg!=NULL) {
        char* prstr = malloc(INIT_BUFFER*sizeof(char));//the string that will be printed
        *prstr = '\0';
        int index = 0;//index for iterating through arguments
        printf("Cmd #%d: ", pos+1);
        while(hist[pos].arg[index] != NULL) {
            printf("%s ", hist[pos].arg[index]);
            strcat(prstr, hist[pos].arg[index]);//concatenate the argument strings
            index++;
        }
        printf("\n");
        pos++;
        free(prstr);
    }
}

1 Ответ

2 голосов
/ 30 марта 2020

Похоже, вы просто храните указатели в вашей cmd структуре данных, а не указатели на строки и массивы. Это означает, что вы в конечном итоге сохраните указатели на локальные переменные после того, как они go выйдут из области видимости, что приведет к неопределенному поведению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...