3

ライブラリの strtok(...) を使用していますが、セグメンテーション違反とプログラムのクラッシュが発生する終了条件まで正常に動作しているようです。API は、strtok(...) が見つからないトークンがなくなると NULL を出力すると主張しています。つまり、strtok( を使用して実行していたループを終了するには、この NULL をキャッチする必要があると思いました。 ...)。プログラムのクラッシュを防ぐために、この NULL をキャッチするにはどうすればよいですか? 終了条件として NULL の使用が許可されていると想像しました。

この動作を観察するための SSCCE を用意しました。私が書いているはるかに大きなソフトウェアで動作するには strtok(...) が必要で、まったく同じセグメンテーション動作が得られます。コマンド ラインでの出力は、このコード ビネットの下に表示されます (はい、ライブラリを囲むために <...> を使用していることは知っていますが、この投稿でコード ライブラリを表示するのに苦労していました)。私は Windows 8 OS で gcc バージョン 4.5.3 を使用しています。以下に、ループ内で NULL をキャッチしようとする方法の 2 つの異なるフレーバーを示します。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

main(){
  char* from = "12.34.56.78";
  char * ch = ".";
  char * token = strtok(from, ch);
  printf("%s\n",token);
  while(token != NULL){
    token = strtok(NULL, ch);
    printf("%s\n", token);
  }
  printf("Broke out of loop!");
  while(strcmp(token, 0) != 0){
    printf("%s\n",token);
    token = strtok(NULL, ch);
  }
}
############ 出力: ############

$ ./テスト
12
34
56
78
セグメンテーション違反 (コアダンプ)
4

6 に答える 6

4

strtok最初の引数を変更します。strtok読み取り専用メモリから文字列を渡していますが、変更しようとするとセグメンテーション違反が発生します。次から変更してみてください。

char* from = "12.34.56.78";

char from[] = "12.34.56.78";
于 2013-03-12T05:00:52.650 に答える
3

最初に が NULL と等しくないかどうかを確認しています (等しい場合はループtokenから抜け出します)。次に、定数 NUMBER を持つ をwhile比較しtokenていますか? NULLここで: 2 つの文字列が必要な場合は、数値を指定しますstrcmp(token, 0)。0番目のアドレス(またはNULL)で文字列をフェッチしようとすると、セグメンテーション違反が発生します。strcmpstrcmp

while(strcmp(token, 0) != 0){
    token = strtok(NULL, ch);
    printf("%s\n",token);
  }

また、このコードは次のようになります。

変化する

  char * token = strtok(from, ch);
  printf("%s\n",token);
  while(token != NULL){
    token = strtok(NULL, ch);
    printf("%s\n", token);
  }

  char * token = strtok(from, ch);
  printf("%s\n",token);
  while(token != NULL){
    printf("%s\n", token);
    token = strtok(NULL, ch);
  }
于 2013-03-12T05:01:22.170 に答える
3

これは問題です:

  while(token != NULL){
    token = strtok(NULL, ch);
    printf("%s\n", token);
  }

NULL をチェックしていますが、strtokもう一度呼び出して、その後チェックするのではなく、印刷する前にチェックしています。

コードには他にも問題がありますが、これが現在の場所でクラッシュする理由だと思います。

于 2013-03-12T05:02:18.690 に答える
2

問題は、 return のときにループを終了してもstrtok()、最初NULLに出力しようとすることです。NULL

  while(token != NULL){
    token = strtok(NULL, ch);
    printf("%s\n", token);    // not good when token is NULL
  }

他の回答で指摘されているように、この例のセグメンテーション違反には、これに加えていくつかの機会があることがわかりました。

サンプルのトークン化を処理する 1 つの方法を次に示します。

char from[] = "12.34.56.78";
char * ch = ".";
char * token = strtok(from, ch);
while (token != NULL){
    printf("%s\n", token);
    token = strtok(NULL, ch);
}
于 2013-03-12T05:01:34.410 に答える
2

コードの目的が「.」で区切られた要素を出力することだけである場合は、char 宣言のみを変更し、トークンを出力する前に、その値が NULL かどうかを確認してください。

 main(){
        char from[] = "12.34.56.78.100.101";
        char * ch = ".";
        char * token = strtok(from, ch);
        //printf("%s\n",token);
        while(token != NULL){
            printf("%s\n", token);
            token = strtok(NULL, ch);
        }
   }
出力
  ./test1
 12
 12
 34
 56
 78
 100
 101
于 2013-03-12T06:27:00.377 に答える
1

メモリ アクセス エラーと論理エラーの両方があります。プログラムのクラッシュの原因となっているメモリ アクセス エラーにのみ対処します。

strtok最初の引数を変更します。文字列リテラルを渡すため、文字列を変更することはできません (文字列リテラルは変更できません)。

from変更可能な文字列配列として定義するための可能な修正は次のとおりです。

char from[] = "12.34.56.78";

渡された文字列を変更するためstrtok、2 番目の while ループでその文字列を再度処理することはできません。strcmp基本的に、そこの関数にNULL を渡しています。可能な修正は、from使用するたびに配列を別のバッファにコピーすることstrtokです。

于 2013-03-12T05:23:50.763 に答える