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

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

ただいまの
回答率

90.75%

  • C

    3445questions

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

  • アルゴリズム

    380questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

C言語での文字列の照合アルゴリズム

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 199

giraffeeee

score 2

「C言語によるはじめてのアルゴリズム入門」という本の3-6にある「文字列の照合」
でのソースコードで理解できないところがあります。
下記のコードで
for (p = text; p <= text + m - n; p++)
という部分があるのですがtextは文字列なのにfor分のなかにあり、整数であるm-nを加えていて、
このコードがどういう動きをしているのか分かりません。
p=text(文字列)とはどういう意味なのでしょうか
初歩的な質問で申し訳ないのですがお願いしますm(__)m

 発生している問題・エラーメッセージ

エラーメッセージ

 該当のソースコード

C
ソースコード

include "stdafx.h"

include <string.h>

char *search(char *, char *);

void main(void)
{
static char text[] = "This is a pen.That is a pensil.";
char *p, *key = "pen";

p = search(text, key);
while (p != NULL) {
printf("%s\n", p);
p = search(p + strlen(key), key);
}
}

char *search(char *text, char *key)
{
int m, n;
char *p;

m = strlen(text);
n = strlen(key);
for (p = text; p <= text + m - n; p++) {
if (strncmp(p, key, n) == 0)
return p;

}
return NULL;
}

 試したこと

ここに問題に対して試したことを記載してください。

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+3

>char *search(char *text, char *key)
では、textは文字列の先頭アドレス(ポインタ)なので、加減算ができます。
従って、 text + m - nは文字列の先頭+文字列長ー検索する文字列長になります。
要は、文字列先頭から検索する文字列長を引いた値まで検索しているだけです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/11 22:15

    なるほどtextは文字列の先頭のアドレスを表していてそれにm-nを加えることで先頭から文字列長ー検索する文字列長までを繰り返しているということですね
    わかりやすい説明ありがとうございました すっきりしました

    キャンセル

checkベストアンサー

+1

p = text

char のポインタを代入してます

 p <= text + m - n

pとtext+m-n のアドレスとを比較してます

 p++

pをインクリメントしてます

その他不明なところはあるでしょうか

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/11 22:15

    textは先頭アドレスを表しているということを完全に忘れていました
    for文でアドレスを比較するのは初めての経験だったので分かりやすい説明ありがとうございます!
    その他不明な点としてmain関数内での
    while (p != NULL) {
    printf("%s\n", p);
    p = search(p + strlen(key), key);

    でprintfしているpはこのtextの文章で最初にkeyであるpenが見つかったアドレス以降の文字列を表示しているからこのソースを実行すると一行目には
    pen.That is a pensil.が表示される
    そして
    p = search(p + strlen(key), key);
    ではp(前にkeyが見つかったアドレスの先頭)にkeyの長さを加えてまたsearch関数に入れることで次のkeyが出てくるアドレスを探し同じように
    見つかったアドレスを返してそのアドレス以降の文字列を表示するので二行目はpensil.
    になるということであってますかね!?
    重ね重ねすいません

    キャンセル

  • 2018/06/11 22:22

    それであってます
    パズルみたいなもんで、読み込んでいくと面白いですね

    キャンセル

  • 2018/06/11 22:28

    重ね重ねありがとうございました

    キャンセル

+1

C言語では「文字列」は,宣言と同時に配列型変数に代入する場合は「NULL終端する文字の配列」と一般的には等価です。
(厳密には,ポインタ型変数に代入したりインラインリテラルとして使用する場合はメモリ確保の方法が少し異なります)

static char text[] = "This is a pen.That is a pensil.";
static char text[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'p', 'e', 'n', '.', 'T', 'h', 'a', 't', ' ', 'i', 's', ' ', 'a', ' ', 'p', 'e', 'n', 's', 'i', 'l', '.', '\0'};

上記2つは等価です。

  • 整数としておなじみの int は一般的には値の範囲が -2147483648 ~ 2147483647 の数値です。(環境に左右されます)
  • 文字としておなじみの char も実は値の範囲が -128 ~ 127 の数値です。各番号に形式上文字が割り当てられているだけの話です。ASCII文字コード - IT用語辞典
  • char のアドレスを表す char * もまた数値です。32ビット環境では -2147483648 ~ 2147483647,64ビット環境では -9223372036854775808 ~ 9223372036854775807 になります。

ここでたとえば text が 0x80000000 番地(16進数表記)から始まっていると仮定すると,各アドレスに対応するデータは以下のようになります。

0x80000000 84 (T)
0x80000001 104 (h)
0x80000002 105 (i)
0x80000003 115 (s)
0x80000004 32 ( )
0x80000005 105 (i)
0x80000006 115 (s)
0x80000007 32 ( )
0x80000008 97 (a)
0x80000009 32 ( )
0x8000000a 112 (p)
0x8000000b 101 (e)
0x8000000c 110 (n)
0x8000000d 46 (.)
0x8000000e 84 (T)
0x8000000f 104 (h)
0x80000010 97 (a)
0x80000011 116 (t)
0x80000012 32 ( )
0x80000013 105 (i)
0x80000014 115 (s)
0x80000015 32 ( )
0x80000016 97 (a)
0x80000017 32 ( )
0x80000018 112 (p)
0x80000019 101 (e)
0x8000001a 110 (n)
0x8000001b 115 (s)
0x8000001c 105 (i)
0x8000001d 108 (l)
0x8000001e 46 (.)
0x8000001f 0 (\0) 

C言語においては int 型に限らず char や char * も加算・減算することができます。今回は char * の加算を利用しています。

一般的にC言語における文字列はNULL終端している必要がありますが,strncmpに関しては,「探される文字列」側はNULL終端している必要がありません。(strncmp を参照)そのため,今回のコードで書いているような以下のアルゴリズムが利用できます。

  • 「探される文字列」の先頭アドレスを1つずつずらしていく
  • 現在のアドレスから「探す文字列」の長さのぶんだけ strncmp 関数にチェックさせる

1回目: Thi と pen が一致するか?
2回目: his と pen が一致するか?
3回目: is  と pen が一致するか?
4回目: s a と pen が一致するか?
5回目:  a  と pen が一致するか?
6回目: a p と pen が一致するか?
7回目:  pe と pen が一致するか?
8回目: pen と pen が一致するか?

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/11 22:30

    ちなみに search 関数とほぼ同じ実装が標準関数の strstr にありますね
    http://hitorilife.com/strstr.php

    キャンセル

  • 2018/06/11 22:39

    C言語における文字列の定義からさまざまな事柄に関して丁寧な説明本当にありがとうございます!
    C言語への理解が少し深まりました
    ここまでの説明をぱっとできるなんて本当にすごいです!
    ありがとうございます!

    キャンセル

  • 2018/06/11 22:41

    標準関数に同じことができるものがあるんですね…
    まだ全然そこらへんを知らないので勉強していこうと思います
    ありがとうございます

    キャンセル

0

 ポインタとかアドレスの概念をまず勉強しましょう。

多分、概念を理解されていません。失礼ながら基礎なしではそもそも議論にならないと思いますよ。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    C言語 動的メモリ確保とリスト(構造体)を利用したプログラム

    現在このような結果で表示されるプログラムの作成を試みています。 >0p↲ >p >1d↲ >pd >0i↲ >ipd >2a↲ >ipad というように、格納位置

  • 解決済

    スタックの応用

    スタックを利用して入力された文字列の回文を作るプログラムを作成したら、出力されません。 例えば、「abcd」と入力したら、「abcddcba」と主著力される。 発生して

  • 解決済

    char型の配列変数にchar型の変数を代入したい

    使用言語 C 環境 Visual Studio 2017 初めての質問です。 独学でプログラミングを始めたのですがわからないところがあり困っています。 char型の配列変数の使い方

  • 解決済

    gcry_mpi_t 内の公開鍵をビット列で取り出したい

     gcry_mpi_t 内の公開鍵をビット列で取り出したい libgcrypt1.7.6 を使ってRSA暗号をいじってく中で, gcry_mpi_t型におさまっている公開鍵をビット

  • 受付中

    c言語 文字列を逆順にして出力する

    発生している問題・エラーメッセージ 文字列を逆順にする関数を作成したのですが最後の文字の入れ替えができません。少しいじるとコアダンプと出てしまいます。どなたか解決法を教えてください

  • 解決済

    ファイルに含まれる文の数を数える(c言語)

    2回目の投稿になります。前回、「英文が書かれたファイルを読み込んで,ファイルに含まれる文の数を数える」 (文の数を判定する文字は'.','?','!'の3つ)c言語のプログラムにつ

  • 解決済

    配列を返す関数を作りたい[VC++][VS2008]

    前提・実現したいこと 配列を返す関数を作りたい。 戻り値に配列の長さ、引数にポインタをもつ関数で配列の値が取得できるようにしたい。 具体的には、ポインタ引数を関数内でnewし、me

  • 受付中

    c言語のif文について

    c言語のif文の条件について 最近c言語の勉強をし始めたものです 以下のようなif文の条件の書き方を教えてください。 キーボード入力(key)から 自然数を入力→ ● a を入

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

  • C

    3445questions

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

  • アルゴリズム

    380questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。