文字列を格納するために使用される char ポインターがあります。これは、プログラムの後半で使用されます。
私は次のように宣言して初期化しました:
char * p = NULL;
これが良い習慣かどうか疑問に思っています。gcc 4.3.3 を使用しています。
文字列を格納するために使用される char ポインターがあります。これは、プログラムの後半で使用されます。
私は次のように宣言して初期化しました:
char * p = NULL;
これが良い習慣かどうか疑問に思っています。gcc 4.3.3 を使用しています。
はい、それは良い考えです。 Google Code Style の推奨事項:
読みやすくするために、ポインタをNULL
、int
を 0 、を 0.0 で初期化します。float
int i = 0;
double x = 0.0;
char* c = NULL;
すべての変数を初期化することをお勧めします。
文字列をポインターに格納することはできません。
の定義mgt_dev_name
は適切ですが、文字列用のスペースのある場所を指す必要があります。そのスペースかmalloc()
、以前に定義された文字の配列を使用します。
char *mgt_dev_name = NULL;
char data[4200];
/* ... */
mgt_dev_name = data; /* use array */
/* ... */
mgt_dev_name = malloc(4200);
if (mgt_dev_name != NULL) {
/* use malloc'd space */
free(mgt_dev_name);
} else {
/* error: not enough memory */
}
それが必要かどうか、または変数をNULL
後で別のものに設定する前に初期化するのが良い考えかどうかを尋ねている場合: に初期化する必要NULL
はありません。プログラム。
プログラミングでは、コードのすべての行を理解することが重要であることに注意してください-なぜそれがそこにあり、正確に何をしているのか. 意味を理解せずに、またはなぜそれを行っているのかを理解せずに、物事を行ってはなりません。
別のオプションは、変数の初期値にアクセスできるコード内の場所まで変数を定義しないことです。ではなく、次のようにします。
char *name = NULL;
...
name = initial_value;
私はそれを次のように変更します:
...
char *name = initial_value;
コンパイラは、値のないコードの部分で変数を参照できないようにします。コードの詳細によっては、これが常に可能であるとは限りません (たとえば、初期値は内部スコープに設定されていますが、変数の有効期間は異なります)。定義をコード内でできるだけ遅く移動すると、エラーを防ぐことができます。
とは言っても、これは c99 標準以降でのみ許可されています (これは有効な C++ でもあります)。gcc で c99 機能を有効にするには、次のいずれかを行う必要があります。
gcc -std=gnu99
または、gcc 拡張機能を標準に加えたくない場合:
gcc -std=c99
いいえ、あなたの文脈を正しく理解していれば、それは良い習慣ではありません.
mgt_dev_name
コードがnull ポインターの初期値を持つことに実際に依存している場合、もちろん、初期化子を宣言に含めることは非常に良い考えです。つまり、とにかくこれを行う必要がある場合
char *mgt_dev_name;
/* ... and soon after */
mgt_dev_name = NULL;
その場合は、割り当ての代わりに初期化を使用することを常にお勧めします
char *mgt_dev_name = NULL;
ただし、初期化は、意味のある 有用な値でオブジェクトを初期化できる場合にのみ有効です。実際に必要になる値。一般に、これはコード内の任意の場所で宣言を許可する言語でのみ可能であり、C99 と C++ はそのような言語の良い例です。通常、オブジェクトが必要になるまでには、そのオブジェクトに適した初期化子を既に知っているため、適切な初期化子を使用して洗練された宣言を簡単に思いつくことができます。
一方、C89/90 では、宣言はブロックの先頭にしか置くことができません。その時点で、一般的に、すべてのオブジェクトに対して意味のある初期化子を使用できるわけではありません。それらを初期化するためだけに、何か(0
またはなどNULL
)でそれらを初期化する必要がありますか?いいえ!!!コード内で無意味なことをしないでください。さまざまな「スタイルガイド」が何を教えてくれるかに関係なく、何も改善しません。実際には、無意味な初期化によってコード内のバグが隠蔽され、バグの発見と修正が難しくなる可能性があります。
C89/90 でも、宣言の局所性を向上させるために努力することは常に有益であることに注意してください。つまり、よく知られているグッド プラクティス ガイドラインでは、次のように述べられています。変数は常に可能な限りローカルにします。関数の最初にすべてのローカル オブジェクト宣言を積み上げないでください。代わりに、オブジェクトの有効期間全体をできるだけしっかりと包み込む最小のブロックの先頭に移動してください。場合によっては、宣言の局所性を改善するためだけに、架空の、そうでなければ不要なブロックを導入することをお勧めします。このプラクティスに従うと、多くの場合 (ほとんどではないにしても)、オブジェクトに優れた便利な初期化子を提供するのに役立ちます。ただし、一部のオブジェクトは、宣言の時点で適切な初期化子がないという理由だけで、C89/90 で初期化されないままになります。ドン' それらを初期化するためだけに、「何か」でそれらを初期化しようとします。これはまったく良い結果をもたらさず、実際にはマイナスの結果をもたらす可能性があります。
一部の最新の開発ツール (たとえば、MS Visual Studio 2005 など) は、コードのデバッグ バージョンで初期化されていない変数へのランタイム アクセスをキャッチすることに注意してください。つまり、これらのツールは、変数が意味のある値を取得する前に変数にアクセスした場合に、コードのバグを示す状況を検出するのに役立ちます。しかし、変数の無条件の時期尚早な初期化を実行すると、本質的にツールのその機能が無効になり、これらのバグがカーペットの下に一掃されます。
このトピックはすでにここで議論されています:
http://www.velocityreviews.com/forums/t282290-how-to-initialize-a-char.html
これは C++ を指していますが、あなたにも役立つかもしれません。
好ましいスタイル:
Cで:char * c = NULL;
C++ で:char * c = 0;
変数をすぐに初期化する必要がない場合でも、変数を初期化することをお勧めします。通常、ポインタを NULL に、int を 0 に、float を 0.0 に初期化します。
int* ptr = NULL;
int i = 0;
float r = 0.0;
この質問にはいくつかの適切な回答があり、そのうちの 1 つが受け入れられています。とにかく、実用性を拡大するために答えます。
はい、ポインターを NULL に初期化し、不要になった (つまり解放された) ポインターを NULL に設定することをお勧めします。
どちらの場合でも、逆参照する前にポインターをテストできることは非常に実用的です。次のような構造があるとします。
struct foo {
int counter;
unsigned char ch;
char *context;
};
次に、複数のスレッドを生成するアプリケーションを作成します。これらのスレッドはすべて、相互排除を使用して、割り当てられた 1 つの foo 構造体で (安全に) 動作します。
スレッド A は foo のロックを取得し、カウンターをインクリメントして、ch の値をチェックします。見つからないため、コンテキストを割り当て (または変更) しません。代わりに、スレッド B が代わりにこの作業を実行できるように、ch に値を格納します。
スレッド B カウンターがインクリメントされたことを確認し、ch の値を記録しますが、スレッド A がコンテキストで何かを行ったかどうかはわかりません。コンテキストが NULL として初期化された場合、スレッド B はスレッド A が何をしたかを気にする必要がなくなり、コンテキストが安全に逆参照 (NULL でない場合) または割り当て (NULL の場合) できることを認識します。
スレッド B が処理を行い、スレッド A がそのコンテキストを読み取り、解放してから、NULL に再初期化します。
同じ理由が、スレッドを使用しないグローバル変数にも当てはまります。それらを逆参照する前に(またはそれらを割り当てようとして、プログラムでリークや未定義の動作を引き起こします)、さまざまな関数でそれらをテストできるのは良いことです。
ばかげているのは、ポインターのスコープが単一の関数を超えていない場合です。単一の関数があり、その中のポインターを追跡できない場合、通常、これは関数をリファクタリングする必要があることを意味します。ただし、一貫した習慣を維持するためだけであれば、単一の関数でポインターを初期化することに問題はありません。
初期化されたポインター (使用前と使用後) に依存する「醜い」ケースを見たのは、次のような場合だけです。
void my_free(void **p)
{
if (*p != NULL) {
free(*p);
*p = NULL;
}
}
厳密なプラットフォームでは、タイプのしゃれのあるポインターの逆参照が嫌われるだけでなく、上記のコードは free() をさらに危険なものにします。すべての操作が一致していることを確信していない限り、「卸売り」の実践に頼ることはできません。
おそらく、あなたが実際に望んでいたよりもはるかに多くの情報です。
私の理論的根拠は、 で初期化せずNULL
、完全に初期化するのを忘れた場合、逆参照時にコードで発生する種類のバグは、その時点でメモリに保持される潜在的なガベージのために追跡するのがはるかに困難になるということです。一方、 に初期化するとNULL
、ほとんどの場合、 しか得られませんsegmentation fault
。これは、別の方法を考えると、より優れています。
以下に示すように、C++ でポインター変数を初期化することは常に適切です。
int *iPtr = nullptr;
char *cPtr = nullptr;
nullptrはboolに変換可能であるため、上記のように初期化すると以下のような状況で役立ちます。そうしないと、コードがコンパイル警告または未定義の動作をスローすることになります。
if(iPtr){
//then do something.
}
if(cPtr){
//then do something.
}