-6

Linux 環境のように動作するプログラムを作成しました。コマンドを入力すると、それが実行されます。

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

int main()
{

int pid;
int status;
printf("Enter command: ");
char s[256];
fgets(s,256,stdin);

const char *a[5];
int i = 0;
char* token = strtok(s, " ");
while(token)
{
    a[i] = strtok(s," ");   
    i++;
}

while (a[0] != "exit")
{
    if(a[0] = "cd")
    {
        chdir(a[1]);
    }

    else 
    {
      pid = fork();
        if (pid == 0)
        {
        execvp(a[0],a);
        }
        if(pid > 0)
        {
            wait(&status);
        }
    }

}
return 0;
}

コマンドのパラメータを区切るためにトークンを使用します。実行してみましたが、コンパイルして実行しますが、必要なコマンドを実行しません。トークンの作成方法に関係があるのではないかと思います。どんな助けでも素晴らしいでしょう。ありがとう。

4

2 に答える 2

3

この線:

a[i] = strtok(s," ");

a[i]変更中の文字列内のポインターに設定され、最終的に一時的な NUL 文字 (からstrtok) が削除される可能性があります。

あなたは試してみたいかもしれません:

a[i] = strdup (strtok (s," "));

代わりは。


さらに説明しましょう。コマンドがあるとします(メモリに存在するため):

ls -al xyzzy\0

あなたがstrtokそれをすると、ほぼ確実に次のように変更されます。

ls\0-al xyzzy\0
^

そして、s( で示される^) から返されstrtok、 に配置されa[0]ます。次回は、文字列を次のように変更します。

ls -al\0xyzzy\0
   ^

で示されるアドレスを取得し^、それを に挿入しa[1]ます。残念ながら、a[0]現在は文字列を指しています"ls -al"

最終的に、文字列は元の状態に戻り、ポインターは正しいアドレスを指していますが、期待どおりに文字列が null で終了することはありません (最後のアドレスを除く)。

したがって、次のようになります。

a[0] = "ls -al xyzzy"
a[1] = "-al xyzzy"
a[2] = "xyzzy"

を使用してstrdup、各文字列のコピーを作成します (文字列が期待どおりの時点で、単一の単語)。これは、文字列のトークン化コードの後の操作によって変更されません。

ただし、使い終わったら、割り当てたすべての文字列を解放することを忘れないでください。

このコードをベースラインとして使用できます。

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

int main (void) {
    char str[256], *word[20];
    int i, num, len;

    printf ("Enter command: ");
    fgets (str, sizeof (str), stdin);

    num = 0;
    word[num] = strtok (str, " ");
    while (word[num] != NULL) {
        word[num] = strdup (word[num]);
        len = strlen (word[num]);
        if (strlen (word[num]) > 0)
            if (word[num][len-1] == '\n')
                word[num][len-1] = '\0';
        word[++num] = strtok (NULL, " ");
    }

    for (i = 0; i < num; i++) {
        printf ("%d: [%s]\n", i, (word[i] == NULL) ? "<<null>>" : word[i]);
        free (word[i]);
    }

    return 0;
}

次のトランスクリプトは、実際の動作を示しています。

Enter command: ls -al xyzzy | grep -v plugh
0: [ls]
1: [-al]
2: [xyzzy]
3: [|]
4: [grep]
5: [-v]
6: [plugh]

さらに、C 文字列を比較する正しい方法は次のとおりではありません。

if (a[0] = "cd")

アドレスを比較するため、バッキング コンテンツが同じであってもアドレスが異なる可能性があります。代わりに次のようなものを使用する必要があります。

if (strcmp (a[0], "cd") == 0)

最後に、argv[]渡す配列にexecvpは、最終的な終了 NULL ポインターが必要です。これはコントラクトの一部であるため、 を呼び出す前に が含まれていることを確認する必要がありますexecvp

于 2013-03-12T06:21:35.080 に答える
0

while ループwhile (a[0] != "exit")は決して終了しません。ポインタ(メモリアドレス)を比較しています。についてお読みくださいstrcmp()

if ステートメントif(a[0] = "cd")も、あなたがやろうとしているとは思えません。"cd"へのポインタをに割り当てていますa[0]。このよくある間違いは、コンパイラ診断を使用した場合に検出されます (おそらく、==代わりに使用することを意図していましたが、これも機能しません - これもstrcmp()文字列比較に使用するものです)。

于 2013-03-12T06:25:00.013 に答える