0

こんばんは、

割り当てに問題があります。

基本的に、与えられたの素因数を計算するプログラムをコーディングする必要がありますstdinstdinデータは、それを介してのみプログラムに入ることができechoます< file.txt。データのストリームが80文字を超えることはありません(数字であってもなくてもかまいません)。

プログラムで使用する関数はread()、、、でstrotol()ありstrtok()、「無関係な」コードは次のように流れます。

  1. malloc80の初期バイトのメモリを割り当てるために使用します。
  2. 読み取った文字数(そして最後の文字int)を介して、に格納します。read()\0
  3. できるだけ多くのメモリを節約するためにメモリを再割り当てしrealloc()ます(この場合は些細なことですが、まあ...)。

ここで注意が必要です。

  1. データはスペースで区切る必要があるため、チェックする項目の最大数は最大で次のようになります(n/2)+1。ここnで、は上限nº2で読み取られた文字数です。
  2. longポイントnº1で取得された数の最大サイズの配列を作成します。
  3. numbers[0]次の結果で埋めます: strtol(strtok(line, delim), &end, 10)
  4. に追加1し、ループcounterに入ります。while

    while((numbers[counter] = strtol(strtok(NULL, delim), &end, 10)) != NULL) {
        if(!*end) {
            // Check whether it's 0, 1, negative, prime or extract its factors
        }
        else {
            fprintf(stderr, "\"%s\" is not a non-negative integer", end)
        }
        counter++;
    }
    

ここで、いくつかの入力とその出力を示します。

入力:echo 1 2 3 4 5 6 7 8 9 10 | ./factors

出力:

1
2    
3
    2    2
5
    2    3
7 
    2    2    2
    3    3
    2    5
Segmentation Fault (core dumped). 

入力./factors < integers.txt 整数に整数の列が含まれている場合。

出力:

すべての整数は適切に因数分解され、最後に次のように出力されます。

Segmentation Fault (core dumped). 

入力:echo abc 12 13 14 15 | ./factors

出力:

"abc" is not a non-negative integer
13
    2    7
    3    5
Segmentation Fault (core dumped). 

入力:echo -1 -2 -3 -4 -5 | ./factors

出力:

"-1" is not a non-negative integer
"-2" is not a non-negative integer
"-3" is not a non-negative integer
"-4" is not a non-negative integer
"-5" is not a non-negative integer

入力:echo abc abc abc | ./factors

出力:

"abc" is not a non-negative integer

(そしてチェックを続けません)。

入力:echo 3 4 0 6 7 | ./factors

出力:

3
    2    2

(そしてチェックを続けません)。

私が見る限り、正常なデータストリームの最後に0、非インスタンスまたは基本的に複数のインスタンスが発生すると失敗します。integerinteger

どうすればこれに取り組むことができるのか、そしてなぜそれが明らかにランダムに失敗するのか、何か考えはありますか?

私はCに不慣れであることをあなたに知らせなければなりません...

よろしくお願いします。

================================================== ==

EDIT1:リクエストに応じて、を生成numbers[]し、そこから読み取るコードフラグメントは次のstdinとおりです。

char *line;
char *end;
char *delim = " \n";
int charsread, counter; 

line = malloc(80);
charsread = read(0, line, 81);
if (charsread == 0) {
    return EX_OK;
}
realloc(line, charsread);
maxelem = (charsread / 2) + 1;
long numbers[maxelem];
numbers[0] = strtol(strtok(line, delim), &end, 10);
if (!*end) {
    zeroone(numbers[0]);
}
else {
    fprintf(stderr, "\"%s\" is not a non-negative integer\n", end);
}
counter = 1;
while [...]
4

3 に答える 3

2

gdbを使用してsegfaultをデバッグするか、適切な環境変数を設定してsegfaulting時にコアをダンプするか、gdbで直接実行してみてください。Segfaultは、メモリの一部を読み書きしてはいけないことを意味します。ランダム性とは、おそらくスタックか何かを壊していることを意味します。「printf」のせいで、彼らの議論をチェックすると思います。また、数値が配列の長さよりも小さいことを確認していませんか?それはそれをオーバーランするかもしれませんか?

于 2012-06-07T18:04:18.180 に答える
1

さて、私たちがそこにいる間にいくつかのことを確認して、あなたの問題を解決できるかどうか見てみましょう。


これはプログラムでは必要ありません。

realloc(line, charsread);

メモリーフットプリントを削減しようとするのは正しいのですが、割り当てが多すぎる場合はどうでしょうか。80バイトです。あなたがすでにあなたの皿に十分に持っていることを過度に複雑にしないでください。


これは奇妙です:

maxelem = (charsread / 2) + 1;
long numbers[maxelem];

これは問題なく、あなたのケースでは機能しますが、数のグループを数えることで、要素の数をより正確に決定できます。


両方のloppで抽出全体を実行することをお勧めします


実際のところsegmentation fault…ここのマシンで再現する機会がないので間違っているかもしれませんが、キャラクターで終わらせなかったためにエラーが発生したと思いlineます\0。Cでは、投稿したスニペットの外観からすでにご存知のとおり、行は通常「NULLで終了」と呼ばれるものであるため、慣例により、の数値である値0で終了します。NULとしても表される文字(\0これは、「NULLで終了する」、「NUL」文字、および「NULLポインター」の間で混乱するため、少し混乱することがあります。これらは別のものです)。

最終的にプログラムは行の終わりを読み込もうとしますが、strtokどこで停止するかわからないため、これによりプログラムが中断します。バッファの長さや、このバッファのどこで停止するかについては、良心がありません。したがって、読み取りを続け、アクセスが許可されていないメモリアドレスに到達すると、が表示されますsegmentation fault

したがって、単純に次のようにします。

/*
** If you keep your realloc, you need to allocate for the number of read
** characters from stdin, and for an extra char to terminate.
*/
line = realloc(line, charsread + 1); 
/*
** Terminate the string.
*/
line[charsread] = '\0';

更新:ああ、あなたは実際にはほとんどそこにいました、あなたは論理を持っていましたが、おそらくこのビットを逃しただけです...あなたはこれを自分で書いた:

read()を介して、読み取られた文字数(そして、最後の\ 0)をintに格納します。

これは部分的に真実です。実際に80文字の行を取得した場合、read呼び出しは\0最後にaが付いた行を返します。ただし、ほとんどの場合、読み取りバッファは表示されている文字のみを読み取るため、文字列を自分でnullで終了する必要があります。


また、処理ループを書き直して、その一部としてstrtokへの最初の最初の呼び出しも実行しようと思います。書くのに必ずしも便利ではありませんが、通常、ループの直前または直後にループ内にあるものとほぼ同じコードのブロックを見ると、より良い論理的アプローチがあると思います。

于 2012-06-07T19:14:08.827 に答える
0

洞察に満ちた対応をありがとうございました。

思ったほどきれいに見えなかったので、結局全部書き直しました。fromのマニュアルでは、トークンを抽出できなかった場合のstrtok戻り値が指定されているため、これが最終的な結果になります。NULL

long number;
item = strtok(line, delim);
while (item != NULL) {
       number = strtol(item, &rest, 10);
       if (*rest == 0) {
           zeroOne(number);
       }
       else {
           fprintf(stderr, "\"%s\": not a non-negative int.\n", item);
       }
       item = strtok(NULL, delim);
}   

よりクリーンなアプローチのようであり、strtokからの戻り値が、以前のループにNULL入ろうとする前に返されるという事実を考慮しています。whileそれから、今朝私はここに戻ってあなたの応答を読みました:)

\0読み取った行へのハードコードされた入力に関するフォローアップの質問:これは、私の最後strtokが実際に\0トークンを出力してループに入ろうとすることを意味しますか、それともNULL最後に導入された直後にエンティティに到達したときにを返しますか?キャラクター?慣例として、使用する場合(または、他の関数が/をチェックできるように、常に読み取り行にaをハードコーディングする必要がread()あるなど、他の読み取り関数を使用する必要がありますか?fgets()\0EOLEOF

他の誰かがこれらの機能(strtokおよびstrtol)のいずれかを使用するのに問題がある場合は、このサイトに投稿された次の2つの質問を確認することをお勧めします。

の2番目の引数についてstrtolStrtolの2番目の引数

strtokの出力について: strtokの出力変数を連結できません。strcatとstrtok

于 2012-06-08T06:34:11.990 に答える