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

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

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

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

Q&A

解決済

5回答

6749閲覧

strcmp関数について

eTakahiro

総合スコア10

C

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

0グッド

0クリップ

投稿2016/11/01 15:04

strcmp関数の中身について二つ質問があります。
①*s1=='\0'が成り立つことでで二つの文字列が等しいとしていますが、これはs1とs2の要素数が同じであることを前提としているのですか?
②最後のreturnでunsigned charにキャストしている理由がわかりません。

int strcmp(const char *s1, const char *s2) { while(*s1==*s2){ if (*s1=='\0') return 0; s1++; s2++; } return (unsigned char)*s1 - (unsigned char)*s2; } ```よろしくお願いいたします。

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

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

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

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

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

guest

回答5

0

①*s1=='\0'が成り立つことでで二つの文字列が等しいとしていますが、これはs1とs2の要素数が同じであることを前提としているのですか?

いいえ、違います。引数としては別に異なる長さの文字列2つでも良いです。たとえばs1とS2が全て等しい場合、S1の要素が\0の時、S2の要素も\0となり、その時は文字列数も同じで retuern 0
つまりstrcmpの文字列が等しいときの戻り値0になります。
しかし要素数が等しくない場合でも先にどちらかの文字終端\0がでてきた時点で*s1==*s2が満たせずwhile文をぬけるので問題なし

②最後のreturnでunsigned charにキャストしている理由がわかりません。

はじめて*s1==*s2が成り立たなくなった時、それまでの文字は等しかったのでその文字で大小で比較します。
その大小ですが、charは文字とはいえコンピュータ的には8bitの数値なので単純に数値としての大小を判定します。
この時unsigned charにキャストしているのはsigned charでは大小がおかしくなるからです。

たとえば(unsigned char)*s1 - (unsigned char)*s2が200の時
(signed char)*s1 - (signed char)*s2は−56になる(たぶん)

本来S1>S2として結果をかえしたいのに、S1<S2となってしまう。

###補足

回答を終わって他の回答者様の回答の1の方をみてぎょっとしましたので、そこだけほそく、S1==\0だけでS2のほうは評価していないのに、等しいと判断しているのはwhile文のS1==*S2がなりたっているからで、それは要素数が同じ前提という事です、私が違いますといったのは、strcmpは2つの文字列が同じ要素数しか受け付けないわけではないという意味での「違います」です。

投稿2016/11/01 15:22

編集2016/11/01 15:57
hiim

総合スコア1689

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

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

eTakahiro

2016/11/02 01:41

回答ありがとうございましたm(_ _)m while文の条件式の時点で要素数が同じか判断されるとわかりました。 signed charで200が-56になることも理解できました。
guest

0

ベストアンサー

こんにちは。

①*s1=='\0'が成り立つことでで二つの文字列が等しいとしていますが、これはs1とs2の要素数が同じであることを前提としているのですか?

その直前にwhile(*s1==s2)が成立していますのでs2も0です。従って長さも等しいです。

②最後のreturnでunsigned charにキャストしている理由がわかりません。

よく見落とすのですがchar型は符号付きの場合があります。
0x80以上の値が入っている時符号付きで比較した場合と符号なしで比較した場合、結果が逆になります。
文字コードは符号なしで比較した方が直感的な理解と一致しますので符号なしへキャストしているものと思います。
(何故にchar型を符号付きと定義する場合があるのかは知りません。単に迷惑な話のように感じますが、何か妥当な理由があるかもです。)

投稿2016/11/01 15:21

編集2016/11/02 01:57
Chironian

総合スコア23272

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

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

eTakahiro

2016/11/01 16:55

今調べたら出てきたのですが、オーバーフローというものですか?0x80の値がsigend charに代入されたら-128になるんですね。。。 でもunsigned charにしたところで0x100の値が入ったらまた符号が逆転しますよね??ASCIIを使っている場合でしたらそもそもunsigned charにする必要はないですか?
Chironian

2016/11/01 17:57

今回の場合は計算するわけではないのでオーバーフローもアンダーフローも無関係です。 16進数の0x80を「8ビット2の補数表現の整数」として解釈すると-128となりますし、「符号なし整数」として解釈すると128になります。 「8ビット2の補数表現の変数」が127の時にインクリメントするとオーバーフローして-128になるのです。 8ビットでは0x100を表現できません。8ビットの変数に0x100を設定すると通常は下位8ビットが残るので0x00になります。 0x00~0x7fまでのコードしか使わない場合(例えばASCIIはおっしゃる通り該当します)は、符号なし(unsigned char)でも2の補数表現(signed char)でも比較の結果は同じです。 しかし、0x80~0xffにも文字が割り当てられている場合には異なります。 日本では0x80以上も割り当てられていますし、ヨーロッパも割り当てられています。 http://tools.m-bsys.com/data/charlist_ascii_kana.php https://charset.uic.jp/show/windows-1250/ ですので、これらの国で1バイト文字列でstrcmpを使う場合には符号なしへキャストした方が自然な結果を得ることができます。char型を2の補数表現のまま比較すると、半角のアとイではアの方が大きいと判定されてしまいますので。
eTakahiro

2016/11/01 23:50

なるほど!だいたい分かったと思います。 文字コードについてもうちょっと勉強しようと思います。 ありがとうございました。
Chironian

2016/11/02 02:03

yohhoyさん。情報ありがとう。 なるほど、初期のCPUにchar型をint型へ拡張する際、符号拡張も一緒に行うのが最も効率的なものがあったから、charの符号付き/符号なしは実装依存なのですね。8080系がその1つだったからMSCはcharを符号付きと定義して、それがそのままVC++に引き継がれていると言うことかも知れませんね。
guest

0

strcmp(s1,s2)の戻り値が下記のようになる様に、一文字づつ比較を行いs1の終端'\0'に到達した
場合’0’を返し、両方の文字列は同じとしています。
以外は異なった時点での文字の大小比較の結果を返します。戻る際にunsignedでcastして全ビット
での差分計算値を返します。(符号ビットを数値として扱う)

<<strcmp戻り値>>
s1 = s2のとき: 0
s1 > s2のとき: 正の整数
s1 < s2のとき: 負の整数

strで始まる関数は文字列の最後が'\0'である事がお約束ですので、そこを意識して使われると良いです。
strcat 文字列の連結
strchr 文字列の先頭から文字を検索する
strcmp 文字列の比較
strcpy 文字列のコピー
strlen 文字列の長さの取得
等々..

投稿2016/11/01 15:48

A.Ichi

総合スコア4070

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

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

eTakahiro

2016/11/01 23:57

回答ありがとうございました。 strの関数はいろいろあるのですね。これから学んでいこうと思います。
guest

0

A1. 文字列は終端が'\0'である、という取り決めがあり、もし文字列の長さ(要素数)が違えば、どこかで一致しなくなります(長いほうの中間の要素と'\0'の比較になるから)。両方が同じで、'\0'まで読み込んだ場合は、最後まで同じとわかるので、文字列一致を意味する0を返すのです。

A2. ANSIの仕様では、strcmp関数はs1 > s2のときは正の値、s1 < s2のときは負の値、それ以外は0を返す、としか決められていません。なので、そのような結果を返すコードはすべて合法となります。途中で文字が違う場合、その文字のコードの大小で、文字列の順序が決まります。このコードを扱う際、char型では負の値が出てきてしまうので、unsignedでキャストしているのです。

投稿2016/11/01 15:27

majiponi

総合スコア1720

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

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

eTakahiro

2016/11/02 00:00

回答ありがとうございましたm(_ _)m
guest

0

答1
はい。少なくともこの実装の場合は、長さが違うならば異なる文字列となります。つまり、長さが同一であり、なおかつ内容が完全一致する場合のみ同一文字列と判定されます。

答2
文字コード(符号なし整数)順を正負の条件にするためだと思います。

投稿2016/11/01 15:11

HogeAnimalLover

総合スコア4830

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

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

eTakahiro

2016/11/02 01:42

回答ありがとうございましたm(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問