ページ 1 / 1
エラーが出て困っています。
Posted: 2011年11月20日(日) 15:13
by ルート
初、投稿のルートです。以後よろしくお願いします。
只今、ノベル風の文字表示のプログラムを作っているのですが(当サイトのサンプルプログラム参考)、エラーが出て困っています。どなたかわかるかたお願いします。
メインプログラム↓
ーーーーーーーーーーー
#include "DxLib.h"
#include "style1.h"
int i=0,j,ch_i=0,counter=0,White;
char Key[256],oldKey[256]={},disp[80]="",ch[5][80];
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1;
SetDrawScreen( DX_SCREEN_BACK ) ;
White=GetColor(255,255,255);
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
style1_up();
for(j=0;j<256;j++){
if(oldKey[j]==0 && Key[j]==1)
Key[j]=2;
oldKey[j]=Key[j];
}
if(Key[KEY_INPUT_RETURN]==2){ // 前回押されてなくて、今回押されていたら
i=0; // iを初期値に戻し
ch_i++; // 表示する配列を1つずらす
if(ch_i==5) // これ以上表示する配列がなくなったらbreak;
break;
}
// 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
if(i<=80-2 && ch[ch_i]!='\0' && counter%5==0){
i+=2; // 全角文字なので配列要素2つずつカウントアップ
strncpy_s(disp,ch[ch_i],i);// iバイトまでの配列要素をdisp配列にコピー
disp='\0'; // 終端記号を代入
}
DrawFormatString(10,420,White,"%s",disp);//disp配列の文字データを表示
counter++;
ScreenFlip() ;
}
DxLib_End() ;
return 0 ;
}
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
//style1.h↓
#ifndef DEF_style1_h //二重include防止
#define DEF_style1_h
void style1_up();
#endif
ーーーーーーーーーーーーーーーーーーーー
//style1.cpp
#include "DxLib.h"
char ch[5][80];
void style1_up()
{
ch[5][80]=(
"プログラムを習得するには、実際に自分で書いてみることが大事。",
"参考書を読むことも重要だが、数学のように演習を通して、",
"体に身につけるようにしよう。",
"きっと、よりはっきりと、関数の使い方、",
"プログラムの書き方がわかるだろう。"
);
}
style1.cppの部分で文を書いて、メインのほうに表示したいのですが・・・・
以下のようなエラーが出ます。
・c:\users\ユーザ名\documents\visual studio 2010\projects\samplex\style1.cpp(12): error C2440: '=' : 'const char *' から 'char' に変換できません。
1> この変換が可能なコンテキストはありません。
開発環境はVisual Studio Professionalを使用しています。
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 15:30
by beatle
ソースコードはcodeタグで囲みましょう。
2次元配列chはstyle1.cppの2行目で定義されていますので、初期化はそこでやらねばなりません。
どうしてもstyle1_up関数内部で文字列を代入したいなら、strcpy関数を使ったり、1文字ずつ代入したりしなければなりません。
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 22:14
by ルート
別に関数ないじゃなくてもいいんですが、
ようは、文章表示の処理をメイン関数以外で、できないかなということなのですが、
ないでしょうか?
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 22:21
by beatle
とりあえず整形したソースを貼ります。本来ならルートさんがやるべき作業です。
main.cpp
コード:
#include "DxLib.h"
#include "style1.h"
int i=0,j,ch_i=0,counter=0,White;
char Key[256],oldKey[256]={},disp[80]="",ch[5][80];
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1;
SetDrawScreen( DX_SCREEN_BACK ) ;
White=GetColor(255,255,255);
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
style1_up();
for(j=0;j<256;j++){
if(oldKey[j]==0 && Key[j]==1)
Key[j]=2;
oldKey[j]=Key[j];
}
if(Key[KEY_INPUT_RETURN]==2){ // 前回押されてなくて、今回押されていたら
i=0; // iを初期値に戻し
ch_i++; // 表示する配列を1つずらす
if(ch_i==5) // これ以上表示する配列がなくなったらbreak;
break;
}
// 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
if(i<=80-2 && ch[ch_i][i]!='\0' && counter%5==0){
i+=2; // 全角文字なので配列要素2つずつカウントアップ
strncpy_s(disp,ch[ch_i],i);// iバイトまでの配列要素をdisp配列にコピー
disp[i]='\0'; // 終端記号を代入
}
DrawFormatString(10,420,White,"%s",disp);//disp配列の文字データを表示
counter++;
ScreenFlip() ;
}
DxLib_End() ;
return 0 ;
}
//style1.h
コード:
#ifndef DEF_style1_h //二重include防止
#define DEF_style1_h
void style1_up();
#endif
//style1.cpp
コード:
#include "DxLib.h"
char ch[5][80];
void style1_up()
{
ch[5][80]=(
"プログラムを習得するには、実際に自分で書いてみることが大事。",
"参考書を読むことも重要だが、数学のように演習を通して、",
"体に身につけるようにしよう。",
"きっと、よりはっきりと、関数の使い方、",
"プログラムの書き方がわかるだろう。"
);
}
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 22:26
by box
ルート さんが書きました:
main.c
コード:
char Key[256],oldKey[256]={},disp[80]="",ch[5][80];
ここのch[5][80]と
ルート さんが書きました:
//style1.cpp
ここのch[5][80]とは、どういう使い分けをしたいのですか?
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 22:39
by beatle
ch変数に関することでいくつか問題点がありますので指摘します。
まず、ch変数はグローバル変数になっているのに、2つの.cppファイルに定義されていることです。
グローバル変数を複数の場所で定義するのはダメです。
次に、配列の扱いに関する根本的な理解不足です。
例えば
と定義された変数aが有った場合、この配列の5番目の要素に書きこむには
コード:
a[5] = 'x'; // 1文字をchar型変数に代入
とします。決して
コード:
a[5] = "0123456789abcde"; // 16文字をchar型変数に代入(無理!)
とは書けません。
これは2次元配列でもまったく同じで、添え字が1つ増えるだけです。
ルートさんは
コード:
ch[5][80]=(
"プログラムを習得するには、実際に自分で書いてみることが大事。",
"参考書を読むことも重要だが、数学のように演習を通して、",
"体に身につけるようにしよう。",
"きっと、よりはっきりと、関数の使い方、",
"プログラムの書き方がわかるだろう。"
);
と書いていますが、これはC++の文法的に誤りです。配列にまとめて値を入れるときは、配列を定義した時点で「初期値」として指定するしかありません。
コード:
char ch[5][80] = { // これは、変数chの「定義」。括弧の形にも注目。
"プログラムを習得するには、実際に自分で書いてみることが大事。",
"参考書を読むことも重要だが、数学のように演習を通して、",
"体に身につけるようにしよう。",
"きっと、よりはっきりと、関数の使い方、",
"プログラムの書き方がわかるだろう。"
}; // 凄くいい言葉ですね。
この場合は、文字列5つを「初期値」として与えているため、C++の文法的に正しいです。
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:05
by ルート
style1_upによる文章の格納はできたのですが、
style1_up関数をそのまま、メインのとこに記述しただけでは、文は表示されないのでしょうか?
やはり、strcpy関数とかで、コピーして表示させるのでしょうか・・・・
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:11
by beatle
ルート さんが書きました:style1_upによる文章の格納はできたのですが、
style1_up関数をそのまま、メインのとこに記述しただけでは、文は表示されないのでしょうか?
やはり、strcpy関数とかで、コピーして表示させるのでしょうか・・・・
恐らく、No.5のboxさんの質問に答えれば、分かってくるでしょう。
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:12
by ルート
なんとか、できました。
みなさん、ありがとうございました。!
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:16
by beatle
その、完成したソースコードを貼って下さい。後の人の参考になるように。お願いします。
これはフォーラムルールでもありますから、義務です。
また、解決した時は、「解決しました」とだけ言って去らず、ソースコードや解決した方法を明記して下さい。
同じ事で困っている人の為に過去ログに有用な情報を残すようお願いします。
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:29
by ルート
解決したかと、思ったら操作みすでした・・・・・
もう少し頑張ってみます。
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:47
by ルート
boxさんが言ってたことは、こういうのとは、また別のことですよね・・・
ーーーーーーメインプログラムだけ載せました↓ーーーーーーーー
#include "DxLib.h"
#include "style1.h"
int i=0,j,ch_i=0,counter=0,White;
char Key[256],oldKey[256]={},disp[80]="", style1_up();
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1;
SetDrawScreen( DX_SCREEN_BACK ) ;
White=GetColor(255,255,255);
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
for(j=0;j<256;j++){
if(oldKey[j]==0 && Key[j]==1)
Key[j]=2;
oldKey[j]=Key[j];
}
if(Key[KEY_INPUT_RETURN]==2){ // 前回押されてなくて、今回押されていたら
i=0; // iを初期値に戻し
ch_i++; // 表示する配列を1つずらす
if(ch_i==5) // これ以上表示する配列がなくなったらbreak;
break;
}
// 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
if(i<=80-2 && ch[ch_i]!='\0' && counter%5==0){
i+=2; // 全角文字なので配列要素2つずつカウントアップ
strncpy_s(disp,ch[ch_i],i);// iバイトまでの配列要素をdisp配列にコピー
disp='\0'; // 終端記号を代入
}
DrawFormatString(10,420,White,"%s",disp);//disp配列の文字データを表示
counter++;
ScreenFlip() ;
}
DxLib_End() ;
return 0 ;
}
ーーーーーーーーーーーーーーーーーーーーーー
Re: エラーが出て困っています。
Posted: 2011年11月20日(日) 23:52
by beatle
boxさんの質問は、2つのch変数について、「どういう使い分けをしたいのか」ですから、日本語で答えたらいいと思います。
Re: エラーが出て困っています。
Posted: 2011年11月21日(月) 00:04
by ルート
boxさんが言いたいのは、グローバル関数を二回も定義しなくてもいい。
みたいなことでしょうか・・・・(確証がなく・・・)
Re: エラーが出て困っています。
Posted: 2011年11月21日(月) 02:51
by bitter_fox
最初に、ソースコードを載せる場合はcodeタグを使ってください。
http://dixq.net/board/board.html#k10
このことは既にbeatleさんからも指摘されていますが、codeタグの使い方が分からないのでしょうか?
もしそうであれば使い方を説明しますのでおっしゃってください。
ルート さんが書きました:boxさんが言いたいのは、グローバル関数を二回も定義しなくてもいい。
みたいなことでしょうか・・・・(確証がなく・・・)
最初のプログラムの問題を簡潔に説明すると、
A地区(ファイルA)にch君がいて、B地区(ファイルB)に同姓同名のch君がいると考えてください。
B地区に居るstyle1_upさんがch君に荷物S(文字列)を預けました。このch君はB地区にいるch君です。
そのあとA地区のWinMainさんがch君から荷物S(文字列)を受け取ろうとします。この時のch君はA地区のch君です。
・・・荷物SはB地区のch君が持っていて、A地区のch君は持っていないのでWinMainさんが行った行動は失敗します。
boxさんの言いたいことはおそらく、A地区のch君とB地区のch君は本当は同じ人であってほしいのではないですか?という事だと思います。
ちなみにこの状況だとリンクに失敗します。
もしstyle1.cppが次のようになっていたら事態はより複雑です。
コード:
#include "DxLib.h"
char ch[5][80];
void style1_up()
{
char ch[5][80] = {
"プログラムを習得するには、実際に自分で書いてみることが大事。",
"参考書を読むことも重要だが、数学のように演習を通して、",
"体に身につけるようにしよう。",
"きっと、よりはっきりと、関数の使い方、",
"プログラムの書き方がわかるだろう。"
};
}
この場合だと、B地区にいるch君に加え、style1_upさんお抱えの秘書のch君が居るというような感じです。
そしてstyle1_upさんが預けた荷物S(文字列)を持っているのはお抱えの秘書のch君です。
この問題の解決にはexternを使ってchを一つにまとめてください。
http://7ujm.net/C++/extern.html
http://www.geocities.jp/ky_webid/c/032.html
あと、グローバル変数を乱用するのは好ましくないので、グローバル変数を乱用しない書き方をしたほうが良いようにも思います。
[hr][追記]
擬似コードを用いると
コード:
file Main
{
include header DxLib
include header style1
char ch[5][80]
function WinMain
}
file style1
{
char ch[5][80]
function style1_up
}
の様になります。
WinMainからはfile style1のchは見えません、また同様にstyle1_upからはfile Mainのchは見えません。
Re: エラーが出て困っています。
Posted: 2011年11月21日(月) 23:19
by ルート
コード:
//style.h
#ifndef DEF_style1_h //二重include防止
#define DEF_style1_h
void style1_up();
#endif
コード:
//style1.cpp
#include "DxLib.h"
void style1_up()
{
char ch[5][80]={
"プログラムを習得するには、実際に自分で書いてみることが大事。",
"参考書を読むことも重要だが、数学のように演習を通して、",
"体に身につけるようにしよう。",
"きっと、よりはっきりと、関数の使い方、",
"プログラムの書き方がわかるだろう。"
};
}
コード:
//samplex
#include "DxLib.h"
#include "style1.h"
int i=0,j,ch_i=0,counter=0,White;
char Key[256],oldKey[256]={},disp[80]="",ch[5][80];
int WINAPI WinMain( HINSTANCE , HINSTANCE , LPSTR , int )
{
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1;
SetDrawScreen( DX_SCREEN_BACK ) ;
White=GetColor(255,255,255);
style1_up();
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
for(j=0;j<256;j++){
if(oldKey[j]==0 && Key[j]==1)
Key[j]=2;
oldKey[j]=Key[j];
}
if(Key[KEY_INPUT_RETURN]==2){ // 前回押されてなくて、今回押されていたら
i=0; // iを初期値に戻し
ch_i++; // 表示する配列を1つずらす
if(ch_i==5) // これ以上表示する配列がなくなったらbreak;
break;
}
// 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
if(i<=80-2 && ch[ch_i][i]!='\0' && counter%5==0){
i+=2; // 全角文字なので配列要素2つずつカウントアップ
strncpy_s(disp,ch[ch_i],i);// iバイトまでの配列要素をdisp配列にコピー
disp[i]='\0'; // 終端記号を代入
}
DrawFormatString(10,420,White,"%s",disp);//disp配列の文字データを表示
counter++;
ScreenFlip() ;
}
DxLib_End() ;
return 0 ;
}
上の三つのようにしたら、windowまでは正常に処理されるようになったのですが、
肝心の文章が表示されません。
Re: エラーが出て困っています。
Posted: 2011年11月22日(火) 07:12
by beatle
A地区のch君、B地区のch君、style1_upさんお抱えの秘書chさん
の3人のうち、いなくなったのはB地区のch君だけです。
残る2人のうち、荷物S(文字列)を持っているのは
- A地区のch君
- style1_upさんお抱えの秘書chさん
のどちらか、分かりますか?
Re: エラーが出て困っています。
Posted: 2011年11月22日(火) 08:45
by softya(ソフト屋)
Re: エラーが出て困っています。
Posted: 2011年11月22日(火) 08:55
by naohiro19
関数の外で宣言された変数は「グローバル変数」といって関数の中に入っても使えます。
しかし、関数の中で宣言された変数は「ローカル変数」といってその関数の中でしか使えないという制限があります。
Re: サウンドノベル風の文表示プログラム
Posted: 2011年11月22日(火) 22:50
by ルート
サウンドノベル風の文表示プログラムを作っているのですが、
文章だけ、違うソースに書いて、それを読み込んで、表示したいと考えているのですが、
なかなかうまくいきません。
何か方法は、ないでしょうか・・・
Re: エラーが出て困っています。
Posted: 2011年11月22日(火) 23:21
by beatle
ファイル分割した場合の基本的なやり方がよく分かっていらっしゃらないようですので、単純な例を示します。
main.cppにあるmain関数から、message.cppにあるmsg変数を利用する、という場面を考えます。
コード:
// message.hpp
#ifndef MESSAGE_HPP_
#define MESSAGE_HPP_
extern char msg[];
void SetMessage(int message_id);
#endif // MESSAGE_HPP_
ルートさんはC++でソースコードを書いているみたいですので、僕もC++で書きました。C++のヘッダファイルは.hppにすることがあります。
ここでのポイントは、グローバル変数msgをextern付きで宣言していることです。externを付けることによって、
「変数msgは、どこか他の場所で実体が定義されていますよー」ということになります。
externで宣言した場所には実体が生成されず、「実体はどこかにある」、という情報だけを表します。
コード:
// message.cpp
#include "message.hpp"
#include <cstring>
char msg[128];
void SetMessage(int message_id)
{
switch (message_id)
{
case 0: strcpy(msg, "msg0: hello"); break;
case 1: strcpy(msg, "msg1: world"); break;
}
}
変数msgの実体を定義しているのがmessage.cppです。extern無しでグローバル変数を宣言(これを定義といいます)すると、
実際にその場所に変数の実体が生成されます。
message.cppでは、#includeでmessage.hppを読み込んでいるため、実際には
コード:
extern char msg[];
char msg[128];
と書いたことと同じになります。
extern付きの宣言とextern無しの宣言が同じファイルに入っていた場合はextern無しの宣言が優先され
実体が生成されることになっていますので、心配要りません。
コード:
// main.cpp
#include "message.hpp"
#include <cstdio>
int main()
{
SetMessage(0);
puts(msg);
SetMessage(1);
puts(msg);
}
main.cppからmessage.cppにあるSetMessage関数とmsg変数を使っています。
message.hppを#includeすることによって、main.cppファイルに
という宣言が取り込まれ、msg変数の実体がどこかにあるんだな、ということが分かるため、msg変数を利用することができるのです。
以上をまとめると
- あるグローバル変数の実体を置くファイルは、どれか1つの.cppファイルにする。今回の例ではmain.cpp
- そのグローバル変数を、ヘッダファイルでextern宣言する。
- そのグローバル変数を使うすべての.cppファイルで、extern宣言が入ったヘッダファイルを#includeする。
となります。
Re: サウンドノベル風の文表示プログラム
Posted: 2011年11月23日(水) 00:48
by ISLe
ルート さんが書きました: サウンドノベル風の文表示プログラムを作っているのですが、
文章だけ、違うソースに書いて、それを読み込んで、表示したいと考えているのですが、
なかなかうまくいきません。
何か方法は、ないでしょうか・・・
この掲示板の下の方にある検索ボックスに「サウンドノベル風」と入力して検索すると幸せになれるかもしれません。
Re: エラーが出て困っています。
Posted: 2011年11月23日(水) 11:31
by ルート
ルートさんはC++でソースコードを書いているみたいですので、僕もC++で書きました。
自分はCの方はまだわかりますが、C++の方は勉強してないので全然です・・・・