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

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

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

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

Q&A

解決済

6回答

13328閲覧

ある文字列中に入力した文字列が含まれるかどうかを判定するコードを書きたい!

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

1クリップ

投稿2018/01/03 10:50

###前提・実現したいこと
任意の文字列bを入力させたとき、文字列World Universityにbが丸ごと含まれるか
どうかの判定をするコードを書きたいです。

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

表示されるエラーの意味が分からないです。(warningとして出てくる、関数judgeの、void型にも関わらず終了させるために returnで1を返しているとことはあえてです(代替が思いつかなかったので。)) あと、引数の変数に&をつけて、対象の関数の仮引数に*をつけると値を保存できるルールを使っているのですが エラーでポインタ扱いされているのが分かりません。(ポインタは宣言しないと使えないはずでは ないのでしょうか)

###該当のソースコード
C言語
#include<stdio.h>
int count_a(char a, int *a_counter){
int i=0;
while(a[i]!='\0'){
i++;
*a_counter++;
}
return *a_counter;
}

int count_b(char b, int *b_counter){
int i=0;
while(b[i]!='\0'){
i++;
*b_counter++;
}
return *b_counter;
}

void judge(char a, char b, int a_counter, int *j){
int i, flag=1;
for(i=0; i<a_counter; i++){
if(b[0]==a[i]){
j++;
flag=flag
0;
break;
}
}
if(flag==1){
printf("no equal!\n");
return 1;
}
return ;
}

void count_j(char a, char c, int j, int *l){
int i;
char c[0]=j;
for(i=j+1; i<count_a; i++){
if(a[j]==a[i]){
*l++;
c[*l]=i;
}
}
return ;
}

finalfunc(char a, char b, char c, int *k, int *l, int *flag, int *b_counter){
int i;
for(i=0; i<*b_counter; i++){
if(b[i+1]!=a[c[k]+(i+1)]){
flag=flag
0;
if(k==*l){
printf("no equal!!\n");
return 1;
}
break;
}
}
return *flag;
}

int main(){
char a[20]="World University";
char b[20];
char c[20];//b[0]と一致したaの添え字がa中に幾つ含まれるか
int a_counter=0, b_counter=0;//a,bの文字数
int j=-1;//b[0]と一致した最初のaの添え字
int k;//b[0]と一致した文字のaに含まれる個数
int l=0;//cの添え字
int flag;
//bに入力してもらう
printf("input b:"); scanf("%s", b);
//関数、a,bの文字数を数える
a_counter=count_a(a, &a_counter);
b_counter=count_b(b, &b_counter);
//関数、b[0]とaのいずれかが一致するか判定する
judge(a, b, a_counter, &j, &k);
//関数、b[0]がaに何文字あるか数える、l-1文字が一致する文字数
count_j(a, c, j, &l);
/関数、b[1]以降とa[c[0]]以降が一致するか、b[1]以降とa[c[1]]以降が
一致するか、以下略
/
for(k=0; k<l+1; k++){
flag=1;
finalfunc(a, b, c, &k, &l, &flag, &b_counter);
if(flag==1){
printf("equal!!\n");
return 1;
}
}
return 0;
}

###補足情報(言語/FW/ツール等のバージョンなど) atomとコマンドプロンプトです。

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

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

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

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

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

diningyo

2018/01/03 11:38

エラー内容をそのまま貼ることをおすすめします。あとソースコードはMarkdown使って書いたほうがいいです。
guest

回答6

0

結論を先に書くと、
大幅に戻って,基礎固めをしてから再チャレンジすることをお勧めします。関数と引数が理解できていません。あるいは、練習としてサブストリング検索プログラムを書いてみたいのならポインタを使わずに関数は作らずにmainだけで配列で書くとか。文字列処理の練習とポインタ取り扱いの練習を一気にやるのはやめた方が良いですよ。

やりたいこと(文字列World Universityにbが丸ごと含まれるか)と現在のプログラムの処理が全く食い違っているように見えます。
あと、実引数と仮引数の型が違ってますね。char[]を渡してint*で受けてます。

count_aとcount_bが仮引数の名前が違うだけでデータ型も内部処理も全く同じ関数のように見えます。

練習のためにあえて書いてみるのならともかく、基礎的な文字列処理は自分では書かずライブラリ関数を使うのが安全・有利です。文字列の長さをしらべるならstrlen()、文字列中の文字列を探すならstrstr()など。定番のライブラリ関数にはどういうものがあるのかを知るのもCプログラミングの初歩なので、がんばってください。

サブストリング検索に有名な高速アルゴリズムがいくつかありますが、とりあえず効率は無視してシンプルにやるなら

alen=aの長さ blen=bの長さ for(i=0;i<=a-b;i++) if(aのi文字目からがbに合致するか?){見つけた} ```てな感じの手順になりますね。 さらに効率を無視して単純化するならば ```ここに言語を入力 for(i=0;a[i]!='\0';i++) if(aのi文字目からがbに合致するか?){見つけた} ```てな感じ。 あと、このプログラムに20文字を越える入力を与えるとどうなるかわかりますか?

投稿2018/01/04 01:24

a_saitoh

総合スコア702

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

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

0

お疲れ様。今日ご自身が「回答」されたコードは動作するようだけど、私から見ると不必要に複雑、どなたかが仰ったように、難しく考えすぎだと思います。
先頭が一致する位置を見つけること自体は間違いではないけど、わざわざ c[] 配列に格納する必要があるだろうか? for ループが5つもあるけど、そんなに必要? …ということで、私の考えを少々回りくどく説明してみます。

まず、a[] の先頭から b[] を比較して一致するかどうか、から考えます。
a[] = "World University"; に対して、例えば、b[] = "Worl"; とか b[] = "Wool"; だったらどうなるか(時々こんな風に、具体的なデータを想定すると考えを整理しやすいもの)。

C

1 /* a[] 文字列の先頭から一文字ずつ b[] と比較していく */ 2 for (i = 0; i < b_len; i++) { 3 if (a[i] != b[i]) { 4 一致しない ; 5 } 6 } 7 一致した ;

言うまでもなく、一個でも違えば不一致、一致したと言えるのは b_len 個すべてが一致した場合…そういうロジックです。
次に、b[] = "orld"; ならどうか。a[] の先頭には一致しないが、a[1] に一致する(と人間にはすぐわかる笑)。それにはコードを、例えばこう修正すれば一致を検出できます。

C

1 for (i = 0; i < b_len; i++) { 2 if (a[1 + i] != b[i]) { 3 一致しない ; 4 } 5 } 6 一致した ;

ここの a[1 + i] は、a[] 文字列の2文字目から b[] と比較することを意味します。さらに、この「1」を k という変数で一般化し、「a[k + i]」とすれば、 a[k] の位置から比較することを意味します。

C

1 k = ???; // 比較する先頭位置を指定する 2 for (i = 0; i < b_len; i++) { 3 if (a[k + i] != b[i]) { 4 kの位置では一致しない ; 5 } 6 } 7 kの位置から一致した ;

ここまできた所で、a[] の中に b[] があるかどうかを探す、とは、

  1. a[0] (先頭)から b[] と比較してみる
  2. a[1] (2文字目)から b[] と比較してみる
  3. a[2] (3文字目)から b[] と比較してみる
  4. ・・・

と、次々に試していけば判定出来るんじゃありませんか。一致するならどこかで一致を検出できるし、最後まで行っても見つからないなら一致しないということ。要するに、こんな感じです。

C

1 // a[] の比較開始位置を、先頭から一文字ずつ進めていく 2 for (k = 0; k < ???; k++) { 3 // a[k] から b[] と比較する 4 for (i = 0; i < b_len; i++) { 5 if (a[k + i] != b[i]) { 6 k の位置では一致しない ; 7 } 8 } 9 k の位置で一致した ; 10 }

わざわざ b[0] に一致する位置を探すまでもなく、一致しなければ
「if (a[k + i] != b[i]) 」でただちに判定でき、比較開始位置を次々に進めていけます。

最後のコードは完成間近ですが、エッセンス部分だけなので、もう少し手を入れる必要があります。でもこれで、二重のforループで実現できる(5つもforループする必要は無い)事と、c[] 配列が不要な事を示せたと思います。ご理解いただけたら、ぜひ完成させて、貴方のコードと見比べてみていただきたく。

なお、flag = flag * 0; という書き方は嫌いです。flag = 0; で済むことだから。
もっといえば、フラグ変数なら1/0よりも true/false を値として使って欲しいものです。

投稿2018/01/10 14:15

編集2018/01/10 14:27
rubato6809

総合スコア1380

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

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

0

難しく考えすぎ、しかも変数/関数名も適当な印象を受けます。
どうすれば解決できるかイメージがはっきりしていないのではないでしょうか?

引数の変数に&をつけて、対象の関数の仮引数に*をつけると値を保存できるルール

ルールじゃないです。ちゃんと理由があります。
よくわからないで使っているならば、一歩立ち返ってポインタを復習しましょう。

また、他にも次の部分も気になります。

C

1a_counter = count_a(a, &a_counter);

a_counterのアドレスを引数として与えている意味が全くわからないです。
**『どうしてこう書くのか?』**を説明できるようになりましょう。


まずはじっくり考え、どのような関数を用意すればいいか考えましょう。
アルゴリズムを思いつけば、後はコードに書くだけです。例えばこんな感じです。

C

1#include <stdbool.h> 2#include <stdio.h> 3#include <stdlib.h> 4#include <string.h> 5 6// 7// str1とstr2を、頭からn文字分比較する 8// @return 全部一致でtrue, そうでなければfalse 9bool strcmp_n(const char* str1, const char* str2, size_t n) { 10 ... 11} 12 13// 14// targetからkeywordを見つけ出す 15// @return 見つかったら何文字目かを返し、見つからなければ-1を返す 16int find_string(const char* target, const char* keyword) { 17 ... 18} 19 20int main(void) { 21 const char str1[] = "World University"; 22 23 // とりあえず四回試す 24 for(int i = 0; i < 4; ++i) { 25 char str2[20]; 26 printf("input str2: "); 27 if(scanf("%19s", str2) != 1) exit(1); 28 29 int search_result = find_string(str1, str2); 30 if(search_result == -1) { 31 printf("%s is not included in %s\n", str2, str1); 32 } 33 else { 34 printf("%s is included at %d in %s\n", str2, search_result, str1); 35 } 36 } 37 38 return 0; 39}

敢えて部分的にコードを伏せていますが、簡単な動作確認はしています。
行数はそれぞれ高々両手で数えられるくらいです。

Cの文字列(というか配列)は少し癖があるので、慣れも必要ですが。

投稿2018/01/03 16:20

LouiS0616

総合スコア35658

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

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

退会済みユーザー

退会済みユーザー

2018/01/10 00:24

解答ありがとうございます。情けない話ですが、見返すと自分でもよくわからないコードでした。あと、ポインタもよくわからず使っていました。結局main関数だけで作り直しました。<stdio.h>と<string.h>しか知らないので、教えていただいたのではつくれていません。西村広光さんお入門プログラミングというのだけで勉強してきましたが、なにかおすすめはありますか?
LouiS0616

2018/01/10 05:08

本に関してはあまりお勧めはないですね。いい本がない、というわけではなく、単に私がそこまで読み込んでいないだけです。もちろん優劣はありますが、明らかに間違ったことが書かれているのでなければ(レビューで判断)、読みやすい本を一冊だけ選ぶといいと思います。
LouiS0616

2018/01/10 05:11

コードを書く際は、文法の知識は大前提、それに加えて設計の知識や経験、センスが必要になります。 英作文と同じですね。 文法面は勉強するしかないです。 不安を払拭できるよう、基礎の確認を怠らないようにしてください。 設計面は、まずはいろいろ書いてみることでしょう。 手間はかかりますが、いろんな方法で同じプログラムを書いてみましょう。 また、他の人が書いたコードを読んで、技術を盗む癖をつけるとよいでしょう。 一朝一夕で身につくものではありません、頑張ってくださいね。
guest

0

あちこち、エラーだらけですね。
とりあえず、質問にだけ回答します。

(warningとして出てくる、関数judgeの、void型にも関わらず終了させるためにreturnで1を返しているとことはあえてです(代替が思いつかなかったので。))

代替とというか、正しくは、1を付けないretrurn;です。

あと、引数の変数に&をつけて、対象の関数の仮引数に*をつけると値を保存できるルールを使っているのですがエラーでポインタ扱いされているのが分かりません。(ポインタは宣言しないと使えないはずではないのでしょうか)

仮引数に*を付けるとポインターの宣言になります。

引数の勉強なら、main1つ、関数1つくらいの、簡単な物から始めるのが良いと思います。

投稿2018/01/03 11:40

otn

総合スコア84423

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

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

退会済みユーザー

退会済みユーザー

2018/01/04 00:02

ありがとうございました
guest

0

ベストアンサー

c

1/* 2あくまで、想定どおりに入力されるとした前提でのコードです。 3まず、入力された文字列uStrの先頭文字が想定文字列strに 4存在するかを確認します。無い場合はプログラムを終了します。 5myCheck関数では、少なくとも入力した文字列uStr分の長さをもつ文字列subに、 6uStrの先頭と一致したstrの文字を先頭にもつ文字列を一文字ずつ 7入れていきます。subはstrの中に含まれる文字列なので 8subとuStrが一致すれば、uStrがstrの中に含まれるといえます。 9 10#include<stdio.h> 11#include<string.h> 12 13int myCheck(char *pstr, char *puStr, int i); 14 15int main(void) 16{ 17 char str[] = "World University"; 18 char uStr[20] = {0}; 19 int i = 0; 20 int j = 0; 21 int flag = 0; 22 int loop = 0; 23 int ans = 0; 24 int sum = 0; 25 26 //scanf("%s", uStr); 27 gets(uStr); 28 29 //このままだと、1回目に一致した文字でしか判定できていないので 30 //2回目に一致した文字でも同様に行うため、添字を配列に格納しておいて 31 //その添字ごとにmycheck関数を行う 32 33 while(*(str+i) != '\0'){ 34 35 if( *uStr == *(str+i) ){ 36 flag = 1; 37 c[j] = i; 38 j++; 39 } 40 i++; 41 } 42 43 printf("uStr:%s\n", uStr); 44 printf("i:%d\n", i); 45 46 if(flag != 1){ 47 printf("含まれません。\n"); 48 return 1; 49 } 50 51 while( loop < j){ 52 ans = myCheck(str, uStr, i); 53 sum += ans; 54 } 55 56 if(sum > 0) 57 printf("含まれますよ。\n"); 58 else 59 printf("やっぱり含まれません。\n"); 60 61 return 0; 62} 63 64int myCheck(char *pstr, char *puStr, int i) 65{ 66 char substr[20] = {0}; 67 int j = 0; 68 int L = strlen(puStr); 69 70 while( j < L ){ 71 substr[j] = pstr[i]; 72 j++; 73 i++; 74 } 75 substr[j] = '\0'; 76 77 if(strcmp(substr, puStr) == 0){ 78 return 1; 79 }else{ 80 return 0; 81 } 82 83} 84 85 86 87 88

投稿2018/05/29 23:48

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

#include<stdio.h>
#include<string.h>

int main(){
char a[20]="World University";
char b[20];
int a_len, b_len;
int i, j, k, flag, l;
int c[20];//文字列b[0]と一致した文字列aの添字を保存するための配列

printf("input b:"); scanf("%s", b);
a_len=strlen(a);
b_len=strlen(b);
j=-1;
flag=1;
/文字列bの1文字目が文字列a中にあるか。jに、一致した時の
文字列aの添字を保存する
/
for(i=0; i<a_len; i++){
j++;
if(b[0]==a[i]){
flag=flag0;
break;
}
}
if(flag==1){
printf("文字列%sと文字列%sは一致しません\n", a, b);
return -1;
}
for(i=0; i<20; i++){c[i]=0;}
c[0]=j;
i=0;
l=0;
/上で一致した文字が、文字列a中に更にあるか。/
for(i=j+1; i<a_len; i++){
if(a[j]==a[i]){
l++;
c[l]=i;
}
}
for(k=0; k<l+1; k++){
flag=1;
for(i=0; i<b_len; i++){
if(b[i]!=a[c[k]+i]){
flag=flag
0;
if(k==l){
printf("文字列%sと文字列%sは一致しません\n", a, b);
return -1;
}
break;
}
}
if(flag==1){
printf("文字列%sと文字列%sは一致します\n", a, b);
return -1;
}
}
return 0;
}

投稿2018/01/10 00:24

編集2018/01/10 00:26
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問