🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

4回答

1973閲覧

プログラムの解読の方法を細部まで丁寧に教えてください。

carnage0216

総合スコア194

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

2クリップ

投稿2021/01/31 05:41

編集2021/01/31 05:51
#include <stdio.h> #include <string.h> void main(void){ char str[] = "str == NULL ? \"(NULL)\" : str"; char *p; p = strtok(str, "?:"); while(p) { printf("|%s|\n", p); p = strtok(NULL, "?:"); } }

*char str[] = "str == NULL ? "(NULL)" : str";
はstr == NULL ? "(NULL)" : strという文字列をchar str[] に入れる。
char p;はポインタ。
p = strtok(str, "?:");はstrに入っている?:をpに代入する。
while(p) とprintf("|%s|\n", p);よりpに代入された?:が|?:|と表示される。
p = strtok(NULL, "?:");より、NULLを?:にして、pに代入する。
という処理かと思ったのですが、まったく違うようで処理結果は以下の通りでした。

/* 出力例: |str == NULL | | "(NULL)" | | str| */

どうかどの部分が間違っているのか細かく教えて頂けないでしょうか?
逆に上の文章で合っている部分はあるでしょうか?

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

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

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

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

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

guest

回答4

0

strtok関数の意味を調べずに勝手に思い込みで解釈している点が間違っています。

関数の意味はちゃんと調べましょう。
ここ→ Man page of STRTOK

リファレンスを読みこなせないときは、「strtok サンプル」とかで検索すると良いです。

投稿2021/01/31 05:50

otn

総合スコア85882

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

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

carnage0216

2021/01/31 05:52

ありがとうございます。 strtok関数は文字列から指定されたトークンを取り出すという働きでしょうか?
otn

2021/01/31 06:00 編集

いいえ。 リファレンスの説明欄を読んでますか??
episteme

2021/01/31 08:38 編集

「指定されたトークンを取り出す」ではない。 「(第二引数で指定された)区切り文字 に 挟まれた部分文字列(トークン) を 返す」もしくは 「(第二引数で指定された)区切り文字 を 含まない(最長の)部分文字列(トークン) を 返す」なら〇
otn

2021/01/31 08:26

> 指定されたトークンを取り出す 「指定した1文字の直前までの文字列(トークン)を取り出す」 です。
episteme

2021/01/31 09:17

厳密には「指定した1文字の直前までの文字列(トークン)を取り出す」はチョットちがう。 strtok("...ABC...", ".") だと "ABC" が返るので。
otn

2021/01/31 09:58 編集

あ、先頭が指定文字だったケースですね。質問コード見ながら書いたので、失念してました。 誤り指摘ありがとうございます。
guest

0

C

1#include <stdio.h> 2#include <string.h> 3 4int main(void) 5{ 6 char str[] = "abcd?ef:ghi"; 7 char *p; 8 p = strtok(str, "?:"); 9 while(p) { 10 printf("[%s]\n", p); 11 p = strtok(NULL, "?:"); 12 } 13}

実行結果

text

1[abcd] 2[ef] 3[ghi]

p = strtok(str, "?:");
strtok は、str の先頭から '?' または ':' を探します。
str[4] で '?' が見つかり、これを '\0' に書き換えます。
これにより文字列は "abcd" と "ef:ghi" に分割されました。
strtok の内部の静的なポインタ変数に "ef:ghi" の先頭アドレスを記憶します。
最後に "abcd" の先頭アドレスを呼び出し元に返します。

p は "abcd" を指すようになりました。

p は NULL ではないので、while (p) { によりループの中に入ります。
そして、printf("[%s]\n", p);[abcd] が表示されます。

p = strtok(NULL, "?:");
strtok は、第1引数が NULL なので、内部の静的なポインタ変数の指す文字列
"ef:ghi" の先頭から '?' または ':' を探します。
':' が見つかり、これを '\0' に書き換えます。
これにより文字列は "ef" と "ghi" に分割されました。
strtok の内部の静的なポインタ変数に "ghi" の先頭アドレスを記憶します。
最後に "ef" の先頭アドレスを呼び出し元に返します。

p は "ef" を指すようになりました。

p は NULL ではないので、while (p) { によりループの中に入ります。
そして、printf("[%s]\n", p);[ef] が表示されます。

p = strtok(NULL, "?:");
strtok は、第1引数が NULL なので、内部の静的なポインタ変数の指す文字列
"ghi" の先頭から '?' または ':' を探します。
'?' も ':' も見つからず、文字列の最後の '\0' に達しました。
strtok の内部の静的なポインタ変数を NULL にします。
最後に "ghi" の先頭アドレスを呼び出し元に返します。

p は "ghi" を指すようになりました。

p は NULL ではないので、while (p) { によりループの中に入ります。
そして、printf("[%s]\n", p);[ghi] が表示されます。

p = strtok(NULL, "?:");
strtok は、第1引数が NULL なので、内部の静的なポインタ変数を見ます。
それが NULL なので、もう '?' または ':' を探すことができません。
NULL を呼び出し元に返します。

p は NULL になりました。

p が NULL なので、 whileループは終了しました。

追記

strに入っている?:をpに代入する。

ポインタの理解が不十分です。

ポインタに文字列を代入することはできません。
ポインタに代入できるのはアドレスです。

char *p; p = "abc"; の場合、
文字列 "abc" の先頭の 'a' のアドレスが p に代入されます。
p は 'a' を指しますが、先頭だから "abc" を指すといってもいいでしょう。

投稿2021/01/31 06:53

編集2021/01/31 07:20
kazuma-s

総合スコア8224

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

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

carnage0216

2021/01/31 08:51

なるほど、pにより文字列のアドレスを探し、prntfにより アドレスに入った文字列が表示されるとわかりました。 すごくわかりやすいです。
kazuma-s

2021/01/31 08:57

分かっていませんね。p はアドレスを探しません。 strtok が切り出した文字列のアドレスを保持するだけです。 アドレスに文字列は入っていません。 アドレスは文字列の先頭の位置を示す値です。
guest

0

逆に上の文章で合っている部分はあるでしょうか?

  1. char str[] = "str == NULL ? "(NULL)" : str"; は str == NULL ? "(NULL)" : strという文字列をchar str[] に入れる。
  2. char *p;はポインタ。
  3. p = strtok(str, "?:");はstrに入っている?:をpに代入する。
  4. while(p) とprintf("|%s|\n", p);よりpに代入された?:が|?:|と表示される。
  5. p = strtok(NULL, "?:");より、NULLを?:にして、pに代入する。

1: まぁ、そのとおり
2: そのとおり
3: まちがい。 '?'と':'を区切り文字とするのだから、pには'?',':'が含まれることはない。
4: 3がまちがいなのでまちがい
5: まちがい。

[追記/ご参考] strtokを自前で書くとこんなかんじ:

C

1// 文字列strから文字cを探し、最初に見つかった位置(ポインタ)を返す。 2// 見つからなかったらNULLを返す。 3const char* my_strchr(const char* str, int c) { 4 while ( *str != '\0' && *str != c ) ++str; 5 return *str == '\0' ? NULL : str; 6} 7 8// strtokを自作したら、こんな実装になる。 9char* my_strtok(char* str, const char* delim) { 10 static char* begin; 11 12 if ( str != NULL ) { 13 begin = str; 14 } 15 16 // delimに含まれない文字が現れるまでbeginを進める 17 while ( *begin != '\0' && my_strchr(delim,*begin) != NULL ) { 18 ++begin; 19 } 20 // delimに含まれない文字が現れなかったなら終了 21 if ( *begin == '\0' ) { 22 return NULL; 23 } 24 25 /* 26 この時点で、delimに含まれない最初の位置がbeginとなる 27 */ 28 29 // beginをendの起点とし、delimに含まれる文字が現れるまでendを進める 30 char* end = begin; 31 while ( *end != '\0' && my_strchr(delim,*end) == NULL ) { 32 ++end; 33 } 34 *end = '\0'; // ここで文字列を終端する。 35 36 /* 37 この時点で beginから'\0'の現れる位置(end)までが切り出されたtokenとなる。 38 */ 39 40 char* token = begin; 41 begin = ++end; // 終端した位置の直後を次回の新たな開始位置にする 42 43 return token; 44}

投稿2021/01/31 08:08

編集2021/01/31 08:20
episteme

総合スコア16612

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

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

0

標準関数などは細かく説明されているところは
沢山あるので、関数の使い方を調べましょう。

以下など、理解しやすいと思いますよ。
http://www9.plala.or.jp/sgwr-t/lib/strtok.html

投稿2021/01/31 06:02

WhiteTempest

総合スコア404

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問