• ベストアンサー

ポインタで詰まりました;

こんばんわ、私は今仕事の合間をぬって独学でCとPerlを学んでいます。 まだやりはじめてから程無いのですが、ポインタに入ったところでつまづいてしまいました;(使い方がわからなくてパニックに; 以下の4つの問題、ポインタを使ったらどうやればいいのか教えてもらえないでしょうか? 1) 文字列の長さを求める関数を、ポインタを使って作成。 2) 文字列を比較する関数を、ポインタを使って作成。 一致の際(0)不一致の際は(1)を返す 3) 文字列中に含まれる、指定した文字の個数を求める関数を、ポインタを使って作成。 「what is this.」の場合、指定文字が「w」の場合は個数1を返す 4) 文字列中に含まれる単語の個数(スペースで区切られた部分)を求める関数を、ポインタを使って作成。 「ehat is this.」の場合、個数は3を返す。 私が今どのくらいの実力があるかといいますと、ほんと初心者同然です。 なので出来るだけ分かりやすく書いてくれると嬉しいです; よろしくお願いします(ノД`

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.8

★問題3と問題4の実装例 問題3:指定文字の個数を求める(C言語のstrchr関数と似た動作) int MyStrCount( const char *string, int c ) {  const char *p;←ポインタ変数  int count = 0;←カウンタ変数(0で初期化)    for ( p = string ; *p != '\0' ; p++ ){←文字列の最後まで調査   if ( *p == (const char)c ){←cはint型なのでキャストする    count++;←指定文字ならカウント   }  }  return( count );←個数を返す } ●解説 ・問題1を改良して指定文字の比較とカウント処理を追加した ・c は int型、*p は char型で型が違うため比較のときや代入時はキャスト演算を行う ・指定文字の個数が多い場合は、int型から long型に変更しましょう 問題4:単語数を求める(C言語のstrspn関数とstrcspn関数との組合せ) int MyWordCount( const char *string ) {  const char *p;←ポインタ変数  int count = 0;←カウンタ変数(0で初期化)    for ( p = string ; *p != '\0' ; ){←文字列の最後まで調査   while ( isspace(*p) ){←空白文字をスキップ    p++;   }   if ( *p == '\0' ){←文字列の最後なら抜ける    break;   }   while ( !isspace(*p) && (*p != '\0') ){←空白文字以外(英数字など)をスキップ    p++;   }   count++;←単語数をカウント  }  return( count );←単語数を返す } ●解説 ・連続する空白文字と連続する英数文字などを1つのブロックとして単語数を数える ・文字列の最後に注意して調査を行う ・isspace関数は空白文字判別の関数です(スペース、タブ、改行など) ・単語数の個数が多い場合は、int型から long型に変更しましょう 注意: ・上記は半角文字列を対称(全角文字は未対応) ・上記の実装例は全て文字列にNULLポインタを渡すと致命的エラーが発生 ・空文字列ならば致命的エラーは発生しない

hope4673
質問者

お礼

お礼が遅くなってしまい申し訳ないですorz たった今長期出張から帰ってきました(ノД。。 投稿どうもありがとうございます! しかも丁寧に2ページ+解説まで; やるのは明日になりますが、参考にさせてもらいますね^^;

その他の回答 (7)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.7

ポインタ: ・ポインタは文字列のような実体の先頭アドレスを表している ・配列は添え字で参照しますが、ポインタは * 文字ですぐに参照可能 ・文字列の最後はNULL文字(00h)が終端 ・空文字列は、文字列の最初にNULL文字がくる文字列 ・NULL文字とNULLポインタ、さらに空文字列を区別して理解しましょう ・文字列の内部表現を良くお勉強しましょう ・#6 さんの改良バージョンです(NULL文字をNULLポインタで表現するのは間違い) ★問題1と問題2の実装例 問題1:長さを求める(C言語のstrlen関数と同じ) int MyStrLen( const char *string ) {  const char *p;←ポインタ変数    for ( p = string ; *p != '\0' ; p++ ){←文字列の最後まで移動   ;←何も処理しないことを表現するコツ  }  return( p - string );←文字列の最後から先頭のアドレスを引く=長さが求まる } ●解説 ・文字列のポインタは文字列の先頭アドレスのこと ・よって、文字列の最後まで移動してアドレスを引き算することで簡単に長さが求まる ・const 修飾子は参照専用のポインタであることを宣言するため(なくても良いが) 問題2:文字列を比較する(C言語のstrcmp関数と同じ) int MyStrCmp( const char *string1, const char *string2 ) {  while ( *string1 == *string2 ){←文字列が同じときの処理   if ( *string1 == '\0' ){←文字列の最後なら完全一致    return( 0 );←一致   }   string1++;   string2++;  }  return( 1 );←不一致 } ●解説 ・文字列ポインタの文字を参照して違えば直ちに不一致 ・同じときは、文字列の最後をチェックして最後なら完全一致 ・同じときでも文字列の最後でなければ次へ進むを繰り返す

回答No.6

1) 文字列の長さを求める関数を、ポインタを使って作成。 Stringに何かデータを入れる(データの終焉はNULLとする) int DataLenFunc( char *String ) { char *p;// ポインタ int DataLen; // データ長 DataLen = 0; // 初期化 for( p=String ; *p!=NULL ; p++ )// NULLになるまで {     DataLen++; // データ長カウントアップ }   return DataLen; } 2) 文字列を比較する関数を、ポインタを使って作成。 一致の際(0)不一致の際は(1)を返す int CmpFunc( char *DataStr1 , char *DataStr2 ) { char *p; char *q; int DataLen1; int DataLen2;  // 1の関数でデータ長を調べる Datalen1 = DataLenFunc(DataStr1); Datalen2 = DataLenFunc(DataStr2); if( DataLen1!=DataLen2 ) // データ長が一致しない return 1; // 比較 for( p=DataStr1 , q=DataStr2 ; *p!=NULL || *q!=NULL ; p++ , q++ ) { // 一致しなければ if( *p!=*q ) return 0; // エラーとして戻る } // ここまできたら正常 return 1; } 3) 文字列中に含まれる、指定した文字の個数を求める関数を、ポインタを使って作成。 「what is this.」の場合、指定文字が「w」の場合は個数1を返す //呼び出し char MotoData[100]; char *ShiteiMozi; int Kosuu; memset( MotoData , 0x00,sizeof(MotoData));//NULLクリア strcat( MotoData , "what is this." );// データセット *ShiteiMozi='w'; Kosuu = KosuuFunc( MotoData , ShiteiMozi ); int KosuuFunc( char *MotoData , char *ShiteiMozi ) { char *p; int Kosuu;//個数 Kosuu=0;//まずは0 for( p=MotoData ; *p ; p++ ) { if( *p==*ShiteiMozi ) Kosuu++;// 指定文字と一致するならカウントアップ }   return kosuu; } とりあえず1から3まででした。

hope4673
質問者

お礼

だいぶ遅くなりましたが、投稿ありがとうございます! やっと明日時間が取れるので、問題をやりながら参考にさせていただきますね^^;

回答No.5

配列形式([]演算子)を使ったからといって、(厳密に言えば)ポインタを使わないことにはなりません。 何故ならば、Cにおいて配列参照というものは全てポインタ参照で実現されるからです。 このことから、 anyType_t * pointer; // 任意の型のポインタ anyInteger_t integer; // 任意の整数型 としたとき、pointer[integer]と*(pointer + integer)は全く同じ意味になります。 #勿論、* pointerはintegerが0と考えて、pointer[0]と書けます。 尚、変数の定義のときはもう少しややこしくなるので要注意。 次の定義の意味の違いを理解しておくと、ポインタ演算が理解しやすくなると思います。 char str1[] = "abc"; char str1_2[] = {'a', 'b', 'c'}; // ナル文字がないから文字列として使えないので要注意 char str1_3[10] = {'a', 'b', 'c'}; // この場合は0(つまりナル文字)が補われるので文字列としても使える char * str3 = "def"; // これはただのポインタ変数(正しくはconst char * str3)

hope4673
質問者

お礼

回答ありがとうございます^^; ふむふむ、丁寧に細部まで説明してくださってありがとうございます。 とても分かりやすい説明でした。 次に問題をやる時も、書かれている点を注意しながら他の方の回答と照らし合わせながらやってみますね。 返信が送れて申し訳ないでした(ノД

  • yonfa
  • ベストアンサー率52% (22/42)
回答No.4

単語数を求めるのはこんなものでしょう。 スペースがどこにいくつ入っていても単語数を出せます。 int Words(char *str) {  int count = 0;  char *p = str;  while(*p != 0){   // スペースを任意文字分読み飛ばす   while(*p == ' '){    p++;   }   // 文字列の終わりか確認   if (*p != NULL){    // 単語数を加算    count++;    // 単語を読み飛ばす    while((*p != NULL) && (*p != ' ')){     p++;    }   }  }  return count; }

hope4673
質問者

お礼

回答ありがとうございます^^; 今日はゆっくり見る時間が無く、時間ができたときにじっくり読んで参考にさせてもらいますね。 返信が遅くなってしまい申し訳ないです(ノД

  • entree
  • ベストアンサー率55% (405/735)
回答No.3

C 言語には文字列型というのは存在しないため、文字列を表すために char 型の配列を使用します。あと、文字列の終端を表すために、NULL 文字 '\0' を使用します。以下、一例を提示しておきますので参考にしてください。 (1) int func1(char *arg) {  int len = 0;  /* NULL 文字のところまでポインタを移動していき、  そこまでに含まれている文字数をカウント */  while (*arg != '\0') {   arg++; len++;  }  return len; } (2) int func2(char *arg1, char *arg2) {  /* とちらかの文字列が終端に達するか、  2つの文字列で違うところが現れるまでポインタを移動 */  while (*arg1 != '\0' && *arg2 != '\0' && *arg1 == *arg2) {   arg1++; arg2++  }  /* 2つの文字列が完全に一致していた場合 */  if (*arg1 == *arg2)   return 0;  return 1; } (3) int func3(char *str, char t) {  int count = 0;  while (*str != '\0) {   if (*str == t)    count++;   str++;  }  return count; } (4)少し面倒ですね。スペースが連続して複数含まれないのであれば、以下のように簡単にできるんでしょうけど。。。 int func4(char *str) {  return func3(str, ' ') + 1; }

hope4673
質問者

お礼

回答ありがとうございます^^; ちょっとパっとみただけでは、どこがどう働いているのか分からないで、時間ができたときに参考にさせてもらいますね。 返信遅くなってすみませんです(ノД

回答No.2

   "スペース"以外の区切り文字は考慮せず。 #include <stdio.h> int Characters(char *str) { int i; for(i = 0; *(str + i) != '\0'; i ++) ; return i; } int Compare(char *str0, char *str1) { char *p0, *p1; for(p0 = str0, p1 = str1; *p0 != '\0' && *p1 != '\0'; p0 ++, p1 ++){ if(*p0 != *p1) return 1; } return *p0 != *p1; } int Search(char *str, char c) { int count = 0; char *p; for(p = str; *p != '\0'; p ++) count += (c == *p); return count; } int Words(char *str) { int count = 0, word = 0; char *p; for(p = str; *p != '\0'; p ++){ if(*p != ' ') word ++; else{ count += (word > 0); word = 0; } } return count + (word > 0); } int main(void) { char *str = "What is this?"; char *str0 = "What is that?"; char *str1 = "What is this?"; printf("%d\n", Characters(str)); printf("%d\n", Compare(str, str0)); printf("%d\n", Compare(str, str1)); printf("%d\n", Search(str, 'W')); printf("%d\n", Words(str)); return 0; }  

hope4673
質問者

お礼

回答ありがとうございます^^; 仕事が終わり家についたのがついさっきで、返信が遅くなりました; 明日、もしくは明後日でも時間ができたらさっそくやってみますね。 明日も仕事だし、今日はもう・・できない(ノД ありがとうございました^^;

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

同じ問題をポインタを使わずに、たとえば配列として文字列にアクセスするという形なら解けますか? もしそれでも解けないのなら、ポインタ云々以前の問題です。 まあそれはおいといて。 1) は、最初に文字列の先頭にポインタの指し位置を合わせておいて、 文字列の終端が見つかるまでポインタの指し位置をずらしていっていけばよいです。 ポインタを増やすときに文字数のカウンタを増やしてもいいし、 終端が見つかったところで先頭からの距離で計算しても良いです (ただし off-by-one エラーに注意) 2) は、ポインタを二つ用意してそれぞれ文字列の先頭に合わせておいて、 比較 → ポインタのインクリメント を短いほうの文字列が終わるまで 繰り返せばよいです。 3) 1)と同じくポインタの指し位置をずらしながら先頭から終端までなめていって、 検指し位置にある文字が検索しているものだったらカウンタを増やしてやるという 手順でできます。 4)はポインタを文字列の先頭から終端までずらしていく操作をする中で、 単語を構成する文字種にはいったらフラグをたて、構成する文字種でない 文字がきたらフラグを寝かせるということを繰り返し、フラグが立った回数を数えれば それが単語の数になります(ハイフネーションと改行のコンボがないとして)。

hope4673
質問者

お礼

さっそくの回答ありがとうございます! 1と2は質問を書いた後、ポインタを使わないでやってはみたので、少し書いてみますね。 (1) { char a[50]={0},x; scanf("%s",a); for(x=0;x<50;x++) { if(a[x]=='\'0) { break; } } printf("%d",x); return 0; } (2) char sub(char 1,char b) { if(a==b) { return 0; } else { return -1; } } int main(void) { char a,b,c; scanf("%c %c",&a,&b); c=sub(a,b); printf("%d",c); return 0; } すごい読みにくい、とは思いますがこんな感じでやってみました。 3と4は時間が無くて手つけられませんでした・・ 後ほど時間が出来次第、No.1さんのと照らし合わせながらまたやってみます。 今朝はこれから会社があるので時間がなくて;; 私だったらこう書く、こんなヒントもあるよ、答えはこうだよ、みたいな投稿でもいいのでどんどんお願いします。 色々な方のプログラムの書き方なども、とても見てみたいので。 朝早くから親切に回答どうもありがとうございました、返信があわただしくて読みにくい文章となってしまって申し分けないです; それではまた夜に^^;

関連するQ&A