C言語で文字列から文字を探すプログラムの作成方法

このQ&Aのポイント
  • C言語で文字列から文字を探すプログラムを作成する方法について解説します。
  • 具体的なコード例を紹介しながら、文字列strの中に文字cが含まれているかどうかを判定する関数の作成方法を説明します。
  • また、コンパイルエラーについての疑問点に対する解決方法も説明します。
回答を見る
  • ベストアンサー

文字列strの中から文字cを探すプログラム(C言語)がわからない

文字列strの中から文字cを探すプログラム(C言語)がわからない 柴田望洋さんの「[新版]明解C言語」という本の演習11-2なんですがどうしてもわかりません。間違いは無いと思うのにコンパイルすると警告を吐かれます。 僕が書いたプログラムを載せます。 /* 文字列strの中に、文字cが含まれていれば(複数ある場合は、最も先頭側とする)、 その文字へのポインタを返し、含まれていなければNULLを返す関数 char *str_chr(const char *str, int c) {} を作成せよ。 */ #include<stdio.h> char *str_chr(const char *str, int c){ while(*str){ if(*str==c) return str; str++; }     return NULL; } int main(){ char *str; char c; scanf("%s",str); scanf(" %c",c);     printf("%d",str_chr(str,c)); return 0; } コンパイラは「関数str_chrのif分の中のreturn strの型変換に問題がある」と言っているんです。 型変換はしるつもりは無いのにコンパイラはなぜそのように認識するのでしょうか。 またネット答えを探しましたがどうやらこのreturn strの部分はreturn (char*)strが正解のようです。意味がわかりません。strはポインタなのになぜまたわざわざchar型に変換しているのですか?といか(char*)の意味が根本的にわかりません。 質問ばかりですみません。初心者でポインタがどうにも理解できないんです。 誰か詳しい人教えてください。 お願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

char *str_chr(const char *str, int c) {} という宣言では 戻り値: char *型(charへのポインタ) 引数: str (cosnt char *型/const charへのポインタ) となります。 const char というのは、「変更できないchar」と言う意味です。 char c='A' ; const char cc='A' ; /* 初期化によってのみ代入可能 */ c ='C' ; /* OK */ cc ='C' ; /* エラー */ const char * はconst char への(普通の)ポインタです。ポインタが指す実体はconst charなので変更できませんが、ポインタ自身は通常の変数なので変更できます。 char str[] = "abcde" ; char * cp = str; const char* ccp ="ABCDE" ; cp ++ ; /* OK */ *cp = 'A' ; /* OK */ ccp ++ ; /* OK */ *ccp = 'A' ; /* エラー */ このように、振舞いが違うので、char/char *型とは別の型として扱われます。 char → const char,char * → const char * は暗黙の型変換ができます。変更を禁止するだけですから。 逆方向は、(本来は)基本できません。const の意味を失ってしまうし、文字列リテラルのような本当に変更してはいけない(致命的なエラーになりかねない)ものもあるからです。 型変換(キャスト)は、暗黙の変換ができない場合でも、強制的に型変換を行うもので、変換したいものの前に (変換したい型) と付けます。 (char *)str はstrの型を強制的にchar *型にします。 なお、この変換は、キャストを書いた箇所だけのもので、変数そのものを変換するわけではありません。 さて、問題のプログラムですが。 return str としていますから、char * 型をreturnしなければならないところに、const char *型を指定している、という警告です。 const char * → char *の暗黙の型変換は無いので、char *として使えない、ということです。 そのため、戻り値の型を合わせるために(char *)でキャストしています。 > strはポインタなのになぜまたわざわざchar型に変換しているのですか? char型には変換していません。 char型に変換するときは(char)です。

その他の回答 (6)

  • kb-nike
  • ベストアンサー率36% (72/200)
回答No.7

ANo.6です、質問の内容を早とちりして、勘違いしていました。 再回答します。 >このreturn strの部分はreturn (char*)strが正解のようです。 >意味がわかりません。 >strはポインタなのになぜまたわざわざchar型に変換しているのですか? >といか(char*)の意味が根本的にわかりません。 質問者さんのコードをそのままコンパイルすると、 VC++では次のような「警告」がかえってきます。 warning C4090: 'return' : 異なる 'const' 修飾子です。 str_chr()引数で「const char *」型として渡された引数を、 「char *」型として戻そうとするために、エラーまたは警告となります。 引数の型を「const char *」→「char *」に変更すると、 エラーまたは警告がなくなることで、その意味がわかると思います。

  • kb-nike
  • ベストアンサー率36% (72/200)
回答No.6

柴田望洋さんのHP:「C」→「標準関数」→「strchr」 http://www.bohyoh.com/CandCPP/C/Library/strchr.html に、「■実装例■」として模範例が出ています。 ご自身のコードと比較してみてください。

  • okormazd
  • ベストアンサー率50% (1224/2412)
回答No.5

char *str_chr(const char *str, int c) {} を作れといっているのだから,「誤り」といわれてもネ。 //はその文字が何番目にあるかにしたいと思っただけで,質問とは関係ない #include<stdio.h> char *str_chr(const char *str, int c) { while(*str){ if(*str==c) return (char *)str;/*一時的に型キャスト,キャストしなくてもエラーではない。constといっているのに変える気か,というような警告*/ str++; } return NULL; } int main() { char str[100]={0};/*scanfで文字列を取りたいのだから配列にして,初期化しておく*/ char c; //char *p; scanf("%s",str); scanf(" %c",&c);/*scanfの引数はアドレス*/ //p=str-1; printf("%p\n",str_chr(str,c));/*ポインタを返すのだから,書式は%p*/ //printf("%d\n",str_chr(str,c)-p);/*ポインタで返されてもわからないから,何番目かわかるようにすればこうなるというだけ*/ return 0; }

回答No.4

(1) 関数の宣言で、 誤:char *str_chr(const char *str, int c) 正:const char *str_chr(const char *str, int c) です。 str_chrの内容は合っていると思います。 (2) mainにおいて、 printf("%d", str_chr(str,c)); は、間違っています。 ------------ 誤:printf("%d", str_chr(str,c)); 正:printf("%s", str_chr(str,c)); です。 改行するなら、printf("%s\n", str_chr(str,c));と\nをつけます。 (3) mainにおいて、 char *str ; scanf("%s", str) ; は間違いです。 実体あってのポインタです。 [ポインタ]----->[実体] char *str ; は、ポインタサイズの容器strを確保しますが、容器の中身は不定です。 そのような値を関数に渡してはいけません。 ----- char enoughBuffer[1024] ; enoughBuffer[0] = '\0' ; /* 空文字列として初期化 */ char *str = &enoughBuffer[0] ; /* ポインタサイズの容器strを確保し、バッファの先頭文字へのポインタを格納 */ scanf("%s", str) ; とか、 char enoughBuffer[1024] ; enoughBuffer[0] = '\0' ; /* 空文字列として初期化 */ scanf("%s", enoughBuffer) ; /* バッファの先頭へのポインタを渡す */ とすべきです。 ちなみに、C言語では、&enoughBuffer[0]とenoughBufferは、同じ値(同じポインタ)です。 ------------------------- 以下、ご参考 ------------------------- ご存じのとおり、C言語には文字列型は存在しません。代わりに文字配列と'\0'の組み合わせで表現します。 (4) 文字へのポインタも、文字配列へのポインタも、char *で表します。 a. [ポインタ(char *)]------>(char)[文字] b. [ポインタ(char *)]------>(char配列)[文字][文字]...[文字][文字] たとえば、 char *p ; という定義において、pがa,bいずれのタイプを指しているかは、プログラムを書いた人にしかわかりません。そのため実務上は、char *pMoji, *pNameなど、変数名で区別します。 (5) ポインタが指している実体を書き換えてほしくないときは、constを使います。 たとえば char moji = 'X' ; char *p1 = &moji ; const char *p2 = &moji ; と定義されているとすると、 p1は、将来、実体を書き換えることを示唆しています。(たとえば、*p1 = 'S') p2は、実体を参照はするかもしれないが、書き換える意図はないことを示唆しています。 (6) 文字列定数は、内部的に文字配列(最後の要素が'\0')です。 定数は書き換えてほしくないので、constを使います。 (例) const char *pcstr = "Good Morning." ; コンパイラが許せば、テクニックとしては、  char *pstr = (char *)"Good Morning." ; という定義も可能ですが、良いプログラムではありません。

  • ohtawa
  • ベストアンサー率23% (9/38)
回答No.3

No.2さんが示されているとおりです 私も間違ったことあるだけでなく なかなか理解できませんでした 私は次のように要約して理解しています (1)const char * と char * とは 別の型である (2)暗黙に変換される方向とそうでない方向がある (3)const char * は書き込み不可 char * 書き込み可 だが    キャストは変数を変えることはしないその場限りである うーん うまく表現できないな

回答No.1

コンパイラがwarningを出す理由は関数の宣言が char *str_chr(const char *str, int c){ と、strがconstと宣言されていて、関数の戻り値の定義、char *と一致しないからです。 ちなみにgccでは以下のworningが出力されています。 warning: return discards qualifiers from pointer target type これは、「リターンでポインターの型宣言が破棄されている」ということです。 const宣言は、「変数の内容が変更できない」と意味なので、誤って変更してしまうバグを予防するために使用されます。この場合は、scanf()で読み取る文字列ですから、内容が変更され使用方法が矛盾しています。 const宣言は一般的にメッセージや定数などの内容を変更してはならない変数(記憶領域)に対して使用されます。特に変数がROMにある場合には、その変数に書き込むとプログラムの実行時にCPUの動作が異常になります。 (割り込み処理に移行したり停止したりする) したがってconstの使用はバグの予防対策として実装されているのです。 あとは、main()の scanf()とprintf()の見直しですね。

関連するQ&A

  • C言語 ポインタと配列

    #include <stdio.h> /* scanf("%c", &search); ではなく scanf(" %c", &search); であることに注意する */ char *str_chr(const char *str, char c) { char *find; find = NULL; do { if(*str == c) { find = (char*)str; break; } } while(*str++); return(find); } int main(void) { char str[100] = {0}; char search; char *find; printf("文字列を入力してください:"); scanf("%s", str); printf("検索する文字を入力してください:"); scanf(" %c", &search); find = str_chr(str, search); if(find == NULL) { puts("検索した文字は見つかりませんでした。"); } else { printf("検索した文字 %c は\"%p\"にあります。\n", *find , find); } return(0); } このコードのfind = (char*)str;の (char*)str;の部分がどうなっているのかわかりません。 あとこのfindというのは&find[0]という解釈でいいでしょうか? 教えてくださいm(_ _ )m

  • C言語 文字列の操作

    文字Cが含まれる個数を求めたいです #include <stdio.h> int str_chnum(const char str[],int c) { int i; int count=0; for(i=0;str[i]!="\0";i++) if (str[i]==c) count++; return(count); } int main(void) { char st[100]; printf("検索文字列を入力してください:"); scanf("%s",st) ; printf("検索文字列数は%uです。\n",st,int str_chnum(const str[],int c)); return(0); } コンパイルできません。なぜですか?printfの行がたぶん間違っていると思うんですが。。。

  • std::stringクラスのc_str()で取得した文字列をいじることは可能ですか?

    c++で、以下のようなコードは問題ないでしょうか? // chrの中身の小文字を大文字にする void func(char* chr); std::string str("aaa"); const char* str_p = std.c_str(); func((char*)str_p); ←これは大丈夫ですか? //このあとstrに対して文字列を追加したりいろいろ処理する。 このようにc_strで取得したconst char*をconstをはずして 強引にいじくることは問題ないでしょうか?

  • 文字列中に含まれる文字の個数をカウントするプログラムについて…

    文字列、1文字が与えられたとき、これをポインタで入力し文字列中に含まれる文字の個数を計算するプログラムを作成せよ。 と、いう課題がだされたんですけど、ユーザが任意の文字列と1文字を入力できるようにすることができません…。 多分main関数の部分をちょっといじくればよいと思うのですが…。 どなたかアドバイスをお願いします。 #include <stdio.h> int count(const char *str, const char ch) { int cnt=0; while (*str!='\0') { if (*str==ch) cnt++; str++; } return cnt; } int main() { const char *str="hello,world!"; const ch='o'; int cnt; cnt=count(str, ch); printf("%s中に%cは%d個です\n", str, ch, cnt); return 0; }

  • 文字列リテラルの比較について

    下記のプログラムの疑問点を教えて頂きたい。 (1)mainの実引数(ch[0]は、str_chr関数を呼ぶ場合、intの型変更する理由、 (2)cをキヤストしてchar 型変更した後、再度int C に代入する理由 (3)char型*Sとint 型Cでは、型が違うのに何故比較できる理由 char *str_chr(const char *s, int c) { c = (char)c; while (*s != c) { } main { char ch[2]; str_chr(G,ch[0]) main {

  • C言語で文字列をかえす正しい書き方が知りたいです?

    C言語で次の警告が表示されます。 文字列を返したいのですが、正しい書き方はどのようにすれば良いのでしょうか? jci.h(20) : warning C4172; ローカル変数またはテンポラリのアドレスを返します。 char *test(char *a, int b) { char str[BUFSIZ]; return str; <------ }

  • 文字列の扱い方

    初歩的な質問ですみません… str文字列からcという文字を見つけたら添字を返すという関数を作ったのですが、 iにこの関数を代入して、if文の制御式にiを使って比較するまでは正常なのですが、 真文にiを使うと何故か偽文(という言い方でいいのでしょうか…この場合("そんな値はありません。"というところです)が実行されてしまいます。 よろしければご教授お願い致します。 #include <stdio.h> int str_char(const char str[],int c) { int len = strlen(str); int i; for (i = 0;i < len;i++) { if (str[i] == c) return i; } return -1; } int main() { char str[64] = "Fucking Brutal Death Metal"; int ch,i; printf("どの文字を調べますか?"); scanf("%c",&ch); i = str_char(str,ch); if (i >= 0) printf("その文字は%d番目にあります。",str_char(str,ch) + 1); //何故かiだと動かない else printf("そんな値はありません。"); return 0; }

  • C言語文字数4つカウント

    こんにちは。大学の課題で「キーボードから入力した文字数に含まれる'h''o''g''e'の4つの文字数をカウントする関数を含むプログラムを完成させよ」という課題がありました。なかなかできず現段階では以下のようになっています。どうすれば問題文のように実行できますか? #include <stdio.h> char str_chnum(const char str[], int ch) { int count = 0; int i; for(i = 0; str[i] != '\0'; i++) { if(str[i] == ch) count++; } return(count); } int main(void) { char str[128]; int ch; printf("文字列を入力してください:"); scanf("%s", str); printf("検索する文字を入力してください:"); scanf(" %c", &ch); printf("%cは%d個ありました。\n", ch, str_chnum(str, ch)); return(0); }

  • C言語 文字列操作

    トリム関数とリムーブ関数を作成してみました。改良点はありますでしょうか? ~~~~以下ソース~~~~ #include <stdio.h> #include <stdlib.h> #include <string.h> char *Trim(char *str); char *Remove(char *str, char *rmv); void main(void) {  char str[10], rmv[10], *p;  int c;  /* " abcd "をトリムする */  strcpy(str, " abcd ");  printf("トリム前 |%s|\n", str);  p = Trim(str);  printf("トリム後 |%s|\n", str);  /* 指定文字列を削除する */  printf("削除する文字列を入力してください :");  scanf("%s", rmv);  Remove(str, rmv);  printf("削除後 |%s|\n", str);  exit(0); } char *Trim(char *str) {  char space[] = " ";  char null[] = "";  int index = 0;  while(1){   if(strcmp(&(str[index]), null) == 0){    index--;    if(strncmp(&(str[index]), space, 1) == 0){     strcpy(&(str[index]), &(str[index]) + 1);    }else{     break;    }   }else{    if(strncmp(&(str[index]), space, 1) == 0 && index == 0){     strcpy(&(str[index]), &(str[index]) + 1);    }else{     index++;    }   }  }  return str; } char *Remove(char *str, char *rmv) {  int c, size, i;  char *p;  c = '\0';  p = strchr(rmv, c);  size = p - rmv;  for(i = 0; i < size; i++){   c = (int)rmv[i];   p = strchr(str, c);   if (p != NULL) {    strcpy(&(str[p-str]), p + 1);   }   else{    printf("""%c""は見つかりませんでした\n", c);   }  }  return str; }

  • 関数について

    char *str_char(const char *str, int c) { while (*str++) if (*str == c) return ((char *)str); return (NULL); } /*文字列strから文字cを検索し最初に存在する文字へのポインターを返す*/ 上記関数なのですが 5行目を return (str); にしてはなぜいけないのでしょうか。

専門家に質問してみよう