0

正直なところ、次のことがどのように起こるのかわかりません。コードは次のとおりです。

while(1)
{
    char** line = read_command();
    char* command = line[0];
    char** parameters = malloc(100);
    int i;

    for(i = 0; i < pNum; i++) // pNum is a global var containing the number of words read from read_command()
    {
        parameters[i] = line[i];
        printf("%i: %s", i, parameters[i]);
    }

    printf("%s\n", parameters[0]);
    parameters[0] = "/usr/bin/";
    strcat(parameters[0], command);
    printf("%s\n", command);
    printf("%s\n", parameters[0]);

    if(fork() != 0)
        waitpid(1, &status, 0);
    else
        execve(parameters[0], parameters, NULL);
}

read_command() は、基本的に入力された文字列の「配列」である char** を返し、各 char* には単語が含まれます。たとえば、「hello people of earth」と入力すると、結果は ["hello", "people", "of", "earth"] になります。この関数は常に機能します。

最初の反復では、すべてが期待どおりに機能します。たとえば、「date」と入力すると、出力は次のようになります。

0: date
date
date
/usr/bin/date
and then the date is displayed

しかし、2回目の繰り返しで、入力として「日付」を再度使用すると、出力は次のようになります。

0:date
edate 
/usr/bin/datedate 
and the date command is not issued

2 番目の printf ステートメントは、「hello」のような定数文字列を出力しても、最初の繰り返しの後に常に「e」を出力します。そして、コマンドポインターには「日付」が1つしかありませんが、パラメーター[0]にはどういうわけか2つの「日付」があります。

そして 3 回目の反復の後、プログラムはユーザー入力を待たず、ノンストップでループし、「PM: 警告、プロセス テーブルがいっぱいです!」と表示します。

何が原因でしょうか?

C用のccコンパイラを使用してMINIX 3.1.0で作業しています

編集: read_command():

char* line = malloc(), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
int currPos = 0;
int currParam = 0;
int i;
char** parameters = malloc(100);

if(line == NULL)
    return NULL;

while(1)
{
    c = fgetc(stdin);

    if(c == EOF) || c == '\n')
        break;

    if(--len == 0)
    {
        char* linen = realloc(linep, lenmax *= 2);
        len = lenmax;

        if(linen == NULL)
        {
            free(linep);
            return NULL;
        }

        line = linen + (line - linep);
        linep = linen;
    }

    if((*line++ = c) == '\n')
        break;
}

*line = '\0'; // everything up to this point i got from this link: http://stackoverflow.com/a/314422/509914

 parameters[currentParam] = malloc(100);

for(i = 0; i < strlen(linep); i++);
{
    if(isspace(linep[i]) || line[i] == EOF)
    {
        parameters[currParam][currPos] = '\0;
        currPos = 0;
        parameters[++currParam] = malloc(100);
    }
    else
        parameters[currParam][currPos++] = line[i];
}

parameters[currParam][currPos] = '\0';
pNum = currParam + 1;
return parameters;
4

1 に答える 1

1

何十年にもわたって試行錯誤されてきた K&R などの評判の良いリソースを読んで学ぶ人は、そうでない人よりもこれらの問題を抱える頻度がはるかに低い傾向があることは確かに興味深いことです...

char** parameters = malloc(100);は 100バイトを割り当てようとしています。realloc同様に動作するため、これについては再度言及しません。おそらく、100 ロットのchar *? : ... ...pNumをたくさん割り当てる方が理にかなっています。char *char **parameters = malloc(pNum * sizeof *parameters);char* linen = realloc(linep, (lenmax *= 2) * sizeof *linep);

strcatメモリを割り当てません。メモリを割り当てる唯一の関数はmalloccallocですrealloc

を呼び出すと、 が指す文字列の末尾に が指す文字列を追加するようにstrcat(foo, bar);求められます。コードで、文字列リテラルを変更しようとしています。未定義の動作であり、通常はセグメンテーション違反です。strcatbarfoo

あなたの変更された試みでさえ間違っています。では、文字列を にparameters[0] = "/usr/bin/";コピーしていません。文字列を指すように割り当てています (前述のように、通常は不変メモリにあります)。MCVEを作成して、未定義の動作の原因を絞り込む必要があります...parameters[0]parameters[0]

read_command()関数の 1 行目で、引数を指定せずchar* line = malloc(), * linep = line;に呼び出しています。mallocそれは制約違反です。コンパイラがエラーを発行しているはずです。おそらくあなたは を忘れていて#include <stdlib.h>mallocそのプロトタイプを見逃していませんか? このような推測を行う必要がないように、MCVE を提供してください。

に別の制約違反がありif(c == EOF) || c == '\n')ます ... MCVE を作成するために空白を埋める必要があるとしても (それはあなたの仕事であり、あなたが私たちに助けを求めているので、これを行う必要はありません)、このコードはコンパイルしません。おそらくそれがクラッシュの原因ですか?コンパイラが表示するメッセージを常に確認してください。警告を無視しないでください...そして間違いなくエラーメッセージを無視しないでください。

この回答から来たとあなたが主張したコードを比較しましたが、かなり異なります。その答えのコードはコンパイルされます。それにもかかわらず、それはあなたを助けようとしている人々との信頼を確立するためのあなたの方法です... 嘘をついていますか?

それほど多くの動的割り当ては必要ありません。通常、私は自分の邪魔をして、これを可能な限り最善の方法で行う方法を説明しますが、嘘は私を先延ばしにしました。もう 1 つ重要な点があります。手動で必要とされているため、(文字列が null 文字で終了するのと同様に) null ポインターで終了していることを確認してくださいparameters

于 2015-08-11T09:27:08.213 に答える