ページ 1 / 1
文字列検索について
Posted: 2017年7月30日(日) 12:30
by 凡人@sos
[1] 質問文
[1.1] 自分が今行いたい事は何か 指定した文字列を表示させるプログラム
[1.2] どのように取り組んだか(プログラムコードがある場合記載)
コード:
#include <stdio.h>
char test1[4];
char test2[16] = "sos filenonfile";
int main(void){
printf("文字入力せよ:\n");
scanf("%s", test1);
result ();
return 0;
}
[1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
[1.4] 今何がわからないのか、知りたいのか
たとえば、scanfで、file と入力した際に、デバッグをしたさいに、
「4文字目から定義されています。」といった判定が出来るぷろぐらむを作りたいのですが、
難しい構文等を調べたのですが、全く分からなかったので、
プログラムの全容を教えて頂きたく、掲載させて頂きました。
[2] 環境
[2.1] OS : Windows10
[2.2] コンパイラ visual stdio 2017 c++
[3] その他
・どの程度C言語を理解しているか 基本的な動作しか出来ません。c言語を始めたばかりで、独学です。
Re: 文字列検索について
Posted: 2017年7月30日(日) 14:04
by purin52002
こんにちは
「c言語 match」で検索をかけたところ、 strstr という関数が用意されているようです。
文字列test2 の中から 文字列test1 とマッチングする箇所を判定したいのだとしたら、
コード:
test1に文字列を入力
char型のポインタ p に strstr(test2, test1) の結果を代入する
(strstr関数は test2 の中から test1 を検索し、見つかったらその位置のポインタを返す。見つからなかったらNULL)
p がNULLだったら
「見つかりませんでした」と表示
p がNULLじゃなかったら
p と test2 の先頭アドレスの差を int型のindex に代入
(引き算してchar型のsizeで割る(でいける?)) *1
「index 文字目から定義~」と表示
のような感じでいける気がします。
コード:
*1 アドレスの差を求める別の方法
test2 の先頭アドレスを char型のポインタ p2 に代入
p と p2 が一致しない間、 int型のcnt をインクリメント
p と p2 が一致したら、 cnt がアドレスの差になってる(、、、はず^p^)
Re: 文字列検索について
Posted: 2017年7月30日(日) 18:48
by みけCAT
凡人@sos さんが書きました:たとえば、scanfで、file と入力した際に、デバッグをしたさいに、
「4文字目から定義されています。」といった判定が出来るぷろぐらむを作りたいのですが、
まずは、fileは終端のヌル文字を含めて5文字なので、4要素しかないtest1には入り切らず、範囲外への書き込みが発生して未定義動作になります。
test1の要素数を増やすべきでしょう。
Re: 文字列検索について
Posted: 2017年7月30日(日) 18:52
by みけCAT
purin52002 さんが書きました:コード:
p と test2 の先頭アドレスの差を int型のindex に代入
(引き算してchar型のsizeで割る(でいける?)) *1
「index 文字目から定義~」と表示
C言語では、ポインタ同士の引き算は配列の添字の差を返すと定義されているので、char型のサイズで割る必要はありません。
char型のサイズは1と定義されているので、割っても間違った結果にはなりません。
purin52002 さんが書きました:コード:
*1 アドレスの差を求める別の方法
test2 の先頭アドレスを char型のポインタ p2 に代入
p と p2 が一致しない間、 int型のcnt をインクリメント
p と p2 が一致したら、 cnt がアドレスの差になってる(、、、はず^p^)
p2を更新しないと、無限ループになってint型のオーバーフローによる未定義動作が発生するかもしれません。
cntの初期化も必要ですね。
Re: 文字列検索について
Posted: 2017年7月30日(日) 23:06
by Math
Windows10, Visual Stdio 2017 C言語, 開発者コマンドプロンプト使用
char の配列の初期化は 次のようにできます。
char str[] = "abc";
これは
char str[] = {'a','b','c','\0'};
のシンタックスシュガーです。
シンタックスシュガーは
http://dixq.net/forum/viewtopic.php?f=3&t=19257
など過去ログで何度もかいてます。
c.bat
コード:
rem コンパイル後リンク
cl /TC c1.c
rem 実行結果
c1.exe
c1.c
コード:
#include <stdio.h>
char test1[] = "file"; // char test1[4];==>コンパイラに数えさせる方が安全:test1[5]
char test2[] = "sos filenonfile"; // char test2[16] = "sos filenonfile";==>同上tese2=[17]
int result(){
int n1=4,n2=16,i=0;
for(i=0; (16-i) > 4; i++){
printf("%d\t",i);
printf("%c : %c\t",test2[i + 0],test1[0]);
printf("%c : %c\t",test2[i + 1],test1[1]);
printf("%c : %c\t",test2[i + 2],test1[2]);
printf("%c : %c\n",test2[i + 3],test1[3]);
if ( test2[i + 0]==test1[0] &&
test2[i + 1]==test1[1] &&
test2[i + 2]==test1[2] &&
test2[i + 3]==test1[3] ){
printf("%d文字目から定義されています",i);
break;
}
}
return 0;
}
int main(void) {
printf("文字入力せよ:\n");
//scanf("%s", test1);==> file が入力されるものと仮定
result();
return 0;
}
実行
コード:
D:\z17c\c\0730>rem コンパイル後リンク
D:\z17c\c\0730>cl /TC c1.c
Microsoft(R) C/C++ Optimizing Compiler Version 19.10.25019 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
c1.c
Microsoft (R) Incremental Linker Version 14.10.25019.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:c1.exe
c1.obj
D:\z17c\c\0730>rem 実行結果
D:\z17c\c\0730>c1.exe
文字入力せよ:
0 s : f o : i s : l : e
1 o : f s : i : l f : e
2 s : f : i f : l i : e
3 : f f : i i : l l : e
4 f : f i : i l : l e : e
4文字目から定義されています
D:\z17c\c\0730>
Re: 文字列検索について
Posted: 2017年7月31日(月) 03:08
by box
Math さんが書きました:
コード:
#include <stdio.h>
char test1[] = "file"; // char test1[4];==>コンパイラに数えさせる方が安全:test1[5]
char test2[] = "sos filenonfile"; // char test2[16] = "sos filenonfile";==>同上tese2=[17]
せっかくこう書くのであれば、
Math さんが書きました:
コード:
int n1=4,n2=16,i=0;
for(i=0; (16-i) > 4; i++){
このあたりもコンピューターに数えてもらう方がよくないですか?
Re: 文字列検索について
Posted: 2017年7月31日(月) 05:38
by Math
C#だと簡単だけどCではどうかくのか 書いてやって ください。思いつかない…。簡単にかけないなら質問者様には主意は十分通じるので余計なことはいまはいいとはおもいますかけど(^^;
Re: 文字列検索について
Posted: 2017年7月31日(月) 06:01
by Math
[char 補足:参考]
実際のプログラムでは配列を文字列で初期化しなければならないケースはそれほどなくたいていの場合は char *str="abc"; と書くことで用はたりるとおまいます。
この場合[char の配列の初期化] でなく char へのポインター を 文字列リテラルで初期化しているので 文字列の内容は書き換えることができません。大抵文字列リテラルは関数(プログラム)本体と同じ領域にマッピングされます。
Re: 文字列検索について
Posted: 2017年7月31日(月) 17:03
by かずま
result() に引数を付けたので、質問の解答ではありませんが、
これを参考にあなたの望んでいるプログラムが書けると思います。
コード:
#include <stdio.h>
char test1[1000];
char test2[] = "sos filenonfile";
int result(const char *s1, const char *s2)
{
int i, j;
for (i = 0; s1[i]; i++)
for (j = 0; ; j++) {
if (s2[j] == '\0') return i;
if (s2[j] != s1[i+j]) break;
}
return -1;
}
int main(void)
{
int i;
printf("test2: %s\n", test2);
puts("文字入力せよ:");
scanf("%s", test1);
i = result(test2, test1);
if (i >= 0)
printf("'%s' starts at test2[%d]\n", test1, i);
else
printf("'%s' not found\n", test1);
}
このプログラムについて、わからないことがあれば
質問を受け付けます。
他の人のアドバイスでも、わからないことがあれば
どんどん質問しましょう。
だまっていると、何も進みません。
Re: 文字列検索について
Posted: 2017年7月31日(月) 22:20
by 凡人@sos
こちらの場合、const char という形に直さなければならないのでしょうか?
又、int main (void){
の文中で、forループを回して表示させる方法が、やはり思いつきませんが、
たとえば、どのように定義することが出来ればよいのでしょうか?
かずま さんが書きました:result() に引数を付けたので、質問の解答ではありませんが、
これを参考にあなたの望んでいるプログラムが書けると思います。
コード:
#include <stdio.h>
char test1[1000];
char test2[] = "sos filenonfile";
int result(const char *s1, const char *s2)
{
int i, j;
for (i = 0; s1[i]; i++)
for (j = 0; ; j++) {
if (s2[j] == '\0') return i;
if (s2[j] != s1[i+j]) break;
}
return -1;
}
int main(void)
{
int i;
printf("test2: %s\n", test2);
puts("文字入力せよ:");
scanf("%s", test1);
i = result(test2, test1);
if (i >= 0)
printf("'%s' starts at test2[%d]\n", test1, i);
else
printf("'%s' not found\n", test1);
}
このプログラムについて、わからないことがあれば
質問を受け付けます。
他の人のアドバイスでも、わからないことがあれば
どんどん質問しましょう。
だまっていると、何も進みません。
Re: 文字列検索について
Posted: 2017年8月01日(火) 04:05
by かずま
凡人@sos さんが書きました:こちらの場合、const char という形に直さなければならないのでしょうか?
こちらとは、どちらでしょうか?
int result(const char *s1, const char *s2) は、
int result(char *s1, char *s2) でも構いません。
それとも、引数なしの result() がダメかという質問ですか?
もちろん、引数なしにもできます。それは、No.5 の Mathさんの
プログラムなどを参考に、あなたにやってもらいたかったのです。
s1 を test2 に、s2 を test1 に置き換えるだけです。
コード:
int result(void)
{
int i, j;
for (i = 0; test2[i]; i++)
for (j = 0; ; j++) {
if (test1[j] == '\0') return i;
if (test1[j] != test2[i+j]) break;
}
return -1;
}
もちろん、呼出しの i = result(test2, test1); を i = result(); に変えます。
凡人@sos さんが書きました:
又、int main (void){
の文中で、forループを回して表示させる方法が、やはり思いつきませんが、
たとえば、どのように定義することが出来ればよいのでしょうか?
質問の意味がよくわかりません。
main を次のようにしたいということですか?
コード:
int main(void)
{
int i, k;
printf("test2: %s\n", test2);
for (k = 1; k <= 5; k++) {
printf("[%d] 文字入力せよ:\n", k);
scanf("%s", test1);
i = result(test2, test1);
if (i >= 0)
printf("'%s' starts at test2[%d]\n", test1, i);
else
printf("'%s' not found\n", test1);
}
return 0;
}
実行結果
コード:
test2: sos filenonfile
[1] 文字入力せよ:
sos
'sos' starts at test2[0]
[2] 文字入力せよ:
file
'file' starts at test2[4]
[3] 文字入力せよ:
non
'non' starts at test2[8]
[4] 文字入力せよ:
nf
'nf' starts at test2[10]
[5] 文字入力せよ:
os
'os' starts at test2[1]
他の回答者のアドバイスも参考に、例えば strstr() を使った
プログラムなどにもチャレンジしてください。
Re: 文字列検索について
Posted: 2017年8月01日(火) 05:52
by かずま
凡人@sos さんが書きました:
又、int main (void){
の文中で、forループを回して表示させる方法が、やはり思いつきませんが、
たとえば、どのように定義することが出来ればよいのでしょうか?
関数 result を定義せず、main の中だけで処理したいということでしょうか?
コード:
#include <stdio.h>
char test1[1000];
char test2[] = "sos filenonfile";
int main(void)
{
int i, j = 0;
printf("test2: %s\n", test2);
puts("文字入力せよ:");
scanf("%s", test1);
for (i = 0; test2[i]; i++) {
for (j = 0; test1[j] && test1[j] == test2[i+j]; j++) ;
if (test1[j] == '\0') break;
}
if (test1[j])
printf("'%s' not found\n", test1);
else
printf("'%s' starts at test2[%d]\n", test1, i);
return 0;
}