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

void main()
{
char *arr;
arr=(char *)malloc(sizeof (char)*4);
scanf("%s",arr);
printf("%s",arr);
}

上記のプログラムでは、本当に arr を割り当てる必要がありますか? mallocを使用しなくても結果が得られます。私の 2 番目の疑問は、' 9 行目にエラーがあると予想しているのは、それが printf("%s",*arr); か何か。

4

4 に答える 4

5

本当にarrを割り当てる必要がありますか?

はい、それ以外の場合は、未定義の動作である初期化されていないポインター (つまり、メモリのランダムなチャンクへの書き込み) を逆参照しています。

于 2013-02-06T11:48:29.030 に答える
0

本当にarrを割り当てる必要がありますか?

呼び出すか、別の配列を指すように設定することによりarr、所有するメモリのブロックを指すように設定する必要があります。mallocそれ以外の場合は、アクセスできる場合とできない場合があるランダムなメモリアドレスを指します。

C では、 の結果をキャストすることmallocはお勧めできません1。これは不要であり、含めるのを忘れた場合やスコープ内 stdlib.hにプロトタイプがない場合、エラーを隠すことができる場合があります。malloc

通常、malloc呼び出しは次のように書くことをお勧めします

T *ptr = malloc(N * sizeof *ptr);

whereTは使用してNいる型であり、割り当てたいその型の要素の数です。 sizeof *ptrは と同等sizeof (T)であるため、 を変更した場合でも、呼び出し自体Tでその変更を複製する必要はありません。mallocメンテナンスの頭痛が 1 つ減ります。

mallocを使用しなくても結果が得られます

宣言で明示的に初期化しないため、 の初期値arr不確定2です。有効な書き込み可能なアドレスに対応する場合と対応しない場合があるランダムなビット文字列が含まれています。無効なポインターを介して読み取りまたは書き込みを試行した場合の動作はundefinedです。つまり、コンパイラーは、ユーザーが何か危険なことをしていることを警告する義務を負いません。未定義の動作の考えられる結果の 1 つは、コードが意図したとおりに動作しているように見えることです。この場合、たまたま書き込み可能で、重要なものが何も含まれていないランダムなメモリ セグメントにアクセスしているように見えます。

私の 2 番目の疑問は、' 9 行目にエラーがあると予想しているのは、それが printf("%s",*arr); か何か。

%s変換指定子は、printf対応する引数が typechar *であることを示してprintf("%s", arr);いるため、正しいです。変換指定子を使用した場合は、そうです。演算子またはorなどの添字を使用%cして逆参照する必要があります。 arr*printf("%c", *arr);printf("%c", arr[i]);

また、コンパイラのドキュメントに有効な署名として明示的に記載されていない限り、 asとして定義しないでください。または代わりに 使用します。mainvoid main()int main(void)int main(int argc, char **argv)


void *1. C++ では、明示的なキャストなしに他のポインター型に値を割り当てることができないため、C++ ではキャストが必要です
。 2. これは、ブロック スコープで宣言されたポインターに当てはまります。ファイル スコープ (関数の外部) またはstaticキーワードで宣言されたポインターは、暗黙的に NULL に初期化されます。

于 2013-02-06T18:26:27.583 に答える
0
  • In the above program, do I really need to allocate the arr?

あなたはそうするに違いない。


  • It is giving me the result even without using the malloc.

確かに、それは完全に可能です...arrはポインターです。メモリの場所を指します。何かを行う前は、初期化されていないため、ランダムなメモリ位置を指しています。ここで重要なのは、それが指している場所は、プログラムが所有することが保証されていない場所です。つまり、値を指してscanf()いるランダムな場所で and を実行できますが、別のプログラムがそのデータを上書きする可能性があります。arr

malloc(X)他の誰も触れられない自分の使用のために X バイトのメモリが必要であることをコンピュータに伝えていると言うとき。次にarr、データをキャプチャすると、呼び出すまで安全に使用できますfree()プログラムで行うのを忘れていました

これは、ポインターを作成するときに常にポインターを初期化する必要がある理由の良い例ですNULL...ポインターが指しているものを所有していないことを思い出させ、それらを使用する前に有効なものを指すようにします。


  • I am expecting an error in 9th line because I think it must be printf("%s",*arr)

正しくない。scanf()指しているアドレスがarr必要なため、実行する必要はありません: scanf("%s", &arr)。そして、printf の "%s" スペシフィエは、文字配列 (文字列へのポインター) をarr必要としているため、これを参照する必要はありません。

于 2013-02-06T12:10:50.200 に答える
0

個人的には、これはメモリ割り当ての非常に悪い例だと思います。

Achar *は、最新の OS/コンパイラでは少なくとも 4 バイト、64 ビット マシンでは 8 バイトを占めます。したがって、4 バイトを使用して、3 文字の文字列の 4 バイトの位置を格納します。それだけでなく、malloc にはオーバーヘッドがあり、実際に割り当てられたメモリにおそらく 16 ~ 32 バイトが追加されます。つまり、4 バイトを格納するために 20 から 40 バイトのようなものを使用しています。これは、実際に必要な量の 5 ~ 10 倍です。

このコードは malloc もキャストしますが、これは C では間違っています。

また、バッファー内に 4 バイトしかないため、scanfオーバーフローの可能性がかなり高くなります。

free最後に、メモリをシステムに返すための呼び出しはありません。

使用する方がはるかに良いでしょう:

int len;
char arr[5];
fgets(arr, sizeof(arr), stdin);
len = strlen(arr);
if (arr[len] == '\n') arr[len] = '\0';

これにより、文字列がオーバーフローせず、4 ~ 8 バイトのスタックスペースとヒープ上でかなり多くのスタックスペースではなく、9 バイトのスタックスペースのみが使用されます (パディングはカウントされません...)。改行を許可するように、配列に余分な文字を追加しました。fgets が追加する改行を削除するコードも追加しました。そうしないと、誰かが文句を言うでしょう。

于 2013-02-06T12:04:41.937 に答える