• 締切済み

C言語で文字列操作のアルゴリズム

C++言語で char s[] = "AAABBBCCCDDDEEE"; という文字列があり、 3バイト毎、取り出して前に*をつけ *AAA s=[BBBCCCDDDEEE] *BBB s=[CCCDDDEEE] *CCC s=[DDDEEE] *DDD s=[DDD] *EEE s=[] のように表示させるプログラムで、 最後だけは3文字とは限らない場合も考慮した 最終的にsが空になるアルゴリズムを考えていますが 何か良い方法はありますか? 例)最後が3文字でない場合 *EE s=[] 2文字でした。

みんなの回答

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

#1 を C で書くなら #include <stdio.h> #include <string.h> void foo(const char *str, int width) { const char *p = str; size_t len; for (len = strlen(str); len >= width; len -= width, p += width) printf("*%.*s s=[%s]\n", width, p, p+width); if (len) printf("*%s s=[] %zu文字でした\n", p, len); } オーバースペック?

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.7

No.5 です。 No.6 さんの >美しくない>#5. >#4 を取り込めば cBak が不要になり, その結果 if の条件を < ではなく <= にすることができる.  確かに美しくなかったですね。  ・No.4 さんの「回答」をじっくりと見れば良かった、と反省。   ( → 早速、ブラウザのフォントを変更しました)   (プロポーショナルだと見づらくて・・、というか)勉強になりました。   今まで、この手の処理は、#5 のように「待避/復帰」で行っていました。   http://www.k-cube.co.jp/wakaba/server/format.html で、懲りもせず、「ポインタでの処理」によるソースを投稿します。 ★ No.6 さんも、#1 をコード化し、投稿してみませんか。 #include <stdio.h> #include <string.h> #define Tocyu(p) ((*p)*(*(p+1))*(*(p+2))) int main() {  char s[ 64 ] = "AAABBBCCCDDDEEE", *p;  p = s;  while( 1 ){   if( Tocyu( p ) ){    printf( "*%.3s s=[%s]\n", p, ( p + 3 ) ); // #4 さんのをパクリ    p += 3;    if( '\0' == *p ) break;   }   else{    printf( "*%-3s s=[] %d文字でした。\n", p, ( strlen( s ) % 3 ) );    break;   }  }  return( 255 ); } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

美しくない>#5. #4 を取り込めば cBak が不要になり, その結果 if の条件を < ではなく <= にすることができる. これで仕様通り. もちろん添え字の代わりにポインタを走らせることもできて, その方がもうちょっと C っぽいかもしれない. あと, for の中で毎回 if を通るのもアレなのでそこは for の条件を工夫して回避するといい... って, こうやっていくと最終的に #1 になりますが. ああ, #1 も while じゃなくて for の方がよりきれいでしょうね. もちろん p + =3; は p += 3; の間違い.

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.5

>最後だけは3文字とは限らない場合も考慮した  「配列の添え字」による処理でのソースを投稿します。  最後が3文字の時も「3文字でした。」のメッセージが付いちゃうけど・・。   → 最後が1,2,3文字でも共通処理(先頭 else の行)です。 >最終的にsが空になるアルゴリズムを考えていますが  「ポインタ」で処理し、文字列終端までポインタが移動=空、ということでしょうか?。  それでしたら↓は、参考程度に・・。 #include <stdio.h> #include <string.h> int main() {  int i, iLen;  char s[64] = "AAABBBCCCDDDEEE", cBak;  iLen = strlen( s );  for( i = 0; i < iLen; i += 3 ){   if( ( i + 3 ) < iLen ){    cBak = s[ i + 3 ];    s[ i + 3 ] = '\0';    printf( "*%-3s s=[%c%s]\n", &s[ i ], cBak, &s[ i + 4 ] );    s[ i + 3 ] = cBak;   }   else printf( "*%-3s s=[] %d文字でした。\n", &s[ i ], ( iLen - i ) );  }  return( 255 ); } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

文字列をコピーしなくても、 printf("*%.3s s=[%s]\n", … とすれば済むように思います。

回答No.3

全体の文字数を把握して、必要な文字数だけ、コピーして、毎回表示する。 基本は #1 のやり方がいいと思います。 プログラムなんて、人が書いたようにしか動きませんから わからないときは、やろうとしていることをまずは机上で「人間」が処理して 今やったことを細かく分析するとくめるようになりますよ。 コンパイラの気持ちになって、処理してあげてください(笑 > 最後だけは3文字とは限らない場合も考慮した > 最終的にsが空になるアルゴリズムを考えています あなたなら、この部分(最後だけは3文字にならなった事)をどういう手段で「理解」しますか? ただ、Cの場合、「移動」という手段を持っていないので 移動したい場合、 移動先へ「コピー」して移動元を「削除」することになります。 今回の場合、先頭部分を削除するだけなので、sの開始位置をずらすだけで 削除の代替となります。 もしも、中間を削除したいと思ったら、削除する部分よりも 先の部分をすべてコピーして削除部分に上書きするイメージになります。 その場合は、同一のメモリアドレスとなるので、memmove(3)を利用してください。 中間部分の削除もやってみればおもしろいと思いますよ。 http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strcpy.3.html, http://www.linux.or.jp/JM/html/LDP_man-pages/man3/memmove.3.html

回答No.2

#include <stdio.h> #include <string.h> int main(void) { int i; char s[]="AAABBBCCCDDDEE"; char buf[5]="*___"; //buf[0]を'*'に、buf[4]を'\0'に初期化 char *p; for (p = s;*p;) //ヌル文字になるまで実行 { strncpy(&buf[1],p,3); //最大3文字コピー for (i = 0;i < 3;i++) //いきなりpに+3しないのが重要 { if (!*++p) break; //ヌル文字が来たら中断 } printf("%s s=[%s]\n",buf,p); } return 0; }

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「s が空になる」の意味はわからんけど.... 長さが 2以下であるような, 最後のときだけ特別扱いすればいいだけではないかな. p=s; 残り長さ=strlen(p); while (残り長さ >= 3) { 上のような表示 p + =3; 残り長さ -= 3; } if (残り長さ) { 最後の表示 } って感じ.

関連するQ&A