C语言-使用strtok构建char后释放内存**
C Language- freeing memory after using strtok to build char**
对不起,我想不出更好的措辞方式。
所以我有一个与 fork
和 exec
一起工作的 C 作业。
我有三个名为 ps
、echo
和 history
的程序,它们都采用不同的参数。最终程序称为 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
制作可以免费使用的副本,并将在原始缓冲区内容的生命周期之后继续存在。
对不起,我想不出更好的措辞方式。
所以我有一个与 fork
和 exec
一起工作的 C 作业。
我有三个名为 ps
、echo
和 history
的程序,它们都采用不同的参数。最终程序称为 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
制作可以免费使用的副本,并将在原始缓冲区内容的生命周期之后继续存在。