.h 文件
#ifndef MDSHELL_H
#define MDSHELL_H
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
void getCommand(char * command, char *commandcopy);
void getNumOfTokens(char *command, char ***arrayofTokens, int *numberofTokens);
void getTokens(char *commandcopy, char ***arrayofTokens, int *numberofTokens);
#endif
主.c文件:
#include <stdio.h>
#include <stdlib.h>
#include "mdshell.h"
int main()
{
printf("Created by Matthew Lewis\n");
printf("Type \"help\" to see implemented commands\n\n");
char *command= NULL;
char *commandcopy = NULL;
char **arrayofTokens;
int numberofTokens;
while(command == NULL || (strcmp(command, "exit")) != 0)
{
if(command == NULL)
{
command = malloc(100 * sizeof(char));
commandcopy = malloc(100 * sizeof(char));
}
else{
free(command);
free(commandcopy);
command = malloc(100 * sizeof(char));
commandcopy = malloc(100 * sizeof(char));
}
getCommand(command, commandcopy);
getNumOfTokens(command, &arrayofTokens, &numberofTokens);
getTokens(commandcopy, &arrayofTokens, &numberofTokens);
for(int i = 0; i < numberofTokens; i++)
{ //used for testing to see tokens being returned. will not be in final build
printf("%s\n", arrayofTokens[i]);
}
if((strcmp(command, "help")) == 0)
{
printf("pwd - Print the current working directory\n");
printf("exit - Exit shell\n");
printf("help - Display this message\n");
printf("<UNIX cmd> - Spawn child process, excecute <UNIX cmd> in the foreground\n\n");
}
for (int i = 0; i < numberofTokens; i++)
{
free(arrayofTokens[i]); //free each element in array of pointers
}
free(arrayofTokens); //frees the array of pointers
}
mdshell.c 文件
#include "mdshell.h"
#include <stdio.h>
#include <stdlib.h>
void getCommand(char * command, char *commandcopy)
{
char word[100];
int size = 0;
printf("mdshell> ");
fgets(word, 100, stdin);
// removes the newline char at the end of whatever user entered
size = strlen(word);
word[size - 1] = '\0';
strcpy((command), word);
strcpy((commandcopy), word);
}
void getNumOfTokens(char *command, char ***arrayofTokens, int *numberofTokens)
{
int isDone = 0;
char delim[] = " ";
while(!isDone) // used to find out how many words there are
{
if((*numberofTokens) == 0)
{
char *word = strtok(command, delim);
if(word == NULL)
{
isDone = 1;
(*numberofTokens)++;
}
else
(*numberofTokens)++;
}
else
{
char *word = strtok(NULL, delim);
if(word == NULL)
{
isDone = 1;
(*numberofTokens)++;
}
else
(*numberofTokens)++;
}
}
//dynamically allocate the array of pointers to the number of elements needed
(*arrayofTokens) = malloc((*numberofTokens) * sizeof(char *));
}
void getTokens(char *commandcopy, char ***arrayofTokens, int *numberofTokens)
{
char delim[] = " ";
int size = 0;
int arrElement = 0;
char *word = strtok(commandcopy, delim);
if(word != NULL)
{
size = strlen(word);
(*arrayofTokens)[arrElement] = malloc((size) * sizeof(char));
strcpy((*arrayofTokens)[arrElement], word);
arrElement++;
}
else
{
(*arrayofTokens)[arrElement] = NULL;
}
while(word != NULL)
{
word = strtok(NULL, delim);
if(word == NULL)
{
(*arrayofTokens)[arrElement] = malloc((size) * sizeof(char));
}
else
{
size = strlen(word);
(*arrayofTokens)[arrElement] = malloc((size) * sizeof(char));
strcpy((*arrayofTokens)[arrElement], word);
arrElement++;
}
}
}
我正在为 Linux 编写一个小 shell 程序。我让用户输入一个命令,然后将其分解为一个以 null 结尾的数组或指向 execvp() 函数所需的 char 的指针。我还没有讲到那部分。 execvp() 需要一个以 null 结尾的字符串数组。我已将字符串放入已计算出的字符串数组中,除了在字符串末尾获取 null 之外。即使我将该元素分配给 NULL,它也只是显示空白而不是 (NULL)
这是我得到的输出示例:
我有一种感觉,我没有为 arrayofTokens 正确释放内存。我正在释放每个动态分配的部分,所以我不知道为什么会出现分段错误。任何帮助将不胜感激,以便我可以继续完成其余的作业。祝你有美好的一天!
我希望能够在 shell 中使用不同的命令时多次使用 arrayofTokens。这在第一次通过后不起作用。
很明显,您确实非常努力地想让它发挥作用。荣誉!
隐藏在代码堆中的是@BoP 在评论中指出的错误。也许教训是努力编写更少的代码。
评论:
malloc()
的电话未被接听?不要假设事情总是有效!void getCommand()
传递了一个缓冲区,但最初使用自己的缓冲区。为什么?而且,如果程序需要第二个副本,则这里不是进行克隆的地方。void getNumOfTokens()
采用 3 个参数,然后通过成为 void
函数来浪费其返回值。令牌的数量可以返回给调用者,并且函数签名得到简化。 (循环if/else
可以大大简化。void getTokens()
...同样,代码重复隐藏了第二个错误。不仅分配的缓冲区大小对于尾随 '\0'
来说太短,而且 argv[argc+1]
的值本来就是 NULL
。太多胆怯和试探性代码让人很难看出出了什么问题。main()
???用 malloc()
和 free()
冲击动态内存表示需要重新考虑代码。下面是代码的单个文件重写。我希望这能为您指明更好的方向。
#include <stdio.h>
#include <stdlib.h>
#define MAX_CMD_LEN 128
char **tokenise( char *str, int *n ) {
static const char *dlm = " \t";
char cpy[ MAX_CMD_LEN ]; // disposable copy
strcpy( cpy, str );
// chop disposable copy to determine # of tokens (pointers)
// start with '1' to allow for extra NULL as sentinel at the end of array
int i = 1;
for( char *cp = cpy; (cp = strtok(cp, dlm)) != NULL; cp = NULL )
i++;
char **arr = calloc( cnt, sizeof *arr ); // use calloc for consistency
/* verification of allocation success left as an exercise */
// chop actual buffer storing pointers to each segment
i = 0;
for( char *xp = str; (xp = strtok(xp, dlm)) != NULL; xp = NULL )
arr[ i++ ] = xp;
*n = cnt - 1;
return arr;
}
int main( void ) {
for( ;; ) {
char iBuf[ MAX_CMD_LEN ]; // small stack buffer
printf( "mdshell> " );
fgets( iBuf, sizeof iBuf, stdin );
iBuf[ strcspn( iBuf, "\n" ) ] = '\0'; // trim LF from end
if( strcmp( iBuf, "help" ) == 0 ) { // early resolution
puts( "pwd - Print the current working directory" );
puts( "exit - Exit shell" );
puts( "help - Display this message" );
puts( "<UNIX cmd> - excecute <UNIX cmd> in the foreground\n" );
continue;
}
int arrgc;
char **arrgv = tokenise( iBuf, &arrgc ); // KISS
// demonstrate results
for( int i = 0; i <= arrgc; i++)
printf( "[%d] '%s'\n", i, arrgv[i] );
free( arrgv ); // easy...
}
return 0;
}
结果:
mdshell> fools rush in where wise men fear to go
[0] 'fools'
[1] 'rush'
[2] 'in'
[3] 'where'
[4] 'wise'
[5] 'men'
[6] 'fear'
[7] 'to'
[8] 'go'
[9] '(null)'
mdshell> // just pressed RETURN here
[0] '(null)'
mdshell>
注意! 我的编译器很友善,打印
(null)
而不是崩溃。您从其他实施中获得的里程可能会有所不同。