• ベストアンサー

sprintf

文字列に1文字を結合したいんだけど、 例えば  char str[] = "xy";  char c = 'z'; があって、2つを結合する場合、 #include <iostream.h> main(){  char str[] = "xy";  char c = 'z';  char buf[2];  buf[0] = c;  buf[1] = 0;  strcat(str, buf);  cout << str; } でもいいけど、もっと簡単にする方法があったら教えてください。  char str[] = "xy";  char c = 'z';  sprintf(str, "%s%c\0", str, c);  cout << str; イメージ的にこうだけど、失敗しました。

  • A__
  • お礼率59% (194/328)

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

  • ベストアンサー
回答No.3

単純に main() { char str[10] = "xy"; char c = 'z'; strncat(str, &c, 1); cout << str; } でいいですけど・・・ 他の方が言われているように、 strは結合後の文字列を表現できる、十分なサイズを確保しておいてください。

A__
質問者

お礼

ありがとうございます。

その他の回答 (3)

  • haporun
  • ベストアンサー率40% (230/562)
回答No.4

sprintfは、第1引数の書き込みバッファと、第3引数以降の読み込みバッファに、同じものが指定されている場合の動作は定義されていません。 ポインタマニアのhaporunでした。

A__
質問者

お礼

ありがとうございます。 それは重要ですね。

  • itohh
  • ベストアンサー率45% (210/459)
回答No.2

こんにちは。itohhといいます。 > char str[] = "xy"; これは、2バイトのエリアしか確保されていません。 そこへ、文字列を追加すると他のエリアを壊すことになります。 > char str[] = "xy"; > char c = 'z'; > > char buf[2]; > > buf[0] = c; > buf[1] = 0; > strcat(str, buf); これも実際はエリアを壊しています。 str[]としたからといって可変の配列になるというわけではないということです。 コンパイル時にコンパイラが判断して2バイトのエリアを確保します。 試しに、   char buf1[100];        <-この行を追加 > char str[] = "xy"; > char c = 'z'; > > char buf[4];         <-変更 > > buf[0] = c;         <-変更 > buf[1] = c;         <-変更 > buf[2] = c;         <-変更 > buf[3] = 0;         <-変更 > strcat(str, buf); > cout << str;         <-(1) として実行してみてください。 そして、(1)でブレイクポイントを設けて(1)まで実行してみてください。 ブレイクポイントで停止したとき変数の内容を確認すると「buf1」のエリアを 壊していないでしょうか?

A__
質問者

補足

ありがとうございます。 でも、予想どおりの結果だったから他のエリアの破壊は 確認できませんでした。 char buf1[100] = "abcdefghijklmnopqr"; char str[] = "xy"; char c = 'z'; char buf[4]; buf[0] = c; buf[1] = c; buf[2] = c; buf[3] = 0; strcat(str, buf); cout << str << "\n" << buf1; //// xyzzz //// abcdefghijklmnopqr

回答No.1

1byte文字1個の扱いは面倒なんで、自分なら1個でも文字列として扱っちゃいますね。 sprintf()がうまくいかないのは、第一引数と展開される引数のstrが同じ領域 なんでうまくいかないのでは?(コピー元と先が同じ) 最悪、関係ない領域(strの後ろの領域)をつぶしますよ。 バッファサイズは常に気をつける必要がありますが、チェックなしでコード書く ならこんな感じ。 -- char str2[BUFSIZ]; sprintf(str2,"%s%c", str, c); cout<<str2; -- 文字列リテラルに"hogehoge\0"なんてやる必要ないですよ。"hogehoge"で充分。 Cの文字列リテラルは最後が'\0'で終わる決まりになってるので。 つまり、"a\0"というのは、'a',0,0の3bytesの並びの領域となります。

A__
質問者

お礼

ありがとうございます。 その方法でもできました。 でも、 char str2[BUFSIZ]; を用意しないといけないから、新しく変数を 用意しなくてもできる方法を探しているんです。

関連するQ&A

  • \0 sprintf( ) strcat( )

    #include <iostream.h> main(){ char color_r[12], color_g[3], color_b[3]; sprintf(color_b, "%d", 123); sprintf(color_g, "%d", 456); sprintf(color_r, "%d", 789); strcat(color_r,","); strcat(color_r,color_g); strcat(color_r,","); strcat(color_r,color_b); cout << color_r; printf("\n%s",color_r[11]); } 結果は 789,456,123 (null) 問題ない。 でも、Winプログラムだと問題がある。 #include <windows.h> #include <iostream.h> 。。。  case WM_PAINT:   hdc = BeginPaint(hWnd, &ps);   char color_r[12], color_g[3], color_b[3];   sprintf(color_b, "%d", 123);   sprintf(color_g, "%d", 456);   sprintf(color_r, "%d", 789);   strcat(color_r,",");   strcat(color_r,color_g);   strcat(color_r,",");   strcat(color_r,color_b);   TextOut(hdc,10,10,color_r,strlen(color_r));   EndPaint(hWnd, &ps);  break; 結果は、実行時エラーです。 えらーだけど、TextOut( ) での表示が 789,456,123456 となっているのは見れる。 456 というのがくっく。 これが問題。 char color_r[12], color_g[4], color_b[4]; として \0 の領域を用意してやれば問題は起こらないけど、 [4] にしたとして、\0 がどのように作用しているのかが 分かりません。 [3] のエラーは  strcat(color_r,color_b); の次に  strcat(color_r,"\0"); を書けばいいような気がしてやってみたけど、 結果は変わらず、実行時エラー。 やっていることは GetPixel( ) の3色分離だけど、 配列の \0 をケチって宣言すると、 R,G,B が、R,G,BG となってしまうことが分かったけど どうして R,G,BG になるのかを知りたいです。

  • sprintf の使い方について

    C 言語の超初心者につき,おろかな質問をお許しください。 sprintf 関数について char str[40]; sprintf(str, "hogehoge %d", hoge_int); という文法はよく目にするのですが char *str; sprintf(str, "hogehoge %d", hoge_int); という文法はあまり見たことがありません。 両方ともちゃんと動くのですが,後者は文法的に正しいのでしょうか? char str[40] とした場合でも char *str とした場合でも, str は文字列の最初の文字のアドレスを表すんだったと思うんですが。 違いが分からず,混乱しています。 初心者につき,間抜けな質問をしているかもしれませんが,ご教授くださると幸いです。

  • C/C++関数間でのStringクラスの扱い

    以下のようなコードを実行してみましたが思い通りに動いてくれません. "sample"という文字列がstrへとコピーされると思ったのですが. stringクラスのc_str()メソッドはconst char*だと言っているので無理矢理キャストしたのが原因でしょうか.stringクラスは記憶領域を自動で変更してくれるのではないのですか.それともこの挙動は仕様ですか. -------- 以下コード -------- #include <iostream> #include <string> using namespace std; int func(char *); int main(void) {     string str("");     func((char *)str.c_str());     cout << "String: " << str << endl;     return EXIT_SUCCESS; } int func(char *buf) {     buf = "sample";     return 0; } -------- 以上コード --------

  • プロンプト入力 malloc( )

    #include <iostream.h> void f(char* str); main(){ char s[8] = "\0"; cout << "文字を入力" << '\n'; fgets(s, 8, stdin); f(s); } void f(char* str){ char* c; c = (char*)malloc(sizeof(char) * strlen(str)+1); cout << strlen(str) << '\n'; cout << sizeof(c); free(c); } - 結果 - 文字を入力 ( a、Ctrl+Z ) a 1 4 でした。 cout << sizeof(c); の結果は4でした。1バイトの入力だから\0を含めて 2バイトを確保したかった。 そのためにはどうしたらいいんですか? どうして4だったんですか? 文字を入力するとこで、Ctrl+Z の代わりに Enter を押すと Enter まで s に格納されてしまう。 cin を使うと8バイト以上の入力でも s に格納されてしまう。 そうならないためのよい方法があったら教えてください。

  • sprintf()の使用方法

    先日から仕事で別の人が作ったソースを見ることになりました。 文字列連結を繰り返す処理でこんなコードが書いてありました。 char str[4096]; for(;;) {      /* 具体的な条件などは忘れました */ sprintf(str, "%s%s", str, var1);   /* 一応、var1はstrに対して十分小さな文字列。*/                      /* 繰り返しが終了するまで溢れることはないのですが */ } strcatなどを知らない人が作ったのでしょう。 一応、目的は達しているし、動いているみたいだからいいと言えばいいのかもしれないですが、なんか気持ち悪い。 こういうコードで何か問題はないのでしょうか?

  • 配列の練習問題

    #include<iostream> using namespace std; //count関数の宣言 int count(char str[], char ch); int main() { char str[100]; char ch; cout << "文字列を入力して下さい。\n"; cin >> str; cout << "文字列から探す文字を入力して下さい。\n"; cin >> ch; int c = count(str, ch); cout << str << "の中に" << ch << "は" << c << "個あります。\n"; return 0; } //count関数の定義 int count(char str[], char ch) { int i = 0; int c = 0; while (str[i]) { if (str[i] == ch) c++; i++; } return c; } こんにちは。 この問題の解答のプログラムの意味がイマイチ解らないので良かったら教えて下さい。 確認がてらに質問します。 よろしくお願いします。

  • strcat で型が合わない

    #include <iostream.h> main(){ char x[15]; for(int i=0;i<15;i++) x[i]=i+49; for(int i=0;i<15;i++){ cout <<x[i]; }; } 9より先の文字化けは考えないとして、 char x[15]; というのは適切ですか? 16個目の要素になる x[15] には、文字列の最後の \0 が入ると思って char x[14]; にしなかったんです。 コンパイルして実行すると 123456789... となるけど、 2桁にしたいんです。半角スペースを使いたいんです。 1 2 3 4 5... のようにしたいんです。 そのように表示する方法は色々あるけど、 文字列の配列でやる場合の方法が知りたいんです。 #include <iostream.h> main(){ char x[15]; char y=" " for(int i=0;i<15;i++){ x[i]=strcat( y,(char)(i+49) ); }; for(int i=0;i<15;i++){ cout <<x[i]; }; } ↑のようなことやってみたけど、型が合わないとかで うまくできませんでした。 strcat とか strncpy は難しいです。 正しいソースを教えてください。

  • プログラムの動作

    10文字をスキップするプログラムなのですが、どのようにスキップしているのかわからないので教えてください。 下にソースコードを書きます。 #include <iostream> using namespace std; //10文字をスキップする istream &skipchar(istream &stream) { int i; char c; for(i=0; i<10; i++)stream >> c; return stream; } int main() { char str[80]; cout << "いくつかの文字を入力する:"; cin >> skipchar >> str; cout << str << endl; return 0; } よろしくおねがいします。

  • sprintfを用いたフォーマット文字列攻撃

    sprintfを用いたフォーマット文字列攻撃に関する質問です。 main文の中で --------------------- int main(void){ char str[50]; sprintf(str,"%s"); puts(str); } --------------------- を実行すると(null)で帰ってきます。 しかし関数呼び出しを行うと結果が変わってきます。 --------------------- void f(){ char str[50]; sprintf(str,"%s"); puts(str); } int main(void){ f(); } --------------------- これを実行すると" ・L "のような文字化けしたものに変わりました。 sprintf(str,"%s%s");と記述することによって" ・L (null) "と、本来呼び出される箇所のものが格納されています。 なぜ関数呼び出しにすると変なところを参照してしまうのか(第3引数があると勘違いしてしまうのか)教えてください。 また、これによりどのような悪影響があるのか教えてください。 自分はプログラマが意図しない箇所を参照するため攻撃者のプログラムアドレスを格納してしまう恐れがあると考えています。

  • strcatの処理方法

    #include <iostream.h> #include <string.h> int main(){char a[]="a";char b[]="b"; char c[]="c"; for(int d=0;d<3;d++){strcat(a,b); strcat(a,c);cout<<a;}} このc言語プログラムの実行結果を、abcbcbc したいのですが、例外処理されます。解決方法お願いします。後、又簡単な連結方法教えてください。

専門家に質問してみよう