• ベストアンサー

関数について

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

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

  • ベストアンサー
  • ency
  • ベストアンサー率39% (93/238)
回答No.8

const は難しいですね。 でも、使い方は覚えておいたほうが良いですよ。 char *str_char(const char *str, int c); という関数の場合、第一引数 str は「const な char型を指すポインタ」ってことですよね。 # ここまでは問題ないんですよね? ということは、この関数は「第一引数に渡された文字列は変更しません」ということを表明していることになります。 char型 → const char型の暗黙の型変換は、コンパイラが勝手に行います。 読み書き可能な char型から読み取り専用の char型への変換は、条件が厳しくなる方向の変換ですから問題ないわけです。 でも、const char型 → char型の暗黙の型変換は、コンパイラによってエラーになります。 読み取り専用の char型から読み書き可能な char型への型変換は、条件がゆるくなる方向の変換ですから、使う側が意図しない動作になってしまう可能性があるわけです。 そう考えるとご質問の、「return (str); にしてはなぜいけないのでしょうか。」の答えもお分かりになるのではないでしょうか。 const char型 → char型の型変換にエラーが出るのであれば、それぞれのポインタ同士の型変換でもエラーが出るのは当然でしょう。 ところで、No4 で BLUEPIXY さんが「戻り値も const char* 型にすべき」というような回答をされておりますが、私はちょっと違う見解です。 # そういうことではない、という場合、私の勘違いです。 # 申し訳ありません。。。 str_char() の目的は「文字列中のある文字と最初に一致する場所を返す」ことです。 ということは、この関数のコール元ではそこの場所にある文字になんらかの操作を加えたい可能性も十分にあると思います。 引数の const はあくまで「渡された文字列に変更は加えません」という意思表示でしかないと思います。 戻り値に関しては、特に問題ないと思います。 # でも、const char* → char* のようなキャストは極力しないほうが良いのは # 確かです。 私のサンプルコードはこんな感じです。 # 中括弧つける派なものでして。。。 -------------------------------------------------------- #include <stdio.h> char *str_char( const char *str, int c ) { int i; for ( i=0; str[i] != '\0'; i++ ) { if ( str[i] == c ) { return (char*)&str[i]; } } return NULL; } int main( void ) { char hoge[] = "ABCDEFGHIJKLMN"; char *piyo; piyo = str_char( hoge, 'C' ); if ( piyo == NULL ) { printf( "Fail to match...\n" ); } else { printf( "Success to match! ->%c\n", *piyo ); /* piyo 以降の文字列を書き換えるのもあり! */ } return 0; } --------------------------------------------------------

その他の回答 (9)

  • ency
  • ベストアンサー率39% (93/238)
回答No.10

> まったく、その通りですね。 > #8さんが、的を射た答えですね。 > #4は、言い過ぎです。すみません。<(_ _)> いえいえ。。。 ポインタ渡しの関数を作るときに、私がよく使う手でしたので、ちょっとコメントさせてもらっただけです。 そこまで言っていただけると、ちょっと恐縮です。。。 ポインタを引数にとる関数のコメントに「IN/OUT」というのをたまに見かけますけど、そんなことをやるよりも const のありなしでやるほうがよっぽど効果があると思っています。 const なしの場合は、関数で中身を変更される可能性があるし、const つきの場合は絶対に変更されないことが保障されるわけですから。。。 # そもそも、私の場合コメントはあまり信用していませんし。 # あとで更新しようと思って、そのまま放置されていることが結構ありますし。。。 …やばい。。。関係ない話で雑談モードに入りそうなので、この辺で失礼します。

buafk516
質問者

お礼

とてもよくわかりました 本当にありがとうございました

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.9

>引数の const はあくまで「渡された文字列に変更は加えません」という意思表示でしかないと思います。 >戻り値に関しては、特に問題ないと思います。 まったく、その通りですね。 #8さんが、的を射た答えですね。 #4は、言い過ぎです。すみません。<(_ _)> 実際の所、 同様の関数strchrのプロトタイプ宣言は、 char *strchr(const char *s, char c); になってますしね。 結局の処は、そういうものは、(constで受けてconstで返すかどうかというのは)プログラマにゆだねられている(そういう状況が必要かどうか)ということですよね。(なんでもかんでもキャストすればいいってものでもないし) C++で言えば、constのメンバ関数とでもいうところですか・

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.7

>while (*str++) 質問者は、既に判っておられると思いますが 正解ではありません。 結局の処、他人の20年の経験なんてあてにはなりません。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.6

#2です。 失礼しました。5行目と6行目を見間違えた挙句に間違ったこと書きました。 で、5行目をreturn(str);に出来ないのは 戻り値の型がchar*であるため。 #4の方が書かれたように、戻り値をconst char*にすれば return(str);と記述できます。 ちなみに、constは、ちゃんとしたライブラリを使うor作るのでしたら必ず意識が必要です。忘れていいわけがありません。 constがあれば、関数を呼び出した先で変更される可能性があるのか無いのかがはっきりとします。 特にWindowsAPI等は、かなり厳格にconstの有無で引数のIOが理解できます。 また、C++になりますが、クラスの内部のポインタを返すときに、 constをつけないで返すとライブラリの使用者にインスタンス内部を破壊される恐れもありますので必須です。 constは、つまり「間違った使い方をしないように」と口頭でお願いするのではなく、「間違って使おうとしてもつかえません」とするためのだと思ってください。

回答No.5

No.1の補足に対する回答。 まず、わたしのプログラムにある誤記を示しておきます。 while (str++)  ↓ while (*str++) が正解です。次に「5行目」の件ですが、「{」だけの行も行数として数えますので、N0.2さんの回答とは大いに違ったものになっています。 でも、「NULL Pointer」というのもアリですから、 return (NULL); はそのままとしておきました。これは「6行目」ですからね。 さて本題に入ります。問題は"const"の使いかたにあるのですが、これは他の方が回答されていますね。 私が言いたいのは、20年も仕事でCを使い込みましたが、"const"を使用するチャンスはゼロでした。なので、"const"はお忘れになったほうがいいとおもいます。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

#include <stdio.h> /* 文字列strから文字cを検索し最初に存在する文字へのポインターを返す */ const char *str_char(const char *str, int c) { for (; *str; str++) if (*str == c) return (str); return (NULL); } int main(void) { const char *p; char str[10]; char uletter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; printf("検索する英大文字を入力してください:"); scanf ("%s", &str); p = str_char(uletter, str[0]); if (p != NULL) puts(p); return (0); } としてみたら? --------------------- なぜいけないかといわれたら、 const char *str ということは、 *str='a'; とかしてはいけないということです。 それを char *p; に p=(char *)str; とかして、 無理やりキャストして代入したとすると *p='a'; を(やるかどうかは別として可能性として)許すということですが、 もともと*strの部分は、constだから変更してはいけないのに、変更を許すということです。 だから いけないのです。 もし、そうした変更を許すなら、 引数として const char * 宣言する方がおかしいのです。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

const 文字列へのポインタなのに、 const じゃないポインタとして返したら ダメなような気がします。 このプログラムって先頭にある文字cを見つけることはできますか?

buafk516
質問者

補足

回答を確認すると以下のようになっていました 関数str_char のstrは mainのstr[0]の番地を格納していて そのstrがインクリメントされていきcと同じであれば str(cと同じ文字を格納しているアドレス)を返すのですよね? 関数str_char の返却値もポインタなのですから わざわざ return ((char *)str) とcharへのポインター型にキャストしなくても そもそも str 自体がアドレスを格納しているポインタ変数だから return (str) でいいのではないでしょうか。 return (str) のままでコンパイルすると、やはり エラーがでます。 難しい>< /*   読み込んだ英大文字以降のアルファベットを表示 */ #include <stdio.h> /* 文字列strから文字cを検索し最初に存在する文字へのポインターを返す */ char *str_char(const char *str, int c) {   for (; *str; str++)     if (*str == c)       return ((char *)str);   return (NULL); } int main(void) {   char str[10] , *p;   char uletter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";   printf("検索する英大文字を入力してください:");   scanf ("%s", &str);   p = str_char(uletter, str[0]);   if (p != NULL)     puts(p);   return (0); }

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

別にいけなくはないですが。 ただし、見つからなかったときはNULLを返すと仕様が決まっているんでしたらNULLにしないとまずいですが。 逆に、見つからなかったときははヌル文字の位置を返す仕様ならstrじゃないとまずいですし。

回答No.1

すっきり書くとこうなります。 ―――――――――――――――――――――――――― #include <stdio.h> char *str_char(char *str, int c) {   while (str++)     if (*str == c)       return (str);   return (NULL); } void main( void ) {   static char *x="abcdefghij";   printf("%s\n", str_char(x, 'd')); } ―――――――――――――――――――――――――― ね、ちゃんとreturn (str);と書けますね。 元のプログラムと、文法書を引っ張り出して考えてください。難しく考えないことです。 (Visual C++6.0で検査済み)

buafk516
質問者

補足

char *str_char(char *str, int c) ここで引数と返却値の型をあわせてあげて、その後 return (str)にすると考えていいのでしょうか 例えば const char *str_char (const char *str, int c) の場合なら (返却値にconstを使えるのかどうかわかりませんが・・) 文法的に return (str)にすることができて const char *str_char (char *str, int c) の場合だと return ((const char *) str) にしなければいけない ということでしょうか。

関連するQ&A

  • 文字列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*)の意味が根本的にわかりません。 質問ばかりですみません。初心者でポインタがどうにも理解できないんです。 誰か詳しい人教えてください。 お願いします。

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

    文字列、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; }

  • 前回質問させて頂き、改善できるところはしました。

    前回質問させて頂き、改善できるところはしました。 再度駄目な所をご指摘お願いします。 仕様は出来るだけ標準関数に近いものを自作したいと思っています。 //---------------------------- MyStrstr ----------------------------------// char *MyStrstr(const char *str1, const char *str2) { const char *p1 = str1; const char *p3 = str1; const char *p2 = str2; while(*p1 != *p2 && *p1 && *p2) { *p1++; *p3++; } while(*p1 == *p2){ *p1++; *p2++; } return (*p2 ? NULL : (char*)p3); } //------------------------------ 終了 ------------------------------------// //---------------------------- MyStrcat ----------------------------------// char *MyStrcat(char *str1, const char *str2) { char *p1 = str1; const char *p2 = str2; while(*p1 != NULL){ p1++; } if(*p2){ while(*p2 != NULL){ *p1 = *p2; p1++; p2++; } } if(*p2 == NULL){ *p1 = *p2; } return p1; } //------------------------------ 終了 ------------------------------------// //---------------------------- MyStrcmp ----------------------------------// int MyStrcmp(const char *str1, const char *str2) { const char *p1 = str1; const char *p2 = str2; while(*p1 != NULL || *p2 != NULL){ if(*p1 == *p2){ p1++; p2++; }else{ if(*p1 < *p2) return -1; if(*p1 > *p2) return 1; } } return 0; } //------------------------------ 終了 ------------------------------------// //----------------------------- MyMemcpy -----------------------------------// void *MyMemcpy(void *str1, void *str2, size_t n) { char *p1 = (char*)str1; char *p2 = (char*)str2; while(n--){ *p1 = *p2; p1++; p2++; } return str1; } //------------------------------ 終了 ------------------------------------// //---------------------------- MyStrcpy ----------------------------------// char *MyStrcpy(char *str1, const char *str2) { char *p1 = str1; const char *p2 = str2; while( *p2 != NULL){ *p1 = *p2; p1++; p2++; } if(*p2 == NULL){ *p1 = *p2; } return p1; } //------------------------------ 終了 ------------------------------------// //---------------------------- MyMe

  • C++での戻り値について

    C++で以下のソースを書きました。 どうしてaaaは問題ないのにbbbはだめなのかがわかりません。 どちらも、func1()、func2()で設定した文字列・vectorのポインタを返したいです。 int main() { const char* aaa = NULL; std::vector<const char*>* bbb = NULL; aaa = func1(); bbb = func2(); } const char* func1() { const char* str = NULL; str = "test"; return str; } std::vector<const char*>* func2() { std::vector<const char*>* str2 = NULL; str2->push_back("test2"); str2->push_back("test3"); return str2; } 現在必要に迫られてC++勉強中です。よろしくお願いいたします。

  • strstr()関数の実装内容について。

    strstr()関数が、どのように実装されてるか知りたかったため、strstr.cの中身を見てみたのですが、 分らない処理がありました。 char * __cdecl strstr (const char * str1, const char * str2) {  char *cp = (char *) str1;  char *s1, *s2;  if ( !*str2 )   return((char *)str1);  while (*cp)  {   s1 = cp;   s2 = (char *) str2;   while ( *s1 && *s2 && !(*s1-*s2) )    s1++, s2++;    if (!*s2)     return(cp);     cp++;    }  return(NULL); } while文のネストの部分で、*s1 && *s2 && !(*s1-*s2)とありますが、 (*s1 && *s2) または !(*s1-*s2) のどちらか一方のみではまずいのでしょうか? 解説、アドバイスの程よろしくお願い致します。

  • strcat関数

    学校の課題で strcat関数と全く同じ働きをするmy_strcatを実装せよ という課題がでています。 strcatは char* strcat(char *dest, const char *str) で表され、文字列 strを文字列 dest に合成して 合成された新しい文字列として dest を返します。 例えば、dest = Japan, str = Korea だったら, 関数処理後に、 dest = JapanKorea を戻り値とします。 ********************************************* my_strcat実装について 実装段階で一番の問題になるのが、文字列のサイズです。 とりあえず、私の書いたコードを示します↓ char* my_strcat(char *dest, const char *src) { int i=0; int j=0; while(*dest) { dest++; i++; } while(*src) { *(dest+i) = src[0]; i++; src++; } *(dest+j) = src[0]; //put null at the end of dest return dest; } 試しにdest=Japan,str=Koreaでやってみたのですが、動きませんでした。 原因はdest の文字サイズを無視した無理やりなりな実装だと考えます。 C言語では文字のサイズを一度宣言したら、変えられないと思うので、困っています。 どなたかアドバイスをいただけないでしょうか。 よろしくお願いします

  • memcpy,memcmp,strcmp,strlen,strcat,

    memcpy,memcmp,strcmp,strlen,strcat,strcpy,strstr,strchr 以上の関数を自作しました。 ひとつひとつを見たときに動作を確認したところうまく出来たのですが、この関数をプログラムに組み込んだところうまく動作しませんでした。 どこか間違っているところがあったら指摘して頂きたいと思います<m(__)m> ちなみに標準関数と全く同じものにしたいわけではなく、それを自分なりに考えて作りたいという趣旨ですので、ご理解ください。 char *MyMemcpy(char *str1, char *str2, size_t n) { char *p1 = str1; char *p2 = str2; while(n--){ *p1 = *p2; p1++; p2++; } return str1; } void *MyMemcmp(void *str1, void *str2) { char *p1 = (char*)str1; char *p2 = (char*)str2; int n = 0, k = 0; while( *p1 != '\0'){ *p1++; n++; } while( *p2 != '\0'){ *p2++; k++; } if(n > k){ return str1; }else if(n == k){ return 0; }else if(n < k){ return str2; } } char *MyStrcmp(char *str1, char *str2) { char *p1 = str1; char *p2 = str2; int n = 0, k = 0; while( *p1 != '\0'){ *p1++; n++; } while( *p2 != '\0'){ *p2++; k++; } if(n > k){ return str1; }else if(n == k){ return 0; }else if(n < k){ return str2; } } size_t MyStrlen(const char *str1) { char *p1 = (char*)str1; size_t len = 0; while(*p1 != NULL){ *p1++; len++; } return len; } char *MyStrcat(char *str1, const char *str2) { char *p1 = str1; char *p2 = (char*)str2; while(*p1 != NULL){ *p1++; } while(*p2 != NULL){ *p1 = *p2; *p1++; *p2++; } return str1; } char *MyStrcpy(char *str1, char *str2) { char *p1 = str1; char *p2 = str2; while( *p2 != NULL){ *p1 = *p2; *p1++; *p2++; } *p1 = '\0'; return str1; } char *MyStrstr(char *str1, char *str2) { char *p1 = str1; char *p2 = str2; while(*p1 != *p2) { if(*p1 == '\0'){ return 0; } *p1++; } return p1; } char *MyStrchr(const char *str1, char str2) { char *p1 = (char*)str1; while(*p1 != str2) { if(*p1 == '\0'){ return 0; } *p1++; } return p1; }

  • 配列を返す

    ファイルから読み込んだ一行の文字列を読み込みカンマごとに区切って 返すというプログラムを関数化することで効率を図りたいと思います。 int main() { char buf[1000]; char *str; char *bufG; //ファイルを読み込む  while(fgets(buf,1000,fp) != NULL){//一行ずつ読む str = buf;//先頭アドレスを指す     bufG = //文字列を返す関数  ・  ・  ・ } } //文字列を返す関数 {    for(i = 0; *str != ',' && *str != '\0'; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; return bufG; } 前の質問で自動変数でこの関数を抜けたら廃棄になるというのは わかったんですが(そういう警告がでました) ここからどのようにすれば求めるプログラムになりますか? 引数とかちょとわからないので関数定義を書きませんでした。 (1)ファイルをよみこむ (2)一行ずつ読み込み文字列をbufにいれる (3)ポインタstrをbufの先頭アドレスにする (4)get_word関数にてポインタをずらしていき カンマがあればそこまでの文字列を返す (5)main関数に戻り変数に代入する (6)終端文字があるまで(4)ー(5)を繰り返す。 (7)さらに行数分繰り返す これらの一連の流れをやりたいのですが わかりません。

  • 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の行がたぶん間違っていると思うんですが。。。

  • 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

専門家に質問してみよう