アプリ版:「スタンプのみでお礼する」機能のリリースについて

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文字でした。

A 回答 (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);
}
オーバースペック?
    • good
    • 0

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 );
}
注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。
    • good
    • 0

美しくない>#5.


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

p += 3;
の間違い.
    • good
    • 0

>最後だけは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 );
}
注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。
    • good
    • 0

文字列をコピーしなくても、



printf("*%.3s s=[%s]\n", …

とすれば済むように思います。
    • good
    • 0

全体の文字数を把握して、必要な文字数だけ、コピーして、毎回表示する。


基本は #1 のやり方がいいと思います。

プログラムなんて、人が書いたようにしか動きませんから
わからないときは、やろうとしていることをまずは机上で「人間」が処理して
今やったことを細かく分析するとくめるようになりますよ。
コンパイラの気持ちになって、処理してあげてください(笑

> 最後だけは3文字とは限らない場合も考慮した
> 最終的にsが空になるアルゴリズムを考えています
あなたなら、この部分(最後だけは3文字にならなった事)をどういう手段で「理解」しますか?

ただ、Cの場合、「移動」という手段を持っていないので
移動したい場合、
移動先へ「コピー」して移動元を「削除」することになります。

今回の場合、先頭部分を削除するだけなので、sの開始位置をずらすだけで
削除の代替となります。

もしも、中間を削除したいと思ったら、削除する部分よりも
先の部分をすべてコピーして削除部分に上書きするイメージになります。
その場合は、同一のメモリアドレスとなるので、memmove(3)を利用してください。
中間部分の削除もやってみればおもしろいと思いますよ。

http://www.linux.or.jp/JM/html/LDP_man-pages/man …
http://www.linux.or.jp/JM/html/LDP_man-pages/man …
    • good
    • 0

#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;
}
    • good
    • 0

「s が空になる」の意味はわからんけど....


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

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!