C语言 - 使用strtok构建char后释放内存**

时间:2015-11-18 18:06:20

标签: c segmentation-fault strtok

抱歉标题,我想不出更好的方式来表达它。

所以我的C作业与forkexec一起使用。

我有三个名为psechohistory的程序,所有程序都采用不同的参数。最终的程序称为shell,它接收来自stdin的命令,并在采取适当的命令后调用exec

示例:

ps -a 

echo Hello World

history 1.txt

一旦它读取一行并发现它是一个有效的命令,就会生成子进程并调用exec

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

const int MAX_LINE = 100;

const char *HISTORY = "./history";
const char *PS = "./ps";
const char *ECHO = "./echo";

void call_cmd(int cmd, char *const argv[]);

/* main function */
int main(int argc, char** argv)
{
    FILE * out;
    char line[MAX_LINE], line_print[MAX_LINE], seps[] = " \n", rm[80];
    char *first, *tmp, ** params;
    pid_t pid;
    int cmd = -1, i = 0,j= 0;

    if (argc != 2)
    {
        printf("Invalid arguments");
        return EXIT_FAILURE;
    }
    out = fopen(argv[1],"w");
    if (out == NULL)
    {
        perror("Couldn't open file to write");
        return EXIT_FAILURE;
    }
    while(fgets(line,sizeof(line),stdin) != NULL)
    {
        strcpy(line_print,line);
        params = (char**) malloc(sizeof(char*));
        tmp = strtok(line,seps);
        while (tmp != NULL)
        {
            if(i != 0)
            params = (char**) realloc(params,sizeof(char*) * (i + 1));
            params[i] = tmp;
            j++;
            tmp = strtok(NULL,seps);
            i++;
        }
        first = params[0];
        if (strcmp("exit",first) == 0)
        {
            sprintf(rm,"rm %s",argv[1]);
            system(rm);
                        exit(0);
        }
        if(strcmp("echo",first) == 0)
            cmd = 0;
        if(strcmp("history",first) == 0)
            cmd = 1;
        if(strcmp("ps",first) == 0)
            cmd = 2;
        if(cmd == -1){
            perror("\nInvalid Command\n");
        }
        if(cmd >= 0)
        {
            fprintf(out,"%s",line_print);
            pid = fork();
            if (pid == -1)
            {
                perror("Error Creating Child");
                return EXIT_FAILURE;
            }
            if(pid == 0)
            {
                call_cmd(cmd,params);
                exit(0);
            }
        }   
        for (i = 0; i < j ; i++)
             free(params[i]);
        free(params);   
        i = j = 0;
        cmd = -1;
    }
    fclose(out);
    return EXIT_SUCCESS;
}

void call_cmd(int cmd, char *const argv[])
{
    switch(cmd)
    {
        case 0:
            execv(ECHO, argv);
            break;
        case 1:

            execv(HISTORY, argv);
            break;
        default:
            execv(PS, argv);
            break;
    }
}

这是我的代码到目前为止,它表现得很奇怪,导致分段错误, 我很确定这是因为我分割参数并释放它们的方式。

示例输出:

*** Error in `./shell': double free or corruption (out): 0x00007ffe58f1a630 ***
Parent Id: 1928
Aborted (core dumped)

所以我一直在编辑for循环

for (i = 0; i < j ; i++)
         free(params[i]);

所有这一切只是从双重自由跳转到分段错误,或者我写了一个像ps或历史这样的命令而它什么都没做,所以我必须做一些事情,但我真的迷失了,试图修复它两天,如果你看到我做错了,请指出。

谢谢。

2 个答案:

答案 0 :(得分:4)

strtok解析字符串就地,因此您不应释放单个结果。它们是原始字符串的一部分。您可以使用POSIX函数strdup制作可以免费复制的副本,并且会在原始缓冲区内容的生命周期内保留。

答案 1 :(得分:2)

你应该添加

params[0] = NULL;

在初始malloc之后(或使用calloc),否则如果该行为空,您将使用单位指针。然后在最后

free(params);

你不需要释放任何params [i],因为它们是指向本地行[]缓冲区的指针。