0

cafがhttps://stackoverflow.com/a/1113041/1354779で説明したように、変数が宣言されているときに初期化子を使用して、既に宣言されている配列を初期化する方法があります。それは素晴らしいことです。配列のすべての項目を 1 つずつ使用する方法があるかどうかを知りたいと思います。

これを使用して、パイプを介してコマンドのリストを渡します。これが機能することはわかっています。

char* script[]={"report blabla","report bla"};
char line[200];
char** command;
for (command = script ; **command ; **command ? command++ : 0){
    if (**command){
        SendCommand(*command, line, sizeof(line));
    }   
}

しかし、以下のコードを試すと、「pipe_GWB9.exe の 0x778915de で未処理の例外: 0xC0000005: アクセス違反の読み取り場所 0xcccccccc」が表示されます。

char* request[] = {"report watact"};
char line[200];
// [...] Other code [...]
static const char *tmp[8] = 
  {
  "report molality H+",
  "report molality Cl-",
  "report molality Ca++",
  "report molality Mg++",
  "report molality K+",
  "report molality Fe++",
  "report molality SO4--",
  "report molality Na+"
  }; 
  memcpy(request, tmp, sizeof request);
char** command;
command=request;
SendCommand(*command, line, sizeof(line));
// Until here, everything works great.
**command ? command++ : 0;
SendCommand(*command, line, sizeof(line));
// But THAT doesn't work!!

配列リクエストの他のアイテムを呼び出すのを手伝ってくれませんか?

ありがとう

4

1 に答える 1

1
char* request[] = {"report watact"};

request1 つの要素を含む char へのポインターの配列です。

static const char *tmp[8] = 
  {
  "report molality H+",
  "report molality Cl-",
  "report molality Ca++",
  "report molality Mg++",
  "report molality K+",
  "report molality Fe++",
  "report molality SO4--",
  "report molality Na+"
  }; 

tmpchar8 つの要素を持つポインタの配列です。

memcpy(request, tmp, sizeof request);

最初の 4 バイト ( と仮定sizeof request == 4) を からtmprequestコピーします。つまり、 の最初の要素を の最初の要素にコピーしtmpますrequest

char** command;
command=request;

簡単です。commandの最初の (そして唯一の!) 要素を指すようになりましたrequest

**command ? command++ : 0;

おっとっと。要素が 1 つしか含まれていないため、 command( request)の境界を超えてしまいました。request次に、次の行を呼び出すときにそれを逆参照しSendCommandます。これにより、セグ フォールトが発生します。UB を呼び出しているため、ここで何かが発生する可能性があることに注意してください。

たとえば、2 つの配列の間のコードを切り取ると、文字列が 2 回送信される可能"report molality H+"性があります。これは、 の境界を超えてポインターをインクリメントするとrequest、最初のtmp.

すべてを にコピーする場合はtmprequest2 つの配列が同じサイズ (または少なくとも と同じ大きさ) であることを確認する必要がありrequestますtmp

余談ですが、この三項式は少しばかげています。

**command ? command++ : 0;

1 つのブランチしか気にしないのに、なぜ 3 項を使用するのでしょうか? 好む:

if(**command)
    command++;

とはいえ、これは配列の境界をチェックする安全な方法ではありません (ご存じのとおり)。ポインターの配列を char へのポインターであるかのように扱っています。つまり、NULL ターミネーターが見つかるまでスキャンします。

配列には NULL ターミネータはありません。配列の境界を越えてしまい、未定義の動作が呼び出されるだけなので、サイズを個別に追跡して確認する必要があります。

于 2012-06-28T00:17:45.773 に答える