1

さて、私はここSOや他の多くの場所で膨大な量の答えを読みましたが、この単純な機能を理解できないようです。私は8年以上c/c ++コードを実行しておらず、再学習を非常に試みているので、しばらくお待ちください...

値をシフトして関数paramを介して文字列を割り当てることから、値を直接返すことまで、これを行うためのさまざまな方法を試しましたが、しばらくの間は何も機能しないようです。コンパイル時にもエラーは発生しませんが、実行時にsegfaultsが発生します。次の関数が機能しない理由を知りたいのですが...elseがcha​​r*content型として正常に返される理由がわかりませんが、strcat(content、line); ではない。strcatのマニュアルページには、strcatの定義は(char * DEST、const char * SRC)である必要があることが示されていますが。私が現在理解しているように、while内のline変数のconst charにキャストしようとすると、ポインターに整数が返されます。だから私はここで困惑していて、時間のある人たちに教育を受けたいです!

char * getPage(char *filename) {
    FILE *pFile;
    char *content;
    pFile = fopen(filename, "r");
    if (pFile != NULL) {
        syslog(LOG_INFO,"Reading from:%s",filename);
        char line [256];
        while (fgets(line, sizeof line, pFile) != NULL) {
            syslog(LOG_INFO,">>>>>>>Fail Here<<<<<<<");
            strcat(content, line);
        }
        fclose(pFile);
    } else {
        content = "<!DOCTYPE html><html lang=\"en-US\"><head><title>Test</title></head><body><h1>Does Work</h1></body></html>";
        syslog(LOG_INFO,"Reading from:%s failed, serving static response",filename);
    }
    return content;
}

この投稿のすべての素晴らしい答えに感謝します。ディスカッションの全員にチェックマークを付けますが、残念ながらできません...

4

6 に答える 6

2

にメモリを割り当てる必要がありますcontent。それはあなたがそれをしているようにファイル全体のために十分に大きくなければなりません。大きなバッファを前もって割り当てて最適なものを期待するか、小さいバッファを割り当てて必要に応じて再割り当てすることができます。

さらに良いのは、ファイル全体を一度に保存する必要がないようにコードを再配置することです。ただし、呼び出し元がWebページ全体を文字列として必要とする場合、それは難しいかもしれません。

また、両方のコードパスから同じタイプのメモリを返す必要があることにも注意してください。静的文字列を返すことも、ヒープに割り当てられた文字列を返すこともできません。これは、頭痛やメモリリークを引き起こすことが保証されています。したがって、ファイルの内容をメモリのブロックにコピーする場合は、静的文字列も同じタイプのブロックにコピーする必要があります。

于 2012-02-09T02:32:13.383 に答える
2

これは非常に単純ですが、高級言語に慣れている場合は非常に驚くべきことです。 Cはメモリを管理しませんしCには実際には文字列がありません。そのcontent変数はポインタであり、文字列ではありません。を呼び出す前に、文字列に必要なスペースを手動で割り当てる必要がありますstrcat。このコードを書く正しい方法は次のようなものです:

FILE *fp = fopen(filename, "r");
if (!fp) {
    syslog(LOG_INFO, "failed to open %s: %s", filename, strerror(errno));
    return xstrdup("<!DOCTYPE html><html lang=\"en-US\"><head><title>Test</title>"
                  "</head><body><h1>Does Work</h1></body></html>");
} else {
    size_t capacity = 4096, offset = 0, n;
    char *content = xmalloc(capacity);
    size_t n;
    while ((n = fread(content + offset, 1, capacity - offset, fp)) > 0) {
        offset += n;
        if (offset == capacity) {
            capacity *= 2;
            content = xrealloc(content, capacity);
        }
    }
    if (n < 0)
        syslog(LOG_INFO, "read error from %s: %s", filename, strerror(errno));
    content[offset] = '\0';
    fclose(fp);
    return content;
}

ノート:

  1. I / Oエラーによってトリガーされるエラーメッセージには、常にを含める必要がありますstrerror(errno)
  2. xmalloc、、、xreallocおよびxstrdupは、先頭がない対応するラッパー関数xです。を返すのではなく、プログラムをクラッシュさせNULLます。これは、ほとんどの場合、発生する可能性のあるすべての場所で手動でメモリ不足から回復しようとするよりも悲しみが少なくなります。
  3. 発信者がいつでも電話できるように、開けなかった場合ではxstrdup("...")なく戻ってきます。文字列リテラルを呼び出すと、プログラムがクラッシュします。"..."free(content)free
  4. おやおや、それは大変な作業でしたね。これが、人々が高水準言語でWebアプリを作成することを好む傾向がある理由です。;-)
于 2012-02-09T02:39:36.823 に答える
1

contentワイルドポインタです。変数にはガベージが含まれているため、左側のフィールドのどこかを指しています。を使用してデータをコピーするとstrcat、データはランダムな、おそらく悪い場所に移動します。これの治療法は、contentどこか良い点を作ることです。関数呼び出しよりも長持ちさせたいので、関数の呼び出しスタック以外の場所に割り当てる必要があります。malloc()ヒープにスペースを割り当てるためにを使用する必要があります。次に、呼び出し元がメモリを所有し、free()不要になったときに呼び出してメモリを削除する必要があります。

を使用するには、にelse直接割り当てる部分も変更する必要があります。これにより、が常に有効になります。割り当てなかったものを解放することはできません!contentstrcpyfree()

このすべてのコードを通じて、割り当てたスペースの量を覚えておいてくださいmalloc()。また、スペースよりも多くのデータを書き込まないようにしてください。そうしないと、クラッシュが増える可能性があります。

于 2012-02-09T02:32:36.833 に答える
1

char *foo文字列を形成する文字を保持するメモリの一部へのポインタにすぎません。したがってstrcat、コピー先のメモリがないため、使用できません。ステートメント内で、行を保持ifするスタックにローカルメモリを割り当てていますchar line[256]が、そのメモリは関数に対してローカルであるため、関数が戻ると消えるので、できませんreturn line;

したがって、本当に必要なのは、関数から返すことができるように、たとえばwithstrdupやなどの永続メモリを割り当てることです。malloc定数と割り当てられたメモリを混在させることはできないことに注意してください(関数のユーザーはfreeメモリを使用する必要があるためです。これは定数でない場合にのみ可能です)。

したがって、次のようなものを使用できます。

char * getPage(const char *filename) {
    FILE *pFile;
    char *content;
    pFile = fopen(filename, "r");
    if (pFile != NULL) {
        syslog(LOG_INFO,"Reading from:%s",filename);
        /* check the size and allocate memory */
        fseek(pFile, 0, SEEK_END);
        if (!(content = malloc(ftell(pfile) + 1))) { /* out of memory ... */ }
        rewind(pFile);
        /* set the content to be empty */
        *content = 0;
        char line [256];
        while (fgets(line, sizeof line, pFile) != NULL) {
            syslog(LOG_INFO,">>>>>>>Fail Here<<<<<<<");
            strcat(content, line);
        }
        fclose(pFile);
    } else {
        content = strdup("<!DOCTYPE html><html lang=\"en-US\"><head><title>Test</title></head><body><h1>Does Work</h1></body></html>");
        syslog(LOG_INFO,"Reading from:%s failed, serving static response",filename);
    }
    return content;
}

これを行うのに最も効率的な方法ではありませんが(strcat毎回終わりを見つける必要があるため)、コードの変更は最小限に抑えられます。

于 2012-02-09T02:34:19.177 に答える
1

contentは、実際の文字列ではなく、文字列への単なるポインタです。文字列用に0バイトのスペースが予約されています。時間文字列を保持するのに十分な大きさのメモリを割り当てる必要があります。後でそれを解放する必要があることに注意してください

char *content=malloc(256);

そして、あなたのコードは大丈夫なはずです-ああ、私はstrncatを使用することをお勧めします

コンテンツへの2番目の割り当ては、以前は問題なく機能していました。これは、const文字列を指すようにポインタを設定しているためです。コンテンツをmallocされたメモリ領域に変更する場合は、固定文字列をコンテンツにstrncpyすることもできます。

理想的には、C ++ std::stringを使用できる場合。

于 2012-02-09T02:30:15.047 に答える
1

以前の回答は解決策を提案しました:

char content[256];

このバッファは、最小のファイル以外のものを保持するのに十分な大きさではなく、実行時ポインタcontentがスコープ外になりreturn content;ます。content = "static..";(文字列は.rodata データセグメントに配置され、そのポインタはプログラムの存続期間全体にわたって常に同じデータを指すため、前の行は問題ありません。)

でメモリを割り当てるcontentmalloc(3)、で必要なスペースを「増やす」ことができますがrealloc(3)、これは恐ろしいエラーの可能性をもたらします。ポインタを渡したものはすべて、データの割り当て後にメモリ割り当て後にクリーンアップする必要があります(または、メモリリークが発生します) 。ポインタ静的に割り当てられたメモリを指している可能性があるfree(3)ため、単純に呼び出すことはできません。content

したがって、2つの簡単な選択肢があります。

  • 必要になるたびに静的文字列strdup(3)複製するために使用content = malloc(size);し、非静的パスに使用します
  • 発信者にメモリの提供に責任を持たせます。すべての呼び出しは、ファイルの内容または静的文字列のいずれかを処理するのに十分なメモリを提供する必要があります。

2番目のアプローチに必要なサイズが呼び出し前にわからないという理由だけで、私はおそらく最初のアプローチを好むでしょう。

于 2012-02-09T02:39:17.657 に答える