#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 になるのかを知りたいです。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

printf("color_r=%x color_g=%x color_b=%x\n",color_r,color_g,color_b);


として実行してみて下さい。それぞれの配列のアドレス(先頭アドレス)が
示されます。そこから指定したバイト分がその変数の領域です。
ちなみに、この配置は処理系に依存します。
    • good
    • 0
この回答へのお礼

ありがとうございます。
printf("%x") で調べて、疑問は解決しました。

お礼日時:2001/12/28 00:55

#1の方の回答にあるように偶然です。


Cの処理系によっては、奇数バイト配列のメモリ上のバウンダリをWORDで扱えるように調整するものもあるので、たまたまそうなったとしかいいようがありません。

またstrcatは文字列連結を行う関数ですが、Cでいう文字列とは「終端文字がnullである」です。
strcatは連結する文字列のnullまでを検索してそれをtarget変数に連結します。
つまり、[3]で宣言した変数にはnullが存在しないため、最悪暴走します。

このことからも、Cで文字列を取扱う場合は必ずnullが入るように1バイト追加して変数宣言するのが常識です。
    • good
    • 0

R,G,BG になるのは、たまたまそうなったと考えてください。



strcatは、文字列を扱う関数なので、
char color_r[12], color_g[3], color_b[3];
で宣言した場合、\0を入れていないため、宣言していない領域外までくっつけてしまうことになります。
この場合、color_g[3]の次が偶然\0だったと思ってください。
color_b[3]の次に、color_g[3]の領域が取られていたと思ってください。

ですので、コンパイルし直すと、違う結果が出てくるかもしれないです。

この回答への補足

必ず R,G,BG になるわけではないけど、
取得する色によって結果が違うんだけど、
R,G,BG になることが多いんです。

Winプログラムの方で、領域外までくっつけてしまうことになるのは
どの行ですか?
それはコンソールの方では起こらないんですか?
コンソールの方で
printf("\n%s",color_r[11]); が \0 になったのは
偶然ですか?

補足日時:2001/12/27 02:07
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

このQ&Aと関連する良く見られている質問

Qfp = fopen(argy[1], "r");の[1]の意味は

https://oshiete.goo.ne.jp/qa/8940272.html
 の11行目に
fp = fopen(argv[1], "r");の[1]の意味が分かりません。
試したいのですが、ソフトがうまく動きません
 よろしくお願いいたします。

Aベストアンサー

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから入力し実行すると、

argc = 5
argv[0] = "test"
argv[1] = "test1"
argv[2] = "test2"
argv[3] = "3"
argv[4] = "4"

と文字列が入ってきます。

以下はサンプル。

void main( int argc , char *argv[])
{
if( argc < 2 )
{
// パラメータ指定がなかった場合の表示
printf( "test に続けて4つまでパラメータを入力できます\n");
exit(0);
}
if( argc > 5 )
{
 // パラメータが5つ以上あった場合の表示
printf( "5つ以上のパラメータは受け付けません\n");
exit(-1);
}

// 正常ルート
printf( "パラメータの数は%d個ですね?ニヤッ\n", argc-1);
printf( "最初のパラメータは%sでしょ?\n", argv[1]);
printf( "残りはargv[2]以降ですが、面倒なので表示しません\n");
}

と言う具合に、引数を活用できます。argv[0]には、実行ファイル名が入ります。
argc は実行ファイルの名前も含めてカウントされます。

プログラムによっては必要な引数の数が変わりますし、
ユーザーのコマンドラインからの入力ミスなどでパラメータがなかったり、
必要なパラメータが不足していたりしますので、
argcとargvを使って最初にシンタックスエラーチェックをするのが常道です。

実行ファイル名の指定がなく、プログラムが実行されることはないと思われます
から、argcは1以上の値になります。

argc, argvの活用は、
実行コマンドを手打ちで打ち込むコンソール形式でよく用いられる基本的な
アプリケーションの開発手法です。

ご質問の箇所は、
第一パラメータにプログラム内で読み込むファイルのファイル名を指定してるの
でしょう。(よくあります)

しかし、Windowsなどのウィンドウを使用するアプリケーションは、
これとは違っておりますので注意が必要です。
(C言語とは別に、Windowsに特化した開発ノウハウの勉強が必要です)

Windows系で上記の様な基本的なプログラムを作成する場合は、
プロジェクトの作成時に(VisualStudioなどで)コンソールアプリケーション
を選んで作成します。実行時にコンソールが開きます。

Linuxの場合は、コンソールがデフォルトになっているでしょうから、
(特殊な設定がなければ)そのまま作成できます。

テキストエディタでソースを記述し、gcc などでコンパイルします。
実行形式ファイルが出来ていれば、想定どおりの動作をするでしょう。

ファイルの読み込みが出来るようになったら、
ファイルの内容を書き換えて保存したり、
ファイル名を変えたり、
ディレクトリ内のファイルを全て表示したり、
ファイル内に含まれる文字列を検索し、該当するファイルをリストしたりなど、

有用なサンプルプログラムを沢山作って練習します。

ファイルを読み込む先は、char型の配列でバイトサイズのメモリーとして確保
します。メモリーと変数の関係を充分に理解することをお勧めします。
殆どのプログラムは、このメモリーの確保やメモリーサイズの計算と格闘する
場合が多くなるからです。

バイナリー形式のファイル(すべてはバイナリー形式として良いのですが)に
ついて理解が深まった後は、
bmpの画像ファイル、wavなどの音声ファイルをあけて、
これの中身を書き換えて遊びます。

特にwavファイルは、音量の変更や周波数フィルタなども掛けれますので、
メモリ、配列、ファイルの関係を(焦らずに)ゆっくり理解するだけで、
今の知識レベルでも面白いことが沢山出来ます。

以上、ご参考に成れば。

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから...続きを読む

Qstruct tanka_kosuu kosuu[10];の[10]て何

#include <stdio.h>
struct tanka_kosuu {
int tanka;
int kosuu;
int kingaku;
};
int main()
{
         struct tanka_kosuu kosuu[10];
       構造体宣言 構造体名  変数名
struct tanka_kosuu kari_nyuuryoku = {-1, 0, 0};
int nyuuryoku_kosuu = 0;
while(kari_nyuuryoku.tanka != 0){
scanf("%d %d", &kari_nyuuryoku.tanka,
&kari_nyuuryoku.kosuu);
kosuu[nyuuryoku_kosuu] = kari_nyuuryoku;
nyuuryoku_kosuu++;
}
return 0;
}
以上ですが、
 struct tanka_kosuu {
int tanka;
int kosuu;
int kingaku;
以上と
struct tanka_kosuu kosuu[10];は
 以下
int tanka;
int kosuu[10];
int kingaku;
 と同じ意味ですか?
 それとも
  int tanka[10];
int kosuu[10];
int kingaku[10]; 
 と同じ意味ですか?
int tanka[10];と
 int kingaku[10];の
 合計に[10]は必要ないですよね
以上すべて私の考え方が間違っていたならごめんなさい。
 以上よろしくお願いいたします。

#include <stdio.h>
struct tanka_kosuu {
int tanka;
int kosuu;
int kingaku;
};
int main()
{
         struct tanka_kosuu kosuu[10];
       構造体宣言 構造体名  変数名
struct tanka_kosuu kari_nyuuryoku = {-1, 0, 0};
int nyuuryoku_kosuu = 0;
while(kari_nyuuryoku.tanka != 0){
scanf("%d %d", &kari_nyuuryoku.tanka,
&kari_nyuuryoku.kosuu);
kosuu[nyuuryoku_kosuu] = kari_nyuuryoku;
nyuuryoku_kosuu++;
}
return 0;
}
以上です...続きを読む

Aベストアンサー

#1です。

>struct tanka_ data { ・・・・(1)
>  int tanka;
>  int kosuu;
>  int kingaku;
>};
・・・途中省略
>} これでいいでしょうか

(1)のところは、変えてはいけません。
struct tanka_kosuu { 
のままにして下さい。
他は、問題ありません。

Qfp = fopen(argv[1], "r");を”w" "a" "r+"・・・で試したらどうなる

http://oshiete.goo.ne.jp/qa/8897349.html
 以上のプログラムで
 以下をfp = fopen(argv[1], "r");の
 ”r"以外で以下を入れた場合の結果がどうなるかお聞きしたいです。
"r" 読み込みモード。ファイルが存在しているとする。
"w" 書き出しモード。すでにファイルがあれば内容を削除し、なければ新たに作成する。
"a" 追加モード。すでにファイルがあればその最後に追加し、なければ新たに作成する。
"r+" 更新モード。ファイルが存在しているとする。
"w+" 更新モード。すでにファイルがあれば内容を削除し、なければ新たに作成する。
"a+" 追加更新モード。すでにファイルがあればその最後に追加し、なければ新たに作成する。
 以上ですが、試す環境がございませんので、よろしくお願いいたします。

Aベストアンサー

お書きのとおりで合ってますよ。大丈夫です。

Qint kosuu; とstruct tanka_kosuu kosuu[10]; の関係は

同プログラムの内容で現在3個の質問をしておりますが!
 その質問を解決する上で4つ目の質問をさせていただきます。
 悪しからず・・・
 さて
以下のサイトのプログラムで 些細な疑問がございます。
https://oshiete.goo.ne.jp/qa/9062058.html
 で
 struct tanka_kosuu {
int tanka; 
int kosuu; 
int kingaku; /
以上の中にあるkosuuと
 struct tanka_kosuu kosuu[10];のkosuu[10]とは直接関係がありますか?
 馬鹿な質問ばかりで申し訳ございませんがよろしくお願いいたします。

Aベストアンサー

#No.1です。

>kosuu[10];をakb[10];変えたところ 以下の errorでてコンパイルできません!?
> example10.c(15) : error C2065: 'kosuu' : 定義されていない識別子です。


宣言している変数名を変更したら、その変数を利用している場所(エラーメッセージで15行目と書かれています)の変数名も変更する必要があると思いませんか?

下の例で、1行目も変数をaからbに変えたら、2行目,3行目のaも、bに変える必要があのはご理解いただけますよね?
01: int a;
02: a = 10;
03: printf("a=%d\n", a);

Qmemcpy,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;
}

memcpy,memcmp,strcmp,strlen,strcat,strcpy,strstr,strchr
以上の関数を自作しました。
ひとつひとつを見たときに動作を確認したところうまく出来たのですが、この関数をプログラムに組み込んだところうまく動作しませんでした。
どこか間違っているところがあったら指摘して頂きたいと思います<m(__)m>
ちなみに標準関数と全く同じものにしたいわけではなく、それを自分なりに考えて作りたいという趣旨ですので、ご理解ください。


char *MyMemcpy(char *str1, char *str2, size_t n)
{

char *p1 = str1;
char...続きを読む

Aベストアンサー

> この関数をプログラムに組み込んだところうまく動作しませんでした。

どんな風に「うまく動作し」なかったのでしょうか?
それがわからなければ、明らかな間違いでも無いかぎり、答えようがありません。

特に
> ちなみに標準関数と全く同じものにしたいわけではなく、それを自分なりに考えて作りたいという趣旨ですので、ご理解ください。
とあるので、このプログラムと標準関数との違いが、間違いなのか仕様通りなのか判断できません。

例えば、
> char *MyStrcmp(char *str1, char *str2)
プログラムを解読すると

str1とstr2、それぞれの文字列の長さを比較。
→長さ等しい場合は (char *)NULL, 異なる場合は、長い方の文字列へのポインタを返す

と、strcmpとはまったく別の関数になっています。(strcmpは文字列の内容も比較し、結果を 負の整数,0,正の整数 (いずれもint型)で返します)


あと、明確な間違いというわけではないですが。
> while(*p1 != NULL){

大抵の処理系では NULL == '\0' == 0 として使えるけど、ヌルポインタとヌル文字はわけて考えた方がいいです。

> この関数をプログラムに組み込んだところうまく動作しませんでした。

どんな風に「うまく動作し」なかったのでしょうか?
それがわからなければ、明らかな間違いでも無いかぎり、答えようがありません。

特に
> ちなみに標準関数と全く同じものにしたいわけではなく、それを自分なりに考えて作りたいという趣旨ですので、ご理解ください。
とあるので、このプログラムと標準関数との違いが、間違いなのか仕様通りなのか判断できません。

例えば、
> char *MyStrcmp(char *str1, char *str2)
プログラムを解読...続きを読む


人気Q&Aランキング

おすすめ情報