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

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

ただいまの
回答率

91.24%

  • C

    2708questions

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

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

受付中

回答 5

投稿

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

konamon

score 2

前提・実現したいこと

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

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

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

該当のソースコード

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とコマンドプロンプトです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • t_masa

    2018/01/03 20:38

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

    キャンセル

回答 5

+4

結論を先に書くと、
大幅に戻って,基礎固めをしてから再チャレンジすることをお勧めします。関数と引数が理解できていません。あるいは、練習としてサブストリング検索プログラムを書いてみたいのならポインタを使わずに関数は作らずに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文字を越える入力を与えるとどうなるかわかりますか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+2

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

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

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

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

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/01/04 09:02

    ありがとうございました

    キャンセル

+2

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

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

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

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

a_counter = count_a(a, &a_counter);

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


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

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

//
// str1とstr2を、頭からn文字分比較する
// @return 全部一致でtrue, そうでなければfalse
bool strcmp_n(const char* str1, const char* str2, size_t n) {
    ...
}

//
// targetからkeywordを見つけ出す
// @return 見つかったら何文字目かを返し、見つからなければ-1を返す
int find_string(const char* target, const char* keyword) {
    ...
}

int main(void) {
    const char str1[] = "World University";

    // とりあえず四回試す
    for(int i = 0; i < 4; ++i) {
        char str2[20];
        printf("input str2: ");
        if(scanf("%19s", str2) != 1) exit(1);

        int search_result = find_string(str1, str2);
        if(search_result == -1) {
            printf("%s is not included in %s\n", str2, str1);
        }
        else {
            printf("%s is included at %d in %s\n", str2, search_result, str1);
        }
    }

    return 0;
}

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/01/10 09:24

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

    キャンセル

  • 2018/01/10 14:08

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

    キャンセル

  • 2018/01/10 14:11

    コードを書く際は、文法の知識は大前提、それに加えて設計の知識や経験、センスが必要になります。
    英作文と同じですね。

    文法面は勉強するしかないです。
    不安を払拭できるよう、基礎の確認を怠らないようにしてください。

    設計面は、まずはいろいろ書いてみることでしょう。
    手間はかかりますが、いろんな方法で同じプログラムを書いてみましょう。
    また、他の人が書いたコードを読んで、技術を盗む癖をつけるとよいでしょう。

    一朝一夕で身につくものではありません、頑張ってくださいね。

    キャンセル

+2

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

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

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


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

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


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

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


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

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

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

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


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

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

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

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

-1

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=flag*0;
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;
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

ただいまの回答率

91.24%

関連した質問

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

  • C

    2708questions

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

  • トップ
  • Cに関する質問
  • ある文字列中に入力した文字列が含まれるかどうかを判定するコードを書きたい!