Q:

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

and sorry for the title I couldn't think of a better way to phrase it.
so I have a C assignment working with fork and exec.
I have three programs called ps, echo and history all of them take different arguments. The final program is called shell and it takes in commands from stdin and calls for exec upon taking a proper command.
example:
ps -a 

echo Hello World

history 1.txt

once it reads a line and find it's a valid command it makes a child process and calls for 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;
    }
}

that is my code so far, it behaves in a weird way causing segmentation faults,
I'm pretty sure it's because of the way I split the parameters and free them.
example output:
*** Error in `./shell': double free or corruption (out): 0x00007ffe58f1a630 ***
Parent Id: 1928
Aborted (core dumped)

so I keep editing the for loop
for (i = 0; i < j ; i++)
         free(params[i]);

all that does is just jump from double free to segmentation faults or I write a command like ps or history and it does nothing, so I must be doing something but I'm truly lost been trying to fix it for two days with, so if you see what I did wrong please point it out.
Thank you.

A:

strtok parses a string in-place so you should not free the individual results. They are portions of the original string. You can use the POSIX function strdup to make copies that can be free'd, and will persist beyond the life of the original buffer contents.

A:

You should add
params[0] = NULL;

right after the initial malloc (or use calloc) otherwise you'll be using an unitialized pointer if the line is empty. Then at the end
free(params);

you don't need to free any of params[i] since those are pointers into the local line[] buffer.

