web-dev-qa-db-ja.com

charポインタの初期化

文字列を格納するために使用されるcharポインタがあります。プログラムの後半で使用されます。

私は次のように宣言して初期化しました:

char * p = NULL;

これが良い習慣かどうか疑問に思っています。 gcc4.3.3を使用しています。

13
ant2009

はい、それは良い考えです。 Googleコードスタイル 推奨:

  1. 今は必要ない場合でも、すべての変数を初期化するため。
  2. 読みやすくするために、ポインタをNULLintを0、floatを0.0で初期化します。

    int i = 0;
    double x = 0.0;
    char* c = NULL;
    
14
f0b0s

すべての変数を初期化することをお勧めします。

文字列をポインタに格納することはできません。

_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 */
}
_
4
pmg

もう1つのオプションは、コード内で初期値にアクセスできる場所まで変数を定義しないことです。だからではなく:

char *name = NULL;

...

name = initial_value;

私はそれを次のように変更します:

...

char *name = initial_value;

コンパイラーは、コードの値がない部分で変数を参照できないようにします。コードの詳細によっては、これが常に可能であるとは限りません(たとえば、初期値は内部スコープに設定されますが、変数の有効期間は異なります)。コード内で定義をできるだけ遅く移動すると、エラーが防止されます。

とは言うものの、これはc99標準からのみ許可されています(これは有効なC++でもあります)。 gccでc99機能を有効にするには、次のいずれかを行う必要があります。

gcc -std=gnu99

または、標準のgcc拡張機能が必要ない場合:

gcc -std=c99
3

必要かどうか、または後で他の変数に設定する前に変数をNULLに初期化することをお勧めするかどうかを尋ねる場合:変数をNULLに初期化する必要はありません。プログラムの機能に違いはありません。

プログラミングでは、コードのすべての行を理解することが重要であることに注意してください-なぜそこにあるのか、そしてそれが正確に何をしているのか。それらが何を意味するのかを知らずに、またはあなたがそれらをしている理由を理解せずに物事をしないでください。

3
Jesper

いいえ、あなたの文脈を正しく理解していれば、それは良い習慣ではありません。

コードが実際にnullポインタの初期値を持つmgt_dev_nameに依存している場合は、もちろん、宣言に初期化子を含めることは非常に良い考えです。つまりとにかくこれをしなければならないなら

char *mgt_dev_name;

/* ... and soon after */
mgt_dev_name = NULL;

その場合、割り当ての代わりに初期化を使用することをお勧めします

char *mgt_dev_name = NULL;

ただし、初期化は、オブジェクトを意味のある便利なの値で初期化できる場合にのみ有効です。実際に必要な値。一般的に、これはコードの任意の時点で宣言を許可する言語でのみ可能であり、C99およびC++はそのような言語の良い例です。オブジェクトが必要になるまでに、通常はそのオブジェクトに適切な初期化子をすでに知っているので、優れた初期化子を使用してエレガントな宣言を簡単に思い付くことができます。

一方、C89/90では、宣言はブロックの先頭にのみ配置できます。その時点で、一般的に、すべてのオブジェクトに対して意味のある初期化子を使用することはできません。それらを何かで初期化する必要がありますか(0NULLなど)、それらを取得するためだけに初期化?番号!!!コードで無意味なことをしないでください。さまざまな「スタイルガイド」があなたに何を教えても、それは何も改善しません。実際には、無意味な初期化によってコードのバグがカバーされ、バグの発見と修正が困難になる可能性があります。

C89/90でも、宣言の局所性を高めるために努力することは常に有益であることに注意してください。つまりよく知られているグッドプラクティスガイドラインには、変数をできるだけローカルにすることが記載されています。関数の最初にすべてのローカルオブジェクト宣言を積み上げるのではなく、オブジェクトの存続期間全体を可能な限りしっかりと包み込む最小のブロックの最初に移動します。宣言の局所性を改善するためだけに、架空の、そうでなければ不要なブロックを導入することも良い考えかもしれません。この方法に従うと、多くの場合(ほとんどではないにしても)、オブジェクトに便利な初期化子を提供するのに役立ちます。ただし、一部のオブジェクトは、宣言の時点で適切な初期化子がないという理由だけで、C89/90では初期化されないままになります。初期化するためだけに「何か」で初期化しようとしないでください。これはまったく良いことを達成せず、実際には悪い結果をもたらす可能性があります。

一部の最新の開発ツール(MS Visual Studio 2005など)は、デバッグバージョンのコードで初期化されていない変数への実行時アクセスをキャッチすることに注意してください。つまり、これらのツールは、変数が意味のある値を取得する前に変数にアクセスしたときの状況を検出するのに役立ち、コードのバグを示します。しかし、変数の無条件の時期尚早な初期化を実行すると、本質的にツールのその機能を無効にし、カーペットの下でこれらのバグを一掃します。

3
AnT

このトピックはすでにここで説明されています:

http://www.velocityreviews.com/forums/t282290-how-to-initialize-a-char.html

これはC++を指しますが、あなたにも役立つかもしれません。

2
Roberto Aloi

推奨されるスタイル:

cで:char * c = NULL;

c ++の場合:char * c = 0;

0
stefanB

私の理論的根拠は、NULLで初期化せず、完全に初期化するのを忘れると、間接参照時にコードに発生するバグの種類を追跡するのがはるかに困難になるということです。その時点でのメモリ。一方、NULLに初期化すると、ほとんどの場合、segmentation faultしか取得できません。これは、代替案を考慮すると、より優れています。

0
Dervin Thunk

以下に示すように、C++でポインタ変数を初期化することは常に良いことです。

int *iPtr = nullptr;
char *cPtr = nullptr;

nullptrboolに変換可能であるため、上記のように初期化すると以下のような状態になります。そうしないと、コードがコンパイル警告または未定義の動作をスローすることになります。

if(iPtr){
   //then do something.
}

if(cPtr){
  //then do something.
}
0

変数をすぐに初期化する必要がない場合でも、変数を初期化することをお勧めします。通常、ポインタをNULLに、intを0に、浮動小数点数を0.0に初期化します。

int* ptr = NULL;
int i = 0;
float r = 0.0;
0
Madhav Datt

この質問にはいくつかの良い答えがあり、そのうちの1つが受け入れられました。とにかく実用性を広げるためにお答えします。

はい、ポインタをNULLに初期化すること、およびポインタが不要になった後(つまり解放された後)にNULLに設定することをお勧めします。

いずれの場合も、ポインターを逆参照する前にポインターをテストできることは非常に実用的です。次のような構造があるとします。

struct foo {
    int counter;
    unsigned char ch;
    char *context;
};

次に、相互排除を使用して、割り当てられた単一のfoo構造で(安全に)動作する複数のスレッドを生成するアプリケーションを作成します。

スレッドAはfooのロックを取得し、カウンターをインクリメントして、chの値をチェックします。見つからないため、コンテキストを割り当て(または変更)しません。代わりに、スレッドBが代わりにこの作業を実行できるように、chに値を格納します。

スレッドBカウンターがインクリメントされたことを確認し、chの値を記録しますが、スレッドAがコンテキストで何かを行ったかどうかはわかりません。コンテキストがNULLとして初期化された場合、スレッドBはスレッドAが何をしたかを気にする必要がなくなり、コンテキストがリークせずに逆参照(NULLでない場合)または割り当て(NULLの場合)しても安全であることがわかります。

スレッドBはビジネスを行い、スレッドAはコンテキストを読み取り、解放してから、NULLに再初期化します。

同じ理由が、スレッドを使用せずにグローバル変数に適用されます。それらを逆参照する前に(またはそれらを割り当てようとして、プログラムでリークや未定義の動作を引き起こす)前に、さまざまな関数でそれらをテストできるのは良いことです。

それがばかげているのは、ポインタのスコープが単一の関数を超えていないときです。関数が1つあり、その中のポインターを追跡できない場合、通常、これは関数をリファクタリングする必要があることを意味します。ただし、均一な習慣を維持するためだけであれば、単一の関数でポインターを初期化しても問題はありません。

初期化されたポインタ(使用前と使用後)に依存する「醜い」ケースを見たのは、次のような場合だけです。

void my_free(void **p)
{
    if (*p != NULL) {
        free(*p);
        *p = NULL;
    }
}

厳密なプラットフォームで型のパンニングされたポインターを逆参照するだけでなく、呼び出し元が安全性についてある程度の妄想を抱くため、上記のコードはfree()をさらに危険なものにします。すべての操作が一致していることが確実でない限り、「卸売り」の実践に頼ることはできません。

おそらくあなたが実際に望んでいたよりもはるかに多くの情報。

0
Tim Post