8
int main()
{
    char *p;
    p = (char* ) malloc(sizeof(char) * 0);
    printf("Hello Enter the data without spaces :\n");
    scanf("%s",p);
    printf("The entered string is %s\n",p);
    //puts(p);
}

上記のコードをコンパイルして実行すると、ポインタpに0バイトのメモリを割り当てても、プログラムは文字列を読み取ることができます。

ステートメントで実際に何が起こりp = (char* ) malloc(0)ますか?

4

3 に答える 3

12

malloc()何が返されるかは実装定義ですが、そのポインタを使用するのは未定義の動作です。また、未定義動作とは、プログラムがグリッチなしで動作することからクラッシュまで、文字通り何でも起こり得ることを意味し、すべての安全な賭けは無効になります。

C99標準:

7.22.3メモリ管理機能
パラ1:

要求されたスペースのサイズがゼロの場合、動作は実装定義です。nullポインターが返されるか、返されたポインターがオブジェクトへのアクセスに使用されないことを除いて、サイズがゼロ以外の値であるかのように動作します。 。

于 2012-05-21T11:43:46.040 に答える
0

Alsのコメントに加えて、何が起こるか:メモリのどこかに書き込み、そこからデータを取得します。したがって、システムとOSの種類に応じて、例外または未定義の動作が発生します。

于 2012-05-21T12:29:14.380 に答える
0

好奇心から、Linuxでgccを使用してコードをテストしましたが、予想よりもはるかに堅牢です(結局、長さ0の文字バッファーへのデータの書き込みは未定義の動作です...クラッシュすると予想されます) 。

これがあなたのコードの私の修正です:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char *p;
    p = malloc(sizeof(char)*0);
    printf("Hello Enter some without spaces :\n");
    scanf("%s",p);

    char *q;
    q = malloc(sizeof(char)*0);
    printf("Hello Enter more data without spaces :\n");
    scanf("%s",q);

    printf("The first string is '%s'\n",p);
    printf("The second string is '%s'\n",q);
}

私の最初の考えは、単一のメモリ位置にデータを読み取るだけであるという事実によって救われるかもしれないということでした-2つのバッファを使用する場合、2番目が最初を上書きする可能性があります...それでコードを入力と出力に分割しましたセクション:

Hello Enter some without spaces :
asdf
Hello Enter more data without spaces :
tutututu
The first string is 'asdf'
The second string is 'tutututu'

最初のバッファが上書きされた場合、次のようになります。

The first string is 'tutututu'
The second string is 'tutututu'

そうではありません。[ただし、これは各バッファにパックするデータの量によって異なります...以下を参照してください]

次に、クレイジーな量のデータを両方の変数に貼り付けました。

perl -e 'print "c" x 5000000 . "\n" ' | xsel -i

(これにより、4 MB以上の「c」がコピーバッファに入れられます)。これを最初と2番目のscanf呼び出しの両方に貼り付けました。プログラムは、セグメンテーション違反なしでそれを取りました。

セグメンテーション違反はありませんでしたが、最初のバッファ上書きされました。大量のデータが画面に表示されたため、わかりませんでした。データが少ない実行は次のとおりです。

$ ./foo
Hello Enter some without spaces :
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Hello Enter more data without spaces :
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
The first string is 'aaaaaaaaaaaa'
The second string is 'ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'

aaaaaaaaaaaaの後に小さなグリフがありました。これは、私の端末が表示できないユニコード文字を表す方法です。これは、上書きされたデータの典型的な例です。データを上書きする内容がわからない...未定義の動作であるため、鼻の悪魔になりがちです。

肝心なのは、スペースを割り当てていないメモリに書き込むと(mallocを明示的に使用するか、配列を暗黙的に使用する)、火遊びをしているということです。遅かれ早かれ、あなたは記憶を上書きし、あなた自身にあらゆる種類の悲しみを引き起こします。

ここでの本当の教訓は、Cは境界チェックを行わないということです。それはあなたが所有していない記憶にあなたが喜んで書くことを可能にするでしょう。あなたは一日中それをすることができます。プログラムは正しく実行される場合と実行されない場合があります。クラッシュしたり、破損したデータを書き戻したり、テスト中に使用したバイト数より1バイト多くスキャンするまで機能する場合があります。それは気にしないので、あなたはそうしなければなりません。

の場合は、この質問malloc(0)の特殊な場合です。

于 2012-05-21T13:35:59.237 に答える