質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • C

    4006questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C言語での文字列の初期化はどうしていますか?

受付中

回答 7

投稿

  • 評価
  • クリップ 3
  • VIEW 25K+

takey

score 275

char str[31+1];
   //配列の先頭をヌル終端すればそれで良い?
   str[0] = '\0';
   //それとも要素すべてにヌル終端する?
   memset(str, '\0', sizeof(str));
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

+6

私は、結論としては、str[0] = '\0';という書き方を薦めます。

まず、静的配列の初期化について。
現在のC言語ではchar str[31+1] = {};という書き方が認められていますが、古いバージョンのCでは、この書き方は認められておらず、{0}としなければなりません。
また、当たり前ですがこの方法は、静的配列でなければ使えません。

次に、memsetを使用する方法。これはどのバージョンのCでも使えますし、すべての要素を確実に0にすることができます。しかしこれにはオーバーヘッドの問題があります。memsetを使うということは、コンパイラがもっと高速な方法を知っていたとしてもそれを使わないと明示してしまうことなのです。
(ほかにも、ゼロクリアと初期化は本質的には違うという問題がありますが、C++プログラマでなければあまり重要ではないかもしれません。)

ではどうすればいいのか。
そこで提案するのが、先頭文字をヌル文字で上書きするという方法です。
ご存じのとおり、こうすればstrは空文字列として扱われます。
静的配列の初期化以外の場面でも使える、万能な方法です。

「この配列がどのように使われるかわからないではないか」という批判は、間違ってはいません。
しかし、strという名前を付けている以上、これは文字列として扱うことが明らかです。
プログラマはユーザーではありません。自分のコードに手を加える人間を全く信用せず、予防的にゼロクリアをするのは、過剰な行動だといえます。ライブラリの都合で、ゼロクリアする必要があるなら、そのときはコメントで補足したうえでゼロクリアすればいいのです。

以下、参考にしたURLです。
http://cpplover.blogspot.jp/2010/09/blog-post_18.html

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/12/17 18:30 編集

    memsetでオールゼロクリアしておく利点として、異常終了時のメモリのダンプ(コアダンプ)をバイナリエディタで直接見る羽目になった時に、ほんの少しだけ見やすくなります。
    auto変数だと前回使用時の内容でメチャクチャですからね。
    普通はgdbなどで見るため問題無いのでしょうが、ごく稀に緊急事態が発生する現場がありました。

    キャンセル

  • 2015/12/18 11:58

    オールゼロクリアでは終端が見つからずに落ちてくれるケースで落ちずに進んでしまう可能性があることにも言及が必要だと思います。そうなるとコアダンプも見れません。

    デバッグ目的ならゼロではなくて先頭以外を0xccなどで埋めるほうが良いと思います。ゼロで埋めてしまうと落ちない可能性が増えてしまいます。予防的なゼロクリアはバグの原因を隠してしまうから良くない、というのがmajiponiさんの主旨だと思います。

    (もちろん、暗号鍵を保存していた文字列・・とかだったら話は別になりますけども)

    キャンセル

  • 2015/12/18 13:14

    私の意図とは若干違いますが、確かに、sharowさんの言うように、バグの隠蔽の問題もありますね(ウチの環境ではデバッグ時に自動変数を0xCCで埋めるオプションを使用しています)。
    私の言いたかったことは、プログラムは本当に必要なこと「だけ」を書くべきであるということです。たとえば、デバッグが終わり、チューニングの過程でゼロクリアがボトルネックと判明したとします。そのゼロクリア、先頭上書きに書き直していいですか? このように、一々神経を遣う必要があります。薬も過ぎれば毒になる、そう伝えたかったのです。

    キャンセル

  • 2015/12/18 15:14 編集

    主旨は言い過ぎでした、すいません。「薬も過ぎれば毒になる」は全面的に同意です。

    キャンセル

+3

「文字列の初期化」という言葉が曖昧だと思います。
「文字列を空文字列にする」だと、str[0] = '\0';だし、
「文字列のエリアをオールゼロにする」だと、memset(str, '\0', sizeof(str));だし。
「文字列を空白(あるいは数字のゼロ)で埋める」だと、また違うことをしないといけないし。

何をしたいのかによって、適切な手段があるかと思います。

「初期化」というと、変数宣言時に値を与えることに限定して捉える人が少なからずだと思いますよ。
それが正しいとは思いませんが。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

原則としては

memset(str, '\0', sizeof(str));

だと思います。

C言語は言語として文字列型をサポートしていませんので、
char str[31+1] が後でどのように使用されるかはわかりません。
(プログラムを書く人しだいです。)

ですので、あくまでも「要素数31+1の char 型配列の初期化」と考えるべきだと思います。

「原則としては」と書きましたが、
スピードを重視するプログラムや配列がとても大きい場合など、
状況に応じてリスクを覚悟したうえで細心の注意を払ってコーディングする前提で、
初期化しなかったり、簡易な初期化で済ますことはあると思いますが、それは例外と考えるべきでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

既に他の回答者の皆様が回答されているとおりですが、
以下、経験上のお話をさせてください。

str[0] = '\0'は、str[0]に直接何か文字をセットしてしまうとNULL終端を失うことになり、バグの原因になりがちです。
memset(str, '\0', sizeof(str))は、ものすごく巨大な文字列だと全てを初期化することになるので、場合によってはパフォーマンスの問題になります。

レベルがまちまちの多くの人が関わってバギーになりがちなプロジェクトでは、安全をとってmemset(str, '\0', sizeof(str))を採用していました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

私は

char str[31+1] = { 0 };


と書いてます。言語仕様的に正しいというのをどこかで読んだか教えてもらいました(ちゃんと調べてないところがまだまだですが)。文字配列に限らず、配列の初期化は上記の書き方をすれば、構造体の配列であっても、適切に初期化されるためです。
また言語仕様的には下記のような書き方も可能らしいです。個人的には使っていませんがご参考まで。

char str[31+1] = { };

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

こんにちは。

振り返ってみると、スキル的にNULL終端をし忘れそうな時は、memset(str, '\0', sizeof(str));してました。ある程度Cに熟練してきて、それがあり得なくなったらstr[0] = '\0';を使ってました。

今は、変数についてはCの文字列を使いません。C++のstd::stringがほとんどです。
定数についてはCの文字列が軽いので良く使いますけど、定数だから「初期化」の概念はないです。
(std::const_stringが欲しい!!)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

char配列を文字列領域として使うことが前提なら、「初期化」でしたらこんな感じです。

char str[31+1] = "";    // = {0};でもいいけど、この方が文字列っぽさを表現できる


「空文字列にしたい」というのであれば、

str[0] = '\0';


です。
基本的にmemsetは使わないことにしています。


追記
最近(というか21世紀に入ってから)は純粋なC言語を使うことがなくなったので、使い捨てのバッファー領域でもない限り、Chironianさん同様、char配列を文字列として使うことはなくなりましたね。STLコンテナのarrayはたまに使います。

std::array<char, 31+1> str;
str.fill('\0');  // 全クリア

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C

    4006questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。