0

関数 vsprintf の使用時に問題が発生しています。

XML ファイルを開く、閉じる、書き込む 3 つの関数があります。open 関数は入力テキストの最初の単語を配列に格納し、close 関数はその単語でタグを閉じます。問題は、使用する終了タグを格納する配列が、開く関数または書き込み関数を呼び出すたびに上書きされることです (書き込み関数が終了タグを格納するために使用される配列への参照を持たない場合でも)。

int xml_level = 0;
char *xml_header[64];
FILE *xml_out;

void xmlopen(const char *format, ...){
   char buffer[256];
   va_list arglist;
   va_start(arglist,format);
   vsprintf(buffer,format,arglist);
   va_end(arglist);
   int i;
   for(i=0; i<xml_level; i++){
      fprintf(xml_out,"\t");  
   }
   fprintf(xml_out,"<%s>\n",buffer);
   xml_header[xml_level] = strtok (buffer, " ");
   xml_level++;
}

void xmlclose(){
   xml_level--;
   int i;
   for(i=0; i<xml_level; i++){
      fprintf(xml_out,"\t");  
   }
   fprintf(xml_out,"</%s>\n",xml_header[xml_level]);
}

void xmlwrite(const char *format, ...){
   char buffer[256];
   va_list arglist;
   va_start(arglist,format);
   vsprintf(buffer,format,arglist);
   va_end(arglist);
   int i;
   for(i=0; i<xml_level; i++){
      fprintf(xml_out,"\t");  
   }
   fprintf(xml_out,"<%s/>\n",buffer);
}

使用例:

xmlopen("Hello Word");
xmlopen("Foo Bar");
xmlwrite("Potato");
xmlwrite("Sentence longer than the other ones");
xmlclose();
xmlclose();

出力例:

<Hello Word>
        <Foo Bar>
                <Potato/>
                <Sentence longer than the other ones/>
        </Sentence longer than the>
</Sentence longer than the>

あるべき場所:

<Hello Word>
        <Foo Bar>
                <Potato/>
            <Sentence longer than the other ones/>
        </Foo>
</Hello>

ありがとうございました。

4

2 に答える 2

1

解決

この行を変更します。

xml_header[xml_level] = strtok (buffer, " ");

xml_header[xml_level] = strdup (strtok(buffer, " "));

また、プログラムの終了時に xml_headers を解放することを忘れないでください。

[更新] もちろん、strtok返品などの可能性のあるまれなケースも確認する必要がありますNULL...

説明

strtok返されたトークンに追加のストレージを割り当てません。私の個人的な推測では、区切り文字を適切な\0 場所に置き換え、毎回次のトークンの開始へのポインターを返すことです。

xmlopenコードでは、256 バイトのバッファーを最初と最初の両方に割り当てていることに注意してくださいxmlwrite。このバッファーはスタックに割り当てられることを思い出してください。したがって、xmlopenまたはへの呼び出しではxmlwritebuffer実際には同じアドレスを指します(これを確認するためにその値を出力できます。printf("buffer is %p\n", buffer)それ0xbff2481cは私のマシンにあります)。

まず、 を呼び出してxmlopen("Hello World")、の開始xml_header[0]点でもある を指します。次に、 を呼び出して、の開始点でもある を指します。次に、 andを呼び出します。この時点で、まだ の先頭を指していることに注意してください。したがって、 を呼び出すと、予想されるトークンの代わりにその文が出力され、後のバッファによって上書きされます。"Hello"bufferxmlopen("Foo Bar")xml_header[1]"Foo"bufferxmlwrite("Portato")xmlwrite("Sentence longer than the other ones")xml_header[1]buffer"Sentence longer than the other ones"xmlclose()

興味深いことに、 と に異なるバッファ サイズを割り当てるxmlopenxmlwrite、たとえば に 256 バイト、xmlopenに 128 バイトを割り当てると、読み取り不能な混乱コードが出力されることがわかりますxmlwritexmlclose

xml_header[0], xml_header[1]との値を検査 (たとえば、出力) することで、これらすべてを確認できますbuffer

于 2012-05-21T11:04:15.130 に答える
1

buffer問題は、呼び出されたローカル変数が 1 つしかなくxmlopen、(a) 関数の外部で使用するためにその変数へのポインターを格納し (未定義の動作)、(b) 複数の呼び出しで使用しようとしている (論理バグ) ことです。

によって返される文字列用のストレージを割り当てる必要がありstrtok、後で破棄するようにしてください。たとえば、次のように変更します。

xml_header[xml_level] = strtok (buffer, " ");

に:

char * s = strtok(buffer, " ");
if (s != NULL)
{
    xml_header[xml_level] = strdup(s);
}

(後でこれらの文字列が不要になったときに破棄することは、読者の課題として残されています。)

于 2012-05-21T10:16:09.537 に答える