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

C Language- freeing memory after using strtok to build char**

对不起,我想不出更好的措辞方式。

所以我有一个与 forkexec 一起工作的 C 作业。

我有三个名为 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]);

所做的只是从 double free 跳转到分段错误,或者我写了一个像 ps 或 history 这样的命令,但它什么也没做,所以我必须做点什么,但我真的迷失了一直在尝试修了两天,所以如果你看到我做错了请指出。

谢谢。

你应该添加

params[0] = NULL;

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

free(params);

您不需要释放任何参数[i],因为它们是指向本地 line[] 缓冲区的指针。

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