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

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

新規登録して質問してみよう
ただいま回答率
85.49%
C

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

Q&A

8回答

100954閲覧

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

takey

総合スコア312

C

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

2グッド

6クリップ

投稿2015/12/17 05:17

C

1 char str[31+1]; 2 //配列の先頭をヌル終端すればそれで良い? 3 str[0] = '\0'; 4 //それとも要素すべてにヌル終端する? 5 memset(str, '\0', sizeof(str));
raccy, kozuchi👍を押しています

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2023/03/10 07:31

で、しつもんはなんでしょうか
guest

回答8

0

私は、結論としては、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 06:13

majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/12/17 09:30 編集

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

2015/12/18 02:58

オールゼロクリアでは終端が見つからずに落ちてくれるケースで落ちずに進んでしまう可能性があることにも言及が必要だと思います。そうなるとコアダンプも見れません。 デバッグ目的ならゼロではなくて先頭以外を0xccなどで埋めるほうが良いと思います。ゼロで埋めてしまうと落ちない可能性が増えてしまいます。予防的なゼロクリアはバグの原因を隠してしまうから良くない、というのがmajiponiさんの主旨だと思います。 (もちろん、暗号鍵を保存していた文字列・・とかだったら話は別になりますけども)
majiponi

2015/12/18 04:14

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

2015/12/18 06:14 編集

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

2019/08/01 09:48

私もここの意見に一票。 実際、デバッグ目的で0以外の値で塗りつぶすmemset()することは良くある。それは即ち、バグを取ってしまえば memset()の必要は無いという事。memset() 或いはオール0にしておかないと動かないなら、重大なバグを残したままだと言ってるように聞こえます。
guest

0

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

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

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

投稿2015/12/17 06:24

otn

総合スコア84498

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/08/01 10:10

妥当な初期値とは何をしたいかに依る,だと思うのでこの回答の高評価を押す. 場合によっては初期化しない(明示的に初期値を与えない)でも良いのかもしれないし.
guest

0

C

1 // コードの意図が: 2 // strを文字列として扱うなら 3 str[0] = '\0'; 4 // char配列として扱うなら 5 memset(str, '\0', sizeof(str));

投稿2019/08/01 10:08

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2019/08/01 14:40

文字列と言っても、そのまま、バッファ領域として使うコードを結構見ているので、単純に先頭のみ、クリアは納得できないので、こっちかと思う。
guest

0

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

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

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

投稿2015/12/17 07:50

argius

総合スコア9388

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

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

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

投稿2015/12/17 07:21

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

原則としては

C

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

だと思います。

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

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

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

投稿2015/12/17 05:57

kozuchi

総合スコア1193

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

C

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

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

C

1str[0] = '\0';

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


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

C++

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

投稿2015/12/17 10:13

編集2015/12/17 10:24
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

私は

c

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

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

c

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

投稿2015/12/17 05:52

編集2015/12/17 05:55
KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問