過去に寄せられた質問と回答
C言語の勉強は当サイトで一番人気のC言語学習塾のページをご利用ください。

|
Study C販売のご案内
Study Cのオンライン販売を行っております。
是非ご利用ください。
|
|
過去にORCHIDのホームページによせられたコンピュータに関する質問と回答のページです。
Q-1
QTVRを制作するためにオーサーリングツールを購入したのですが、このツールを使用する
ためにMacのMPW上のツールを使わなければならないのですが、この方面は素人でMPWの操作
方法も 全然解りません、何か素人でも解る入門書をご存じであれば是非お教え下さい。
A
どなたか、解答をお願いします。
Q-2
Cは入門講座を受けた程度の初心者です。関数も入門書に出てくるものしか
知りません。でも、顧客管理用のリレーショナルデータベースを作りたいのです。
初心者には無理でしょうか?
いい勉強方法や教材があったら教えて下さい。
A
かなり難しいでしょうが無理ではないと思います。
データベースのプログラムを作には次の3通りが考えられます。
(1)fread()、fwrite()などを使ってファイル入出力を自分で行う。
(2)ISAMライブラリを使う。
(3)ORACLEなどのデータベースを使う。
(1)は簡単な住所録(データ数も少ない)などに使います。どういう方法で
ファイルに書き込んだり検索するかを考えるのが大変です。
(2)はデータベース用のライブラリ(関数群)を入手する必用があります。
1年(?)程度前のCマガジンの付録にISAMライブラリが付属していたと思います。
2、3万円で売っているものもあります(使い物にならないものも売っていると
思います)。ISAMライブラリを入手すればそれを使った簡単な住所録などの
サンプルが付属していると思います。これを改造していくのが良いでしょう。
ISAMの関数を10個ほど理解すれば基本的なことはできるようになります。
ISAMでもたいていのことはできますが、複雑な条件(年齢、性別、...)で検索
する必用があったりネットワーク経由で複数のユーザーが同時に使うような
データベースを構築したいなら(3)の方法が最適です(ISAMを使う方法でも
できないことはありません)。
(3)は大規模なデータベースの標準的な作り方です。データベース自体は購入
してデータ登録や条件検索の部分をC言語などで記述子データベースを制御
します。ORACLEのデータベースが一番使われていると思います。データベース
自体が数十万から数百万円(ユーザー数による)します。また、C言語以外にSQL
というデータベース制御用の言語を覚える必用があります。
(2)の方法がお勧めですが、最近はORACLEしか使わないのでどのISAMが良いの
か解りません。もう一つ問題なのはユーザーインターフェイスです。普通なら
Windowsなどで作のでしょうが、最初からは無理だと思います。最初はMS-DOS
で動作させるかWindowsのDOSボックスで動作するものを作るしかないと思いま
す。
Q-3
スタディCは、Windows NT上でも起動可能なのでしょうか?
A
ORCHID -> 動作確認をしてみます。しばらくお待ちください。
動作確認の結果 : 一応動作する
ようですが、簡単なテストでも何点か動作がおかしい機能がありました。
ホームページにアップロードしているStudy CはNT上では使わない方がよいと
思います。
移植について : NT用のStudy Cを教材として採用するようなところがあれば移植しますが、
NT Ver4の日本語版がでるまでは動作対象として考えていません。
Q-4
SCSIボードAdaptec 1542Bを使っているマシンにLinuxを初めてインストールしようと
していますがうまく行きません。インストールに使ったCD-ROMはUNIX USERの付録の
Slackware 3.0です。ボードの設定はI/O 0x330, IRQ 11, DMA 5です。ブート時に
SCSIボードが認識できません。エラーはDMAの(priority)チャンネルが解らないと
いったようなメッセージです。ブートパラメータにaha1540=0x330,11,4,5などと指定
しても同じエラーが出ます。よろしくお願いします。
A
fjの古い記事に同様の症状が載っていました。原因はブートイメージがPCI bios
supportをyにして作られていると発生するとのことです。他のlinuxシステム上で
PCI bios supportをnにてカーネルを再構築したブートイメージが必用です。
これが作れない場合はSlackware 3.0を、このような症状が出るシステムに
インストールできないようです。
Slackware 3.1があるサイトをのぞいてみたところブートディスクのイメージに
1542用が追加されていたので使ってみたところ、同じシステムでブートすることが
できました。このブートディスクを使いSlackware 3.0をインストールしカーネルの
再構築でPCI bios supportをnにしました。これでブートできるようになりました。
Q-5
これまでTurbo Cを使っていたのですが、最近になってWIN95の
Visual C++を使うようになりました。しかし、WIN上でのグラフィック画面を
オープンするためのヘッダファイル(たとえばgopen.hのようなもの。また、ヘッダ
ファイルが両方にある場合でもその中に含まれている関数が異なっている等)がなくて
困っています。どうすればいいんでしょうか?
A
もうBorland C++のマニュアルしか残っていませんがgopen.hがどの関数の定義に使われて
いるかわかりません。Borland C Ver2のインストールされているマシンにもgopen.hという
ファイルは入っていませんでした。具体的にどのような関数群を使いどのようなプログラム
を作りたいか簡単に教えてください。
「WIN上でグラフィック画面をオープンするための機能」といえばWindowsのAPIを
連想します。WindowsのAPIならばBorlandとMicrosoftの製品での違いはありません。
また、Borlandの製品で固有の機能としては、BGI,EasyWin,Turbo Vision,ObjectWindowsなどが
思い浮かびますが何れの機能もVisual C++では使えないと思います。ソースファイルが
存在する機能もあるので移植することのできる機能もあるかもしれませんがVisual C++を
Windows 95で使うのであれば、MFCかWindowsのAPI(Win32)を使う以外に方法はないと思い
ます。
Q-6
C言語でのグラフの書き方が分かりません。分布図を書きたいのですがどのように
すればいいのでしょうか。C言語は大学で習っただけなので基本的なことしかでき
ません。VisualC++を買ったのですが、ほかにグラフィックのソフトを買
わないといけないのでしょうか。
A
Visual C++があれば分布図は作成できます。Windows上でグラフを表示するソフトを
作るとしたら、WindowsのAPI(ウィンドウをオープンしたり線を引いたりする関数群)を
使って作と思います。C言語の知識はたいして必要ないのですが、WindowsのAPI(関数)は
無数にありかなり苦労すると思います。Windows APIはVisual C++のヘルプで見ることが
できます。ヘルプを見ても普通はプログラムを作れるようにならないのでWindows
プログラムの入門書を見て(立ち読みで良いと思います)理解できるようならこの方法
で作のがよいと思います。
Visual C++のAppWizardを使えとウィンドウプログラムの
骨格を作ってくれます(それでもWindows APIを知らなければそれ以上のことは
なにもできません)。骨格があれば知らなければならないWindows APIの数が減るのですが、
AppWizardが作成するプログラムはC++なので
C言語だけの知識でどこまで使えるかはちょっと解りません。しかし、Visual C++を
お持ちなら一度、AppWizardを使って骨格となるプログラムを作って見てみるのが
良いでしょう(ぜひ、見た感想なども投稿してください)。それから、Windowsのプロ
グラムを作成する場合は(AppWizardも同じ)イベント駆動形式のプログラムスタイル
を知っている必用があります。これは一言では説明できないので入門書などを参考
にしてください。
どちらの方法でも理解できない場合は、MS-DOSかMS-DOSプロンプトウィンドウで
動作する。プログラムで我慢するしかないと思います。MS-DOSプロンプトウィンドウ
上では基本的に文字しか表示できないので用途によっては使えないかもしれません。
しかし、文字ベースで
*
* * *
* * * *
* * * * * *
のように表示するプログラムを作るのがもっとも簡単です。画面上の自由な位置に
文字を表示するには次のようにエスケープシーケンスを使います。また、同じような
方法で文字の色を変えたりすることもできます。
printf("\033[10;10H*"); 10行目の10カラム目に*が表示されます。
注)エスケープシーケンスを使うにはconfig.sysにansi.sysが組み込まれている必用があります。
Q-7
先日、VisualC++で分布図を描くプログラムについて質問した者です。
あれからいろいろな本を読んでみたりはしたのですがVisualC++やWi
ndowsのプログラムの本は初心者には難しくグラフの書き方は分かりません
でした。ほかのものを探したところ、TurboCのグラフィックの本が比較的
分かりやすくサンプルプログラムもついていたので、これでプログラムを作って
みたのですがVisualC++では動きませんでした。
実は、大学の演習の課題でファジィ分布のプログラムを作らなくてはならないの
ですが、関数の公式がu(x)= 1 (x<=c) 1/{1+a(x-c)^b} (x>c, a,b>0)
というものなので、前回教えてもらったprintfを使う方法ではきれいにかけませ
ん。どうやったら直線や曲線を描くプログラムが出来るんでしょうか。
A
MS-DOS(DOS/V)用のソフトで良いのであれば、もう一つ方法が残っていました。
Turbo Cのグラフィックの本に書かれるのが多分その方法だと思います。
MS-DOS用の開発環境が含まれているコンパイラには、通常グラフィック表示用の
関数が用意されています。この関数群(ライブラリ)は各社仕様が異なり同じようには
使用できません。Visual C++でもMS-DOS用の16bit開発環境があれば
グラフィックライブラリが使えると思います。Visual C++は16bit開発環境を
別にインストールする必用があったと思います。これをインストールした
ディレクトリのlib\の中をしらべgraphics.libというファイルがあれば
DOS用のグラフィック関数が使えると思います。ボーランドのグラフィックライブラリ
の方が有名だったと思いますが、マイクロソフトのグラフィック関数を使った
書籍もあると思います。
今回のケースには向いていないかもしれませんがアップロードしてあるStudy Cでも
グラフを表示することはできます。タートルグラフィックという性格上直線での
表現が基本となりますが、その分折れ線グラフなどは非常に簡単に描くこととができます。
Q-8
C言語学習塾 第7回講座で、print_bar や print_dot を使ったプログラムを
実行すると”プロトタイプ宣言なしに関数が呼ばれています”
のエラーが出てしまいます。プログラムはテキストどうりなので
何がおかしいのかわからずにいます。回答よろしくお願いします。
P.S print_dot を使ったプログラムの18行目はprintf(" ")ですよね。
A
エラーではなく"WARNING(1202) プロトタイプ宣言なしに関数が呼ばれています."
と表示されているのだと思います。WARNING...はエラーではないけれども注意した
ほうがよい個所をプログラマに知らせるため、Study Cが表示するメッセージ(警告)です。
サンプルプログラムはメッセージ表示後、正常に動作すると思います。この警告は
print_barやprint_dotのプロトタイプ宣言を追加することで表示されなくなるのですが、その説明をもっと
後の講座で行おうと思っていました。しかし、警告がでていると気になるようなので
7回講座内でプロトタイプ宣言の説明を付け加えようと思います。とりあえず、
サンプルプログラムの先頭に、次の行を付け加えれば警告がでなくなります。
int print_bar(int);
main()
{
print_bar(...
または
int print_dot(int);
main()
{
print_dot(...
print_dotを使ったプログラムの18(19?)行目は、ご指摘のとおりprintf("*");ではなく
printf(" ");の誤りでした。修正いておきました。
Q-9
第7回講座から第1回実力試験へのリンクが張れてませんよ。
A
ご指摘ありがとうございました。すぐに直しておきます。
Q-10
C言語(Djgcc)でCADの制作を行いたいのですが、よい参考図書が見つかりません。
C言語は初歩的なことはわかるのですが、こんな自分でも作れるでしょうか?
できれば、初心者にでもわかるような参考図書を教えていただければよいのですが・・・
A
Djgccは使ったことがないのですが、Windows 95(NT)のソフトは作れるのでしょうか?
今からCADを作のならばWindows 95(NT)上のアプリケーションとするべきだと思います。
最終的に大規模なソフトになると思うので、32bitアプリケーションで作る必要がある
ことと、グラフィックボードのアクセラレーション機能を利用した画面表示を行って
くれることが必用です。日ごろUNIXを使っているのならばPC UNIXもこの条件にあては
まるのですが、完成したCADを広く使ってもらいたいのならばWindows 95(NT)のほうが
良いでしょう。
CADを作る上で
まず必要なことはWin32を使って簡単なソフトが作れるようになり、そのウィンドウ上で
図形などが描画できるようになることです。
この件に関しては、Q-6に対する回答が参考になると思います。
ただし、CADを作る場合はWindows 95(NT)用のWin32以外で作ることは考えない方が
よいと思います。参考書はここまできてから探せばよいと思います。
P.S. : フリーのCADがあったと思います(J???CADとかいう名前?)。
DOS上での動作するものだった気がします。
もし、ソースが付属していれば参考になるのではないでしょうか。ただし、DOS上で
の動作というのは参考にしない方がよいと思います。このCADについてなにかわかったら
教えてください。
私は使ったことはないのですが、CADに関して、kbanというフリーの小規模基板設計
プログラムがソース付きで公開されています。DOS版は、
http://www.vector.co.jp/common/dos/ap/cad/kban194.lzh(バイナリ)
http://www.vector.co.jp/common/dos/ap/cad/kban194s.lzh(ソース)
WIN95版(β版)は、
http://www.vector.co.jp/common/win95/ap/cad/kban2a08.exe
(バイナリ、及びソース)で入手可能です。何かの役に立つかもしれません。
(ここから、ORCHIDさんへのメッセージ)Cプログラミングを始めようと思い、
関連WWWページを探していたら
ORCHIDさんのホームページに行き当たりました。
Study C、MaxEditorともにダウンロードさせて頂きました。Otermだけとりあえず
使用してみましたが、かなり使えそうです。使用期限付きとはいえ、有用な
ソフトを提供して下さっていることに感謝します。
Q-11
早速Study Cをダウンロードさせて頂きましたが、PC-98では動作しないんですね。
今後PC-98に対応させる予定はあるんでしょうか?
また、PC-98でも動作する安価なC言語インタープリタなど
ありましたら教えて頂けないでしょうか?
A
Windows 95の発売でPC-9801とIBM PC互換機間でソフトが共通になったと言うような
話を聞きますが、こだわると動作の違いがきになる部分があります。たとえば、
PC-9801の普通のエディタでカーソルキーを押しながら画面をスクロールさせます。
このときShiftキーを押すとスクロールが加速します(DOS用だけでなくてWindows用も)。
しかし、IBM PC互換機ではShiftキーを押した時点でスクロールがとまってしまうのが
普通です。Study Cのエディタ部分がMAX EDITORという弊社のエディタを使っているため、
この辺のこだわりが多くIBM PC互換機用のEXEをPC-9801で動作させるとまともに動かない
ので起動時にチェックして動作しないようにしています。
PC-9801用のStudy Cも試験的に作ってありますが、デモ目的で配布しているので将来性の
うすいPC-9801用を配布する予定はありません。
PC-9801で動作するC言語インタープリタは、共立出版から販売されているスタディC
(\3,780)に、DOS用のStudy Cが付属しています。Windows 95用に比べて、機能はだいぶ
落ちますが勉強には十分使えると思います。DOS用なのでまだ在庫が残っているか解りま
せん。また、Windows 95上から使えるかも不明です。
Q-12
音声のWAVEファイルを読み込んで音声波形を出すプログラムを書きたいのですが、
グラフの書き方がわかりません。教えてください。 音声データを(X,Y)の座標に
するところまではできているのですが。
A
Q-6、Q-7と同じ質問だと思うのですがどうでしょうか? 違っていたらもう一度、
詳しく質問してください。
Q-13
C言語を勉強したいと思っているMacユーザーです。このホームページとStudy Cに
感激しました。Study CのMac版のリリースの予定はないのですか?
A
一時、MacにもORCHIDの製品(特にMAX EDITOR)を移植しようと思っていましたが、
そのうちアップル社の減益のニュースが流れるようになり中止しました。
MAX EDITORやStudy CがMacの改行コードに対応しているのはそのときの移植作業の
なごりです。現在のところ、Mac用のStudy Cが大量に注文でもされない限りMacへの
移植作業を再開する予定はありません。
Q-14
いつも勉強させていただきありがとうございます。初めて質問しますが、1からnまでの
数字をランダムに配列するプログラムを教えてください。
A
"配列する"という部分の意味があいまいですが、配列に格納すると解釈します
(違っていたら連絡してください)。
C言語で乱数を作るときはrand()関数を使います。rand()関数は次の点を注意する
必要があります。rand()関数はプログラムを起動するたびに同じ値を返してきます。
たとえば、次のプログラムを実行すると毎回同じ値が表示されます。
main()
{
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
}
これでは、ゲームなどの用途には向きません。これをさけるにはsrand()という関数に
毎回異なった値を与える必要があります。
main()
{
srand(毎回異なった値を与える);
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
}
srand()関数には現在の時刻(秒単位)などを与えるとよいでしょう。
#include <stdio.h>
#include <time.h>
main()
{
srand(time(NULL));
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
}
これらの関数を使えば質問のプログラムは次のようになります。
#include <stdio.h>
#include <time.h>
main()
{
int data[100], n, i1, rnum, value;
n = 100; /* nは100まで */
srand(time(NULL));
/* 1からnまでの数字を順番に配列に格納する */
for(i1 = 0; i1 < n; i1++){
data[i1] = i1+1;
}
/* i1番目の要素とrand()が返したrnum番目の要素を交換する */
for(i1 = 0; i1 < n; i1++){
rnum = rand() % n;
value = data[i1];
data[i1] = data[rnum];
data[rnum] = value;
}
/* 配列の内容を表示する */
for(i1 = 0; i1 < n; i1++){
printf("<%d>", data[i1]);
}
}
nの最大が決まっていない場合はmalloc()関数を使ってdataの領域を確保するように
変更する必要があります。
Q-15
構造体ポインタがよく把握できません。p->tel,p->name,等の記述がよくでてくるのですが、
意味が把握しきれません。一言でいうとどういった機能なのでしょうか?例として、
以下のプログラムを解説していただけるととてもうれしいです。
<名前をキーにして電話番号を単方向リストに登録するプログラム>
struct elem{
char name[12];
char tell[30];
struct elem *next;
} *root;
main(){
<コマンド指示により、指定された関数を実行する。switch文で場合分け>
}
int put_data(s)
char *s; <---- データを単方向リストに登録する関数
{
struct elem *cp;
char s1[40], s2[40];
int i, ret;
cp = (struct elem *)malloc(sizeof(struct elem));!!
if(cp == NULL){
puts("...memory over !!");
return(-1);
}
separate(s,s1,s2); <---- 文字列sをs1とs2に分割する関数
s1[11] = 0x0;
s2[29] = 0x0;
strcpy(cp->name,s1);!!
strcpy(cp->tell,s2);!!
ret = put_single(cp);
printf("ins return ( %d )",ret);
}
とりあえず抜粋しました。特に”!!”の部分の文の意味が把握できません。
構造体の形式は次の通りです。
<コマンド><名前><空白><電話番号>
コマンド: + データ登録
- 名前で示すデータを削除
その他のコマンドにデータの昇順、処理の終了があります。
図等で視覚的に把握できればなぁと思っています。宜しくお願いします。
A
"cp->name"は、一言で説明すると"(*cp).name"と全く同じものです
(cpがstruct elem cpと宣言されていればcp.nameとなります)。
構造体はポインタとして(*cp).nameのように使われることが多いため(だと思います)
"->"という特別な記号が用意されています。()がないと*(cp.name)となってしまいます。
この説明だけでは理解できないと
思いますが、その理由はたぶんポインタについての理解が完全でないのだと
思います。C言語学習塾でも近いうちにポインタの講座(構造体についてはまだですが)
を予定しております。ここではポインタについてある程度の知識を前提として
簡単に説明したいと思います。
まず、ポインタは場所(メモリ上のアドレス)を示すものであることをよく覚えて
おいてください。Windows 95では場所を表すために4バイト(char型変数4個分)の
サイズが必要です。このためポインタ変数は4バイトになります(struct elem *cpの
cpも4バイトのサイズです)。
4バイトしかないポインタ変数であるcpには当然name(12バイト)やtell(30バイト)
を記憶させることはできません。ポインタの指し示す場所には、nameやtellを
記憶するための領域(実体)が必要です。この実体を確保している部分が
malloc()関数を使っている部分です。malloc()関数をまだ知らない方は、
以下のように配列でも置き換えてみるとよいでしょう(配列にすると
扱える最大数が決まってしまうので普通malloc()を使います)。
struct elem body[100]; どこかでこのような配列を用意しておく
cp = &body[0]; 1回目の呼び出し
cp = &body[1]; 2回目の呼び出し
cp = &body[2]; 3回目の呼び出し
.
.
.
もっと極端な例にすると
struct elem body0, body1, body2 ...; malloc()はこのような変数を次々と作り出してくれる
cp = &body0; 1回目の呼び出し
cp = &body1; 2回目の呼び出し
cp = &body2; 3回目の呼び出し
.
.
.
これで、cpには実体がセットされました。ポインタは*cpで実体にアクセスすることが
できます。cp = &body0;のあとならば*cpはbody0と同じ意味になります。
つまり、(*cp).name === body0.name === cp->nameということになります。
これで、理解できたでしょうか? 感想を教えてください。
Q-16
C言語+SDKでウィンドウズプログラムを作っています。
(VC++4.1)MFCはあきらめています。
ダイアローグ・ボックス、クラスメニュー、アイコンなどの作成
グラフィックスや文字の表示などは一応できるようになったものの
基本的なことでどうしてもわからないことがあります。
それは、子供ウィンドウの作成です。親と同じように作ればよいと
思っておりましたが、CreateWindow()の10番目の引数、
つまりインスタンスをどうするのかでつまずいています。
この関数が失敗するため子供ウィンドウのハンドルはNULLです。
できれば、ごく簡単な子供ウィンドウを表示する
SDKプログラムの例を教えてください。ウィンドウの種類は何でもいいです。
入門書には、ありそうで絶対に出てきません。できれば、32ビット版で
A
子供ウィンドウは何種類か考えられますが、おそらくStudy Cでタートルグラフィック
関数を実行するときに作成されるようなウィンドウをさしているのだと思います。
基本的に親ウィンドウと同じように作ればよいのですが、何かが不足しているのだと
思います。また、CreateWindow()の10番目の引数が原因ではないと思います。この値は
親ウィンドウと同じ値を与えればよいのできっと試しているでしょう。それよりも
8番目の引数の方が子ウィンドウに影響を与えます(まずはNULLでためしてみてください)。
子ウィンドウをオープンするまでの手順を簡単に説明すると次のようになります。
(1)子ウィンドウのWndProc()を作成(例 : ChildProc(){...})
(2)起動時に子ウィンドウのWndProc()などのクラス情報をRegisterClass()で登録
(親ウィンドウのクラス登録の直後にでも行ってください)
例)
wndclass.lpfnWndProc = ChildProc;
wndclass.lpszClassNmae = "CHILD";
.
.
RegisterClass(&wndclass);
(3)子ウィンドウのクラス名でCreateWindow()をコール(まずはWS_OVERLAPPEDWINOWで
試してみてください)
例)
hWnd = CreateWindow("CHILD", "CHILD", WS_OVERLAPPEDWINOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL,
hInst/*グローバル変数などで保持しておく*/, NULL);
表示できない原因がわかったら教えてください。
Q16で質問をしたものですが、教えていただいたとおりやってみると実に簡単に
成功しました。ありがとうございます。間違いの原因は、やはりインスタンスでした。
実は、私は今までサードパーティのライブラリを使ってウィンドウズプログラミングを
しておりました。どういうものかというとメッセージ処理を肩代わりしてくれるもので
dos-likeな書き方で簡単にウィンドウズのプログラムができてしまいます。
しかもほとんどのAPI関数が使えるので重宝しておりました。ところが、やはり自分で
メッセージ処理がしたくなる場合が出てきます。(SetTimer関数を使いたいときなど)
この場合ウィンドウをサブクラス化してメッセージ処理を行わなくてはいけません。
この時16ビット版ではMakeProcInstance関数を使いますね。
ここで、私の勘違いが始まりました。すなわち、ウィンドウごとにインスタンスを
取得しなくてはいけないと・・・それで子供ウィンドウと親ウィンドウのインスタンスが
同じはずがない・・・ 考えてみるとばかばかしい間違いですが本人は1週間くらい徹夜で
悩みました。ともかくありがとうございました。また、おかしな質問をするかもしれませんが
よろしくお願いします。
Q-17
Q15の質問をさせて頂いたものです。
こんなに早くお答えを頂き、びっくりしています。ありがとうございます。
"cp->name"は"(*cp).name"と同じことであるという説明は納得できました。ありがとうございました。
実際のアドレス値の取り扱いについてもうちょっと質問させて下さい。
同じ関数でも引数にアドレス値と実際の値をとれるものがあります。
このへんで混乱をきたしてしまうのです。
例えば、
char s[10] = "Lesson24",
t[] = "String";
char *p;
とすると、
p = strcpy(s,t);
と書けます。この場合のs,tの記述はそれぞれの文字列の先頭アドレスを示しているの
ですよね。 標準関数であるstrcpyはこの場合、sの先頭アドレスを戻り値にするという
ことですから、pにはsの先導アドレスが代入されるはずです。この処理の後、
puts(p); という記述があるのですが、pはアドレス値ですよね。なんでこの場合puts
表示が"String"になるのでしょう?
puts("string"); 等の文は理解できるのですが、引数にアドレス値をいれて実体が
出力できるのはなぜなのでしょう。教えて下さい。
このホームページには大変に感謝しています。これ位感謝したホームページはありません!!
A
どの入門書も"cp->name" = "(*cp).name"と説明していると思っていました。
これだけで、理解していただけたならよけいなことを書きすぎたようです。
"..."に関数する質問ですが、これも一言で説明すると"..." => アドレス値です。
"..."と表現するとなにか実体があるように感じますが、実際は100番地とか200番地と
言ったアドレス値にコンパイラが変換してしまいます。
C言語では"..."とアドレス値を区別することはできません。
puts("abc")もputs(p)もputsからみればputs(0x100)とかputs(0x200)のような
アドレス値に見えています。
Q-18
-- C Ver6(Windows95)上でタスクをマルチに実行する方法について --
例えば以下の様にタスクAとタスクBがある場合、タスクAからexeclによりタスクBを
起動した後、再びタスクAに処理が返り(タスクBからはexeclを使わない)タスクAと
タスクBがマルチに実行できる方法を教えて下さい
また、C++でないと不可能であれば下記プログラムはそのまま使用可能であるか教えて
下さい
// --- task A ---
#include <stdio.h>
#include <process.h>
main()
{
printf(" This program is taskA");
execl("taskB.exe","taskB.exe",NULL);
printf(" taskA -> taskB 起動後");
.
.
.
}
// --- task B ---
#include <stdio.h>
#include <process.h>
main()
{
printf(" This program is taskB");
.
.
.
}
A
ちょっと質問の意味が分からないところがあります。このプログラム例が何かの
システムで要求どおりの動作をしているように書いてあるのですが、普通のexecl()
関数でプロセス(この質問の意味ではタスクよりプロセスと表現した方が良いようなので
プロセスとします)を呼び出すと、その時点で呼び出しもとのプロセスは消滅してしまいます。
つまりtask Bが起動されるとtask Aは終了してしまい。printf(" taskA -> taskB 起動後");
やそれ以降の処理は行われないはずです。もちろんこのプログラム例はWindows 95でも動作
するでしょうが質問の内容とは違っているのではないでしょうか?
こまかい使い方は別として、Windows 95でのプロセス起動はCreateProcess()で行い
ます。execlもそのライブラリ内でCreateProcess()を呼び出しているはずです。
CreateProcess APIを普通に使えばtask Aからtask Bを起動しその後両プロセスは
動き続けます。もちろんC++でなくても使えます。
Q-19
先日は、ランダムに関する質問に答えて頂きありがとうございました。
現在、私はVRP(容量制約付き配走路問題)というTSP(巡回セールスマン問題)
に需要量の制約がついた問題を解くためのプログラムを作っています。先日の1からnの
数字は訪問する顧客の番号でして、番号の並んだ順に顧客を訪問するという初期解を
複数作るときに必要だったのです。そして、これから最適解を求める過程でこれらの
顧客を「削除」「挿入」という作業をするためにデータ構造の「リスト」を使うことに
なるのですが、巷の本ではポインタを用いた説明ばかりで、僕には理解し難いため
「配列」を用いて、教えて頂けないでしょうか。その説明の上で、先日の1からnの
数字をランダムに「リスト」にして頂けると助かります。また、VRPを遺伝
アルゴリズムで解くプログラムをご覧になった記憶がありましたら、是非教えて
頂けないでしょうか。
A
VRPとかTSPはわかりませんが、削除や挿入がある以上ポインタを使うべきだと
思います。データを配列に格納してループやmemcpy()などで格納場所を移動して
削除や挿入を行えないこともないですが、効率が悪いだけでなくプログラムも
かえってわかりにくくなると思います。
Q-20
DOS/VマシンでWindows 95を使っています。このシステムでDOS BOXを起動すると
キーボードがASCII配列となってしまうことがあります。リブートすると
JIS配列に戻ったりもしますがあまり規則性がありません。DOS BOXのクローズと
再オープンでは直りません。この現象はDOS BOX内だけで他のアプリケーションは
正常に入力できます。対処方法をご存じの方がいらっしゃいましたら教えてください。
A
Logitechマウスのコントロールソフトをインストールすると
この現象が現れるようです。アンインストールしてコントロールパネルのマウスの
設定でLogitechマウスを選ぶと直りました。
まだ、発生していました。同じマシンに新しくWindows 95をインストールした時、
Logitechマウスのコントロールソフトの一つ前のバージョンをインストールした
ところ100%上記の症状が発生したため、新しいバージョンのコントロールソフト
を再インストールしてみました。しかし、依然上記の症状は100%発生していたため
アンインストールとコントロールパネルのマウスの再設定を行ってみました。
これでほとんど症状が表れなくなったのですが、しばらく使っていたところ
ときどき発生しています。
Q-21
Q18の質問をしたものです。回答ありがとうございました。回答について再度質問ですが、
私が使用しているMicrosoftCVer6.0ではCreateProcess()がありません。別にライブラリを
購入する必要があるのか教えていただけないでしょうか。
A
Microsoft C Ver6.0というとかなり古い製品(どういう製品かもう覚えていません)の
ようですが、Windows NTやWindows 95用の
Win32開発環境は付属しているのでしょうか? なければ、バージョンアップしなければ
Win32の開発はできません。Win32の開発が可能という製品ならCreateProcess()ライブラリ
は存在するはずです。
Q18に関してですが、私はずっと以前にMSC6.0使っていました。これは、OS/2の開発
(開発キットは別売りだったと思います)は、できてもWindowsのSDKには対応してい
るのでしょうか。 また、対応していたとしても、printfなんかは使えないと思います
が・・・マルチスレッドのプログラムを作るには、今ならVC++4.0以降だと思います。
でも、これってすごく難しいんですよね。多分VBではまだマルチスレッドに対応して
いなかったと思います。参考になれば・・・
粂井康孝様 kumei@iacnet.or.jp
Win32アプリケーションのprintfについて
Win32のAPIを使い開発する場合、ときどきprintfで表示させてデバッグを行っています。
開発しているソフトはoterm上から起動します。表示にprintf("...");fflush(stdout);
を使いフォーカスをotermに移すとprintfのメッセージが表示されます
(otermはDOSボックス風のコマンド入力ウィンドウです。
ここからダウンロード
できます)。
DOSボックスから起動する場合は、開発するソフトをリダイレクトして起動すれば
ファイルを表示してメッセージを確認することができます。
Q-22
data[i][j] という二次元配列で、i は0、1、2、と入るようにして、 j には構造体を
配列したいのですが、どのように行えば良いのでしょうか。
A
質問が間違っているような気がします。「data[整数][構造体]としたい」と取れるのですが
[]内には構造体は使えません。data[整数][構造体.整数型のメンバ]としかできません。
こういう質問ではないような気がしますが、どうでしょうか?
Q-23
データ入力が終了したとき、「E」を入力するのではなくリターンキーを押すだけで
よいように作り替えてください。*/
下の様なプログラムで,データ入力をchar型で
入力し、その後int型に変換するのですが、
データ入力の終了条件は,「E」を入力したときです。これをリターンキーのみを押すと
データ入力が終わるようにしたいのです。どのようにすればよいでしょうか?
int main(void)
{
int n;
double sum, xsum, av, sg, sd;
char data[64],str[2];
n = 1;
sum = 0.0;
xsum = 0.0;
while(1) {
main_str:
printf("data[%3d]=", n++);
scanf("%s", data);
if (strcmp(data,"E") == 0){ <-- ここ!!
while(1) {
printf("処理を中止しますか?");
scanf("%s", str);
A
Cの標準関数を使う場合、ユーザーインターフェイスに期待しないことです。
たぶん、scanf()では質問の要求仕様をみたすことができないと思います。
それに、このプログラムでは64バイト以上になる文字列を入力したら
暴走してしまうのではないでしょうか? このような理由からCの標準関数で
キーボードからの文字列入力に使える関数はfgets()くらいしか考えられません。
まずはfgets()に書き換えるべきでしょう。
fgets()を普通に使って満足できないようなら
環境に依存した方法でユーザーインターフェイスを作る必要があります。
しかし、かなりの行数のプログラムを作る必要があります。
Q-24
質問があります。通常、文字型配列では、char s[10]などと、配列の最大値を
決めますけど、配列の長さを限定しないで、自分の好きなだけの長さを持たせる
ようにするには、どのようにすればよいのでしょうか。宜しくお願いします。
A
ポインタとmalloc()系の関数を使用します。たとえば次のようにします。
char *s;
int len1, len2;
len1 = 10;
len2 = 100;
.
.
.
s = malloc(len1);
if(s == NULL)
エラー処理
strcpy(s, "....");
.
.
.
free(s);
s = malloc(len2);
if(s == NULL)
エラー処理
strcpy(s, "....");
このほかstrdup()関数なども有用かもしれません。malloc()を使う方法でも完全に最大値
から解放されているわけではありませんが、配列よりは自由度は上がります。
Q-24
C言語でhtmlのテキストボックスなどに入っている値を持ってくることは
可能ですか。また、どのようにすればよいのでしょうか?
A
可能です。だいぶ前にプログラムしたことがあります。ちょっと記憶がさだかでは
ありませんが、標準入力か環境変数(methodによって異なります)で渡されてきたと
思います。
WEB SEMINALの
7F
に情報があるかも知れないので参照してみてください。
Q-25
studyCをダウンロードしました。早速 C:\StudyC\MyProg>tg openwin(500, 400)と
コマンドを入れたのですが、 関数のパラメータ値が一致しませんという警告がでてき
てしまい、windowが開きません。何が悪いのでしょうか?
教えていただけますか?
宜しくお願いします。
A
さきほど、早速 C:\StudyC\MyProg>tg openwin(500, 400)と
コマンドを入れたのですが、 関数のパラメータ値
が一致しませんという警告がでてきてしまい、windowが開きません。
という質問を致しました。
(500,400)というところを、(500.400)と書いていました。ピリオドにしていました。
ちゃんと起動しました。どうもすみませんでした~。
Q-26
MAX EDITORをダウンロードして、setup.eucの通り、me_linkを実行して、
wmaxコマンドを実行したのですが、以下のようなエラーメッセージがでて
しまいます。Color set or get errorまったく対処方法がわかりません。
どうしたらうまくいくのでしょうか。
A
一度リブートして、起動し直したらちゃんと起動できたみたいです。
お手数かけてどうもすいませんでした。
Q-27
C言語を使って、UNIXの機能のWCコマンド(行数、単語、文字数などを表示)
と同様な機能を実現させるにはどのようにすればよいのでしょうか。
A
まず、どの部分がわからないのかをはっきりさせることが必要です。
wcコマンドの処理は次のようになります。
(1)コマンド行からのファイル名、オプションの取得
(2)DOSやWindows 95などではワイルドカードの展開
(3)カウントするファイルを順番にオープン
(4)ファイルの内容を読み込みカウント
(5)クローズや表示などの処理
Q-28
#include <stdlib.h>
これを書くとエラーになってしまいます。どうしたらよいでしょうか?
実は結城浩著「C言語プログラミングレッスン入門編」の、59ページ List3-5を入れたらそうなって困っています。
よろしくお願いします。
A
インクルードファイルは、主に構造体定義、define、標準関数のプロトタイプ宣言から構成されております。
Study Cでは、このうちの標準関数のプロトタイプ宣言と一部の構造体定義をインタープリタ内部に持っています。
このため、必要でない(用意するとしたら空のファイルになってしまう)インクルードファイルがあり用意しておりません。
質問のエラーを回避するには、存在しないインクルードファイルのinclude行を削除してしまいます。
また、stdlib.hという空のファイルをc:\studyc\include(デフォルト位置にインストールした場合)に
作成してもかまいません。
Q-29
全く基本的な質問ですが、よろしくお願いします。
以下のような data ファイルをリダイレクションで xx.exe へ入力する場合、
#-- 以下1行全部を buf へ読み込む方法を教えて頂けないでしょうか?
(下記PGMを実行しますと空白があるため#--- が最後まで読み込めない!?)
*** data *** 入力データ
1.2
2.5
#-------- space -----
*** xx.c *** プログラム
#include <stdio.h>
main()
{
float f1;
float f2;
char buf[100];
scanf("%f",&f1);
scanf("%f",&f2);
scanf("%s",&buf);
printf("float f = %f",f1);
printf("float f = %f",f2);
printf("string of buf = %s",buf);
}
*** 計算結果*** (#-------- space ----- と出力されない)
c:\>xx < data
float f = 1.200000
float f = 2.500000
string of buf = #--------
以上よろしくお願します。
A
C言語学習塾の「情報処理第2種 C言語問題のファイル入力部徹底解説」でちょうど同じ
ことが説明されています。標準入力の説明ではありませんがfpをstdinとすれば、今回の
ケースと同じになります。
Q-30StudyCユーザからの質問
ナツメ社の「はじめてのC言語」(中山敬二 著)を「Stydy C」を使って勉強しています。
ポインタ配列に関して質問があります。上記の本のP.266-268を参考に下記のような
プログラムを作成しましたが、意図した結果(都市名が3行、3回出力される)になりません。
3つのfor文の出力結果は同じになると思うのですが。ちなみに、*city[]の部分を
city[3][8]に変更すると意図した動きになります。
main()
{
static char *city[] = {"Tokyo", "Osaka", "Nagoya"};
int i, j;
for(i = 0; i < 3; i++){
printf("%s", city[i]);
}
for(i = 0; i < 3; i++){
printf("%s", *(city+i));
}
for(i = 0; i < 3; i++){
for(j = 0; *(*(city+i)+j) != '\0'; j++){
printf("%c", *(*(city+i)+j));
}
printf("\n");
}
return(0);
}
A
Study C Ver1.03のバグのため上記のプログラムが正常に動作しておりませんでした。
修正版(Ver1.04)を
ユーザーサポート
のページにアップロードしておきます。単純なポインタではなく**p、や*p[10]のように組み合わせて使う場合はVer1.04を
ダウンロードしてからお使い下さい。
Q-31StudyCユーザからの質問
作成したプログラムや図をプリンターにて印刷するには?
A
タートルグラフィック機能で表示した図形などは、Alt+PrintScreenキーで
クリップボードに書き込み後、ペイントなどのグラフィックツールへ取り込んで
印刷してください。
プログラムリストの印刷機能は現在作成中です(6月頃のリリース予定)。印刷機能の
対応版はダウンロード可能にする予定です(印刷機能はプリンタドライバによっては
動作しない可能性もあるのでご了承ください)。
→プログラムリストと画面に表示されている文字の印刷機能を追加したVer 1.08を
リリースしました。
ユーザーサポートのページからダウンロードしてください。
Q-32StudyCユーザからの質問
多分、簡単なことを見落としているはずだと思うのですが、どうしてもこのプログラムが
わかりません。お手数ですが教えていただけないでしょうか
二つの整数値を読み込んで、前者の値が後者の何%であるかを表示するプログラムを
作成するもの・・
二つの整数を入力してください。整数A:54 整数B:84 Aの値はBの64%です。
というふうになればいいのですが・・・・
A
結果がどう思い通りにならないのかが不明ですが、おそらく0になってしなうのだと
思います。A、Bに整数型の場合両変数に54と84をセットし C = (A/B) * 100; という式で
パーセントを求めようとすると結果は0になってしまいます。これはA/Bの結果が0.64 = 0
(整数型の場合)になってしまうからです。
対処方法は C = (A*100)/C; とすればよいでしょう。doubleやfloat型を使っても正しい
結果が得られますが、安易にdouble、float型を使うべきではありません。パーセントを
小数点以下2桁まで表示するような場合でも、double、float型は不要で以下のようにすれ
ば求められます。
main()
{
int A, B, C;
scanf("%d %d", &A, &B);
C = (A*10000)/B;
printf("Percent = %d.%02d\n", C/100, C%100);
}
Q-33StudyCユーザからの質問
初歩の質問ですが、system関数を使うためにはどうすればいいのですか?
A
この質問は、手違いで掲載が送れてしまいました。
StudyCではsystem関数を用意していないため、使用することができません。
system関数がANSI C規格には含まれていないことと、あまり安全ではない
関数と判断したため現在のバージョンでは用意していません。
Q-33StudyCユーザからの質問
どうやってもこの構造体のアドレスが渡されません。・・・
meibo[0] → struct s_data *p
どうすればよいのでしょうか?
別のコンパイラではエラーは出ないのですが。・・・
void main(void);
void nyuryoku(void);
void hyoji(void);
char s[20];
static struct s_data{
char name[20];
int age;
char jusho[30];
}meibo[10];
void main(void)
{
nyuryoku(meibo); ←ここで、パラメータの数が合わないと表示される。
hyoji(meibo);
}
void nyuryoku(struct s_data *p) /*ある参考書でもこんな感じでした。*/
/* ↑meibo[0]のアドレスを格納したつもり。*/
{
int x=0;
while(x<10)
{
printf("名前を入力してください。");
gets(p->name);
printf("年齢を入力してください。");
gets(s);
p->age=atoi(s);
printf("住所を入力してください。");
gets(p->jusho);
x++;
p++; /*meibo[0]~[9]のアドレスがインクリメント*/
}
}
void hyoji(struct s_data *q)
{
int y=0;
while(y<10)
{
printf("%s,%d,%s",q->name,q->age,q->jusho);
q++;
y++;
}
} /*お手数ですが宜しくお願いします。*/
A
質問のプログラムは、単純なコーディングミスがあります。
void nyuryoku(void);
void hyoji(void);
この部分が間違っています。正しくは
void nyuryoku(struct s_data *);
void hyoji(struct s_data *);
などとする必要があります。これをエラーにしないプログラムはかなり珍しいと思います。
また、このような疑問点があるときは、もっとプログラムを削って行き小さいプログラムに
していくと良いでしょう(質問するときも同様)。質問のプログラムならまず、hyoji()関数
は関係ないので全部削ることができます(nyuryoku()関数の内容なども)。
Q-34StudyCユーザからの質問
巷の文法書には色々なヘッダーがあり(math.h ctype.h stdlib.h)これらのない
studycでは、この問題は、解けないのですか?
A
Study Cでは主なインクルードファイルの内容が、最初から内部にセットしているため
使用する必要がありません。標準関数のプロトタイプ宣言なども内部に保持しています。
空のヘッダファイルを用意しておいて表面上はインクルードしているように見せかけても
よいかと思います。
Q-35
windows98上でC言語の勉強をしたいのですが、Study Cを購入するだけで、
それが可能なのですか。それとも、他に何か必要なのですか。製品を購入していないのに、
質問して申し訳ありません。
A
Study CがあればC言語の勉強は可能です。ただ、Study Cはプログラムを入力し実行させ
その動作を観察する機能しかないので(学習機能はありません)、何か入門書が必要となります。
C言語学習塾のページは最初の
入門書としては最適ですが、このページはC言語の勉強を始める最初の一歩でつまずかない
ことを第一目標に作成しているため内容的には不十分(簡単すぎます)です。いずれ次の入門書が必要になると思います。
C言語の文法が十分理解できたらUNIXやWindowsなどの専用ソフトの作り方を勉強
することになると思いますが、その段階でStudy Cの役目は終わりとなります(GNU Cや
Visual C++などを使用することになります)。
また、現在StudyCはWindows 95に正式対応となっております。Windows 98での動作確認
は一通り完了しておりますが、ドライバやOSのリビジョンによる問題などが発生する
可能性もあります。ご購入の前には必ずサンプル版での動作確認をお願いいたします。
Q-36
例えばファイルから読み込んだ 「10010」 を10進でなく、 2進で表したいんですけど、どうしたらいんでしょうか??
A
ケーススタディに
2進数で表示するプログラムを追加しましたので参考になると思います。
Q-37
駐車料金を出すシステム
駐車開始時刻を入力し終了時刻を入力すると料金が表示されるプログラムを教えてください
A
ケーススタディに
駐車料金の計算プログラムを追加しましたので参考になると思います。
Q-38
三日三晩考えたのですがどうしてもわかりません。次のがその問題です。
”入力行の長さを100文字以下であると仮定して、テキストを読み込み、
行の長さの分布と、平均を調べるプログラムを作れ。
分布は配列カウンタに書き込み、平均はその配列を引数として
取る関数によって計算するものとする。(改行文字も行に含まれる)”
というものです。初心者の僕にはさっぱりわかりません。どうかヒントをお願いします。
A
ケーススタディに
1行の文字数の分布図プログラムを追加しましたので参考になると思います。
Q-39
”フィボナッチ数列のn番め値を表示せよ。"
Fo=0 Fn=Fn-1+Fn-2
F1=1
突然すいません!大学の課題の一つです。
本を読んでもいまいち分かりません。
どうかこの問題1つだけ答えいただけませんか?
A
ケーススタディに
フィボナッチ数列のn番めの値を求めるプログラムを追加しましたので参考になると思います。
Q-40
初めまして。僕は今、高1なんですけど、プログラミングの勉強をしてみようと思っています。
そこで質問があるのですが、C言語を勉強するにはどれくらいの数学の知識が必要になりますか?
高1の僕でもC言語を理解する事は可能でしょうか?教えてください。
A
プログラミングに数学の知識はほとんど必要ありません(中学の数学程度は理解している方がなにかと便利だと思います)。
特に入門レベルで数学の知識はほとんど必要ありません。
実際、著者がプログラムを始めたのは中学3年の時(当時はFORTRANでしたが)なので全く問題ないと思います。
高1からプログラミングの勉強を始めるのは、パソコンが普及している現在では遅いぐらいだと思います。
すぐに勉強を始めた方がよいと思います。
注)将来作成するプログラムの分野によっては、その分野に関する数学の知識が必要になってくると思います(たとえば3Dのプログラムを作るときには三角関数を使うと思います)。
Q-41
初めまして。昔挫折したC言語を勉強しようと思い、参考書を片手に勉強していましたが、やはり初心者の私にとっては、参考書に書いてあることに対する補足が必要な状態で、悪戦苦闘しておりました。
そんな時に、当ホームページを発見しました。今までの疑問がほとんど解消されました。ほんと~に助かりました。
私はStudyCを購入していないので、14回以降を勉強することができず非常に残念です。こんなに良い内容なので、公開してくださった方が私以外の方々にも役にたつと思いつつも、開発費・運営費といった資金は必要だからな~とも思う今日のこの頃です。
と長くなってしまいましたが、早速質問です。
ケーススタディの文字列操作3(文字列の前後逆転)で配列に格納するプログラムですが、for文の中で、iは1からではないでしょうか? 0から始めるとresult[0]は、' 'になってしまうと思うのすが。
・result[j]ではなくresult[j++]もしくresult[j] = ~; j++;ではないでしょうか?
宜しくお願いします。
A
ご指摘いただきありがとうございます。プログラムが間違っていたので修正しておきました。
Q-42StudyCユーザからの質問
StudyCを購入し、今日届きました。早速インストールし、自作のプログラムを実行すると、プログラム
#include <stdio.h>
#include <string.h>
int menu();
main(){
・
・
}
kojin.c [1]: 1: ERROR(113) インクルードファイルがオープンできません.
というエラーが、発生します。
環境変数を調べてみるとINCLUDE=C:\Program Files\StudyC\includeとなっており、おかしい所がないと思うのですが、プログラム上どうしてもインクルードファイルを使用したいため、お手数ですが、ご指導お願いします。
A
スペース(空白)文字が含まれているディレクトリ(C:\Program Files\など)にStudy Cをインストールすることを想定していなかったため発生した問題です。
早急にインストーラを修正してインストール先ディレクトリにスペース(空白)文字が含まれていないかチェックするように修正します。
お手数ですが、空白文字を含まないディレクトリ(C:\StudyC\など)にインストールし直してください。
また、string.hファイルは、現在特に必要ないため用意していないので、Q-28のを参照ください(stdlib.hをstring.hと読み替えてください)。現在、stdlib.hに必要な定義が追加されたため存在していますが、string.hは必要な定義が同インクルードファイル内に存在しないため用意していません(空のファイルになってしまうので)。
プログラム内に#include <string.h>と記述したいのであれば、c:\studyc\include\string.h(デフォルトインストールの場合)という空のファイルを作ってしまえばstring.hのインクルードエラーは発生しなくなります。
2000/9/27以降の出荷分のStudy Cおよびダウンロードしたサンプル版は、インストールするディレクトリの空白文字チェック機構を入れました。
また、インストール時にctype.h、string.h、math.hファイル(内容はほとんど空です)も用意しました。
今回はインストールプログラムの修正と、空のインクルードファイルを書き込むだけなので進パージョンとしての差分ファイルは用意されていません。
Q-43StudyCユーザからの質問
始めまして。まだまだ初心者です。ですが、ちょっとほかの入門書を読んでいて分からない所が出てきたので、ご質問します。
以下、分からないプログラムです。
#include <stdio.h>
char *str_copy(char *d,const char *s)
{
char *t=d;
while(*d++=*s++)
;
return(t);
}
int main(void)
{
char s1[128]="ABCD";
char s2[128]="EFGH";
printf("文字列s1:");
scanf("%s",s1);
str_copy(s2,s1);
puts("s1をs2にコピーしました");
printf("s1=%s",s1);
printf("s2=%s",s2);
return(0);
}
というものです。
分からない点は、
1.どうして、関数宣言の関数名の所に、「*」がついているのか?
(入門書にはstrcpyなどの関数にもついていました。こちらのHPではついていなかったと思うのですが・・・。
文字列を操作する目的の関数には付くのでしょうか?)
2. どうして、わざわざ、ポインタのtを宣言してそれに代入しているのか?
関数内の式は、while(*d++=*s++) ; だけでは駄目なのか?
3.どうして、このプログラムをstudy.cで実行できないのか?
(ERROR802:自動変数の配列、構造体の初期化はサポートされていません・・・
と表示されます)
の3点です。
以下、勉強不足で申し訳ないのですが、是非お教え頂きたいのですが。どうぞよろしくお願いします。
A
単に文字列をコピーする関数ではなく、strcpyと全く同じ機能の関数を作るという課題なのだと思います。
strcpy関数は、コピー先の配列の先頭アドレス(このプログラムなら変化する前のdの値)をreturn値として返すという機能があるため、このようにプログラムする必要があります。
そのような説明が載っていないのでしょうか? もし載っていないのならとんでもない入門書のように思えます。
また、載っていたとしてもこのような関数を作ったならプログラムは
printf("str_copy = %p,%p\n", s2, str_copy(s2, s1));
などのようにして、動作を確認できるプログラムにするべきです。
もちろん文字列をコピーする関数ならご指摘の通り次のようなプログラムになります。
str_copy(char *d,const char *s)
{
while(*d++=*s++)
;
}
最後に「自動変数の配列、構造体の初期化はサポートされていません」の件ですが、この機能はANSI CというC言語の2番目の規格で導入された機能です。
Study Cは、それ以前から作成されていたのでANSI C対応時に色々機能追加をしたのですが、この機能はほとんど使われないと判断してサポート外にしてしまいました。
実際、実務でお目にかかることはほとんどありません(通常は静的変数の初期化として記述するからです)。
しかし、一部の入門書では(その辺の違いが解って使っているのか不明ですが)むやみに自動変数の配列の初期化を使用しているようです。
このためユーザーの混乱を招きかねないので、現在この機能をサポートする作業を行っていますので、しばらくお待ちください。
→暫定版ですが、自動配列の配列、構造体の初期化機能を追加しました。
ユーザーサポートのページからダウンロードしてください。
また、サンプル版も更新してあるので、この機能が必要な方は
ダウンロードして再インストールしてください。
int main(void)
{
static char s1[128]="ABCD";
static char s2[128]="EFGH";
この機能がサポートされるまでは、上記のように書き換えて実行してください(実務で使うときは普通はこのように記述します)。
→サポートしました。
Q-44
始めまして。初心者な自分ですが、質問があります。
C言語でsinカーブをグラフにするというのはできるんですか。
参考書をみてもいまいちわからないんで・・・。
A
C言語でグラフ表示は可能ですが、初心者にはかなり難しいと思います。
グラフィックの表示を行おうとするとC言語の勉強ではなく、ウィンドウシステムなどのプログラミングの勉強になってしまいます。
Study Cのグラフィック機能は手軽なので初心者にも扱いやすいと思いますが、ゲームやグラフを描くには不向きなため現在新しい機能を追加しています。
この機能追加が完了すれば、sinカーブのグラフを描くプログラムは次のようになる予定です。
#include "oglib.h"
main()
{
int t;
int x, y, lx, ly;
gl_openwin(640, 400);
gl_line(0, 200, 639, 200, 1, 0, RGB(0, 255, 0));
gl_line(320, 0, 320, 400, 1, 0, RGB(0, 255, 0));
lx = ly = -1000;
for(t = -320; t < 320; t++){
x = t*5 + 320;
y = -sin(t/10.0) * 150 + 200;
if(lx != -1000 && ly != -1000){
gl_line(lx, ly, x, y, 1, 0, RGB(255, 0, 255));
}
lx = x;
ly = y;
}
gl_refresh();
}
また、3Dタートルグラフィックライブラリにも、この機能を組み込むのでコンパイルして配布することができます。
コンパイルしたEXEファイルです。
sin
tan
Q-45StudyCユーザからの質問
初めまして、先日StudyCを購入させていただきました。
コンピュータ言語自体が超初心者で始めはちんぷんかんぷんでしたがC言語講座を見ながら勉強して最近すこしづつ分かってきました。(ホントに少しですけど(^^;))
質問ですが、いずれはVisual C++ 6.0を使って3DCGのレンダリングプログラムを作ってみたいのですが、Visual C++なだけにCを始めに勉強するべきかC++を勉強するべきか、少し悩んでいます。
CとC++は基本は一緒といってもどの程度まで違うのでしょうか?
さすがにいきなりVisual C++を使っても難し過ぎると思いましてCをいじってみてはいるのですが・・・。この掲示板にそぐわない内容で申し訳ありませんが、是非教えて下さい。宜しくお願いします。
A
「CとC++は基本は一緒」というよりはCの全ての機能がC++に含まれています。
結局C++をすべて理解するためには、Cを完全に理解しなければなりません。
一部のCの文法だけを理解しC++の勉強に移るという方法や、最初からC++として勉強するという方法も考えららます。
しかし、C++の文法はCに比べるとかなり大規模なので、Cで足下を固めてからC++を勉強する方が良いと思います。
C言語を理解している人向けのC++入門書なども用意されているようなので、C++をそこそこ使えるようになるのに1ヶ月もかからない(C言語をちゃんと理解できていれば)と思います。
Q-46StudyCユーザからの質問
例えば
if(hensa[i]>=55){
printf("A");
}else if (hensa[i]>=45){
printf("B");
}else
printf("C");
となっていたときにA、B、Cの個数を返したいときはどうすればいいのでしょうか。
A
質問の意味が良くわかりませんが、hensaが配列になっているのでA/B/Cの個数をカウントする方法という意味なら次のようになります。
int a,b,c;
a = b = c = 0;
for(i = 0; i < hensaの最大項目数; i++){
if(hensa[i]>=55){
printf("A");
a++;
}else if (hensa[i]>=45){
printf("B");
b++;
}else{
printf("C");
c++;
}
}
printf("A = %d, B = %d, C = %d\n", a, b, c);
Q-47StudyCユーザからの質問
こんにちは、前回質問させて頂いた者です。(Q-45)
初歩的な質問で申し訳ありません。
第七回講座での関数の部分なのですが、(以下)
int print_dot(int);
main()
{
int x;
for (x = 1; x <= 8; x++) {
print_dot(x);
}
}
print_dot(n)
int n;
{
int i;
for (i = 0; i < n-1; i++) {
printf(" ");
}
printf("*");
}
MAIN関数の中で宣言された変数(x)に、print_dot(n)の変数(n)は何故
移動できるのですか?MAIN関数の変数は(n)でなくてリンクできるのかが、
いまいち把握出来ません。なんとなく分かる気がするんですが実際どういった
動きをとっているかが(引数)きっとしっかり分かっていないんだと思います。
勉強不足なのでしょうが、ここでつまずいていて次に進めません。
何かこういった引数や関数の動きを理解する上でコツがあればどうかご教授ください、よろしくお願いします。
A
print_dotが呼び出されるときに「n = x」に相当する処理が自動的に行われているため、xの内容がnに代入されます。
func(int a, int b, int c)という関数にfunc(1,x,2);という呼び出しを行うと呼び出し時にa = 1、b = x、c = 2という代入がfunc関数の呼び出し時に行われます。
Q-48StudyCユーザからの質問
現在日時に指定時間を加算もしくは、減算した日時を取得するには、どのようにすれば、よろしいですか?
例 2000年2月25日12時00分00秒に
10日12時間を加算した場合、
2000年3月 7日 0時00分00秒が
取得される関数がありますか?
A
mktime()で2000年2月25日12時00分00秒をカレンダー時刻に変換し、
10日12時間を秒に変換した値を加算して、最後にlocaltime()でローカル時間に戻せばよいと思います。
ケーススタディのカウントダウン時計の作り方2が多少参考になると思います。
Q-49StudyCユーザからの質問
単純な質問で申し訳ないのですが、プログラムをフロッピーディスクに保存する方法を教えてください。
A
コマンドモードでsave a:\abc.cのように実行するか、ファイルメニューの別名の保存でダイアログ最上部の保存する場所を3.5インチFDにすれば保存できます。
Q-50StudyCユーザからの質問
私はC言語プログラムレッスン入門編という本でStudeyCを使いC言語を学んでいるものですが下記のプログラムがprint_student(taro);という所でエラーが出てしまいます。
StudyCではどのように書き換えればよいか教えてください。
#include <stdio.h>
#include <string.h>
struct student{
int id;
char name[20];
int kokugo;
int suugaku;
int eigo;
};
void print_student(struct student s);
main()
{
struct student taro;
struct student jiro;
taro.id = 10;
strcpy(&taro.name[0],"Yamada");
taro.kokugo = 100;
taro.suugaku = 85;
taro.eigo = 60;
jiro = taro;
jiro.id = 11;
strcpy(&jiro.name[0],"次郎");
jiro.eigo =99;
print_student(taro);
print_student(jiro);
return(0);
}
void print_student(struct student s)
{
printf("出席番号:%d\n",s.id);
printf("氏名:%d\n",s.name[0]);
printf("国語:%d\n",s.kokugo);
printf("数学:%d\n",s.suugaku);
printf("英語:%d\n",s.eigo);
printf("合計:%d\n",s.kokugo + s.suugaku + s.eigo);
printf("\n");
}
ちなみにVisualC++5.0ではエラーは起きませんでした。
A
前方参照の関数で構造体の実体(構造体へのポインタではなく)を渡していて、そのプロトタイプ宣言が行われている場合エラーが発生するというStudyCの不具合でした。
早急に修正版を作成しユーザーサポートのページへアップロードするのでしばらくお待ちください(
→修正版をアップロードしました。ユーザーサポートのページからダウンロードしてください)。
とりあえずは、次のように関数定義の順番を変えて使用していてください。
#include <stdio.h>
#include <string.h>
struct student{
int id;
char name[20];
int kokugo;
int suugaku;
int eigo;
};
void print_student(struct student s);
void print_student(struct student s)
{
printf("出席番号:%d\n",s.id);
printf("氏名:%d\n",s.name[0]);
printf("国語:%d\n",s.kokugo);
printf("数学:%d\n",s.suugaku);
printf("英語:%d\n",s.eigo);
printf("合計:%d\n",s.kokugo + s.suugaku + s.eigo);
printf("\n");
}
main()
{
struct student taro;
struct student jiro;
taro.id = 10;
strcpy(&taro.name[0],"Yamada");
taro.kokugo = 100;
taro.suugaku = 85;
taro.eigo = 60;
jiro = taro;
jiro.id = 11;
strcpy(&jiro.name[0],"次郎");
jiro.eigo =99;
print_student(taro);
print_student(jiro);
return(0);
}
質問の内容とは少しずれますが、このプログラムは構造体の実体を関数のパラメータとして渡す実験のためのものでしょうか?
このようなケースでは、構造体へのポインタをパラメータとして渡します(実験だからと、ちゃんと注意書きがあるでしょうが一応念のために)。
Q-51StudyCユーザからの質問
このプログラムでエラーが出てしまいます。なぜでしょうか?
マクロをつかったらできなくなりました。
#include <stdio.h>
#define FNAME "C:\\My Documents\\filepointa\\data.txt"
main()
{
int old;
char name[32];
FILE *fp;
printf("あなたの名前を入力してください。 -> ");
scanf("%s", name);
fp = fopen(FNAME, "a");
fprintf(fp, "Hello, world.\n");
fprintf(fp, "あなたの名前は %s です。\n", name);
fclose(fp);
printf("処理が終わりました。\n");
}
A
Study Cの不具合のためマクロで文字列内に'\'文字が存在すると正しく実行されませんでした。
取り急ぎ修正版を作成したので、お手数ですが
ユーザーサポートから修正版をダウンロードしてください。
Q-52StudyCユーザからの質問
C言語プログラミングについての質問があります。
御面倒だとは思いますが時間があれば教えてください。
オライリ-ジャパンのC実践プログラミングという本で勉強していたのですが、
本の中で
----------------------------------------------------------------------
非常に小さい整数型は直接読み込むことはできません。まず、数値を整数型に
読み込んでから代入文を使用しなければなりません。例えば次のようにします。
#include
signed char very_short; /*非常に小さい整数型*/
int temp; /*一時的な数値 */
char line[100];
int main()
{
/*非常に小さい整数型を読み込む*/
fgets(line,sizeof(line),stdin);
sscanf(line, "%d", &temp);
very_short = temp;
return(0);
}
----------------------------------------------------------------------
となっています。
sscanf(line, "%d" , &temp);
のところを
sscanf(line, "%d" , &very_short);
でも良いような気がするのですが、本文中のほうがなにかメリットなどが
あるのでしょうか?
あと、直接読み込むことができないというのは、lineをvery_shortでは無理だと
いうことなんでしょうか?
A
---で囲まれた部分が、本の内容だと思います。もし、原文そのままだとしたらとてもわかりにくい説明だと思います。
まず、「非常に小さい整数型」などという表現は初めて聞きました。
それに「直接読み込むことができません」というのも、何がどこからどこへ読み込むのかよく解りませ(前後の部分で詳しく説明してるのでしょうか)。
また、サンプルプログラムでstdinからの入力結果をsscanfに渡している理由も解りません。
scanfでサンプルプログラムを作ればlineという変数も必要なくなり説明が解りやすくなると思います。
上の文を日本語?に翻訳すると次のようになります(サンプルも簡略化します)。
scanf関数で%dを使用する場合は、int型の変数にしか結果を代入することができません。
scanf関数は直接int型以外の変数に代入することができないので、一旦int型変数に結果を代入しその値をsigned char型の変数へ代入し直す必要があります。
#include
signed char very_short; /*非常に小さい整数型*/
int temp; /*一時的な数値 */
int main()
{
/*非常に小さい整数型を読み込む*/
scanf("%d", &temp);
very_short = temp;
return(0);
}
理由も説明すると、int型変数は通常4バイトのサイズを持ち、signed char型の変数は1バイトのサイズを持ちます。
scanf(sscanf)関数で%dを使用すると、結果を4バイト分の場所に書き込んでしまいます。
scanf("%d", &very_short)としてもかまわずに4バイト分のデータを書き込んでしまいます(実際には1バイト分の領域しかないのに)。
このため、very_shortに格納される値が不正なだけでなく他の3バイト分のメモリも破壊されてしまいます。
Q-53StudyCユーザからの質問
こんにちは。質問コーナーでQ-52の質問をしたものです。
すぐに解答していただいてありがとうございました。
私が使っている教本は本当にわかりにくくて苦戦しています。
本屋さんでわかりやすい教本を探してこようと思います。
よろしければなのですが、プログラムの勉強はどうゆう風に学習したのか教えていた
だけないでしょうか? 専門学校などでしょうか? それとも、本屋さんに並んでい
る教本などでしょうか?
ご返事はどんなに遅くなってもいいので、ぜひ教えてください。
お願いします。
A
C言語学習塾の内容は全部理解できましたか。
解りやすく記述したつもりなので入門書を買って勉強する前にご参照ください。
残念ながら「プログラムの勉強はどうゆう風に学習したのか」は、昔過ぎて参考にならないと思います。
本もほとんどなく、情報を集めるのが大変な時代でした。教えてくれるような学校もほとんどなく、すべて独学で勉強しました。
Q-54StudyCユーザからの質問
質問できることをうれしく思います。
ポインタを用いたプログラムで、定義をしなおせ!と、出てきて実行できません。
たとえば、次のようなプログラムです。
#include <stdio.h>
main()
{
int a,b;
int *p;
a=80;
printf("a=%d\n",a);
printf(""&a=%d\n",&a);
p=&a;
printf("*p=%d\n",*p);
printf("p=%d\n",p);
b=*p;
printf("b=%d\n",b);
printf("&b=%d\n",&b);
p=&b;
printf("*p=%d\n",*p);
printf("p=%d\n",p);
}
/*実行結果*/
a=80
&a=3560
*p=80
p=3560
b=80
&b=3558
*p=80
p=3558
以上です。
テキストは、オーム社発行「C言語マスターブック」の問題です。ポインターを扱う問題などに不具合が生じます。よろしくお願いします。C-Studyを購入し、勉強を始めたばかりの者です。
A
ポインタの値(アドレスを)printfで表示している行でエラーになるのだと思います。
printf("%d\n", p);という表現は、Windows 9X(Win32)などで使用するコンパイラでは問題なく動作します。
しかし、一世代前のMS-DOS用コンパイラ(メモリモデルによる)では、正しく動作しないこともありました。
その理由は、int型が16ビットのサイズでポインタ型が32ビットのサイズというパターンがあったためです。
また、将来広く使われるコンパイラのint型が32ビット、ポインタ型が64ビットとなる可能性もあります。
その時printf("%d\n", p);は、また間違った表現になります。
正しい使い方は、printf("%p", ポインタ);となります。
%pという書式がポインタのアドレスを表示するために用意されています。
printf("%d",int型);
printf("%p", ポインタ);
上記のように%d、%pで次に与えることのできる変数などの型が決まっています。
Study Cでは、このような間違った使い方をエラーチェックで知らせています。
通常のCコンパイラではprintfの2番目以降のパラメータはチェックしないためどんな型の使い方をしていてもエラーになりません。
結局、Study Cで正しく表示させるには次のように変更してください。
printf("%d\n",(int)p);
printf("%p\n", p);
ただし、%pを使用することを強くおすすめします。
ポインタ型とint型は、全く別の型であり両者のサイズは一致しないことを念頭においてポインタを使用してください。
一応正しく表示できるprintf("%d\n", ポインタ);のようなパターンは、Study Cでエラーチェックしないようにして各入門書の説明にまかせてしまうことも検討しております。
ご意見のある方は、お聞かせください(下記のフォームから)。
Q-55StudyCユーザからの質問
はじめて質問いたします。宜しくお願い致します。
下記のプログラムを実行すると
"123-4567 東京都千代田 03-1111-1111 123-4567 東京都千代田 03-2222-2222 "
とFileにWriteされるのを
123-4567東京都千代田 03-1111-1111
123-4567東京都千代田 03-2222-2222
とWriteさせたいのですが。
(質問1)構造体をファイルにWriteした際、構造体の最後にCRLFを付与したいのですが
どうすれば良いのでしょう。
(質問2)文字配列を定義する時には、実際のデータ長+1バイト必要ですが
ファイルに書く時には 実際のデータ長分のみWriteしたい時はどうすれば良いのでしょう。
struct personal_info {
char zip[9]; /*郵便番号*/
char addr[13]; /*住所*/
char tel[15]; /*電話番号*/
} pinfo1,pinfo2;
FILE *fp1;
main()
{
strcpy(pinfo1.zip, "123-4567");
strcpy(pinfo1.addr, "東京都千代田");
strcpy(pinfo1.tel, "03-1111-1111");
strcpy(pinfo2.zip, "123-4567");
strcpy(pinfo2.addr, "東京都千代田");
strcpy(pinfo2.tel, "03-2222-2222");
fp1 = fopen( "temp", "a+" );
if( fp1 == 0 ){ /*ファイルオープンに失敗した*/
printf("Can't open\n");
return;
}
if(fwrite(&pinfo1,sizeof(struct personal_info),1,fp1)!=1){
printf("error \n");
};
if(fwrite(&pinfo2,sizeof(struct personal_info),1,fp1)!=1){
printf("error \n");
};
fclose(fp1);
}
A
(質問1に対して)fwriteの後にfwrite、fputs、fprintfなど(どの関数でもよいですが)の関数を使用してCRLFを出力するしかないと思います。
(質問2に対して)fwrite(pinfo1,zip, 8, 1, fp1)のようにすれば、余分なデータは必要無くなります。
構造体の各要素に対して同じことをしたければ、構造体データの書き込み関数を別に用意して、その関数内で構造体の各要素ごとに上記のように書き込む必要があります。
他に、余分なデータを含まない構造体を用意してstrncpyなどの関数でデータをセットしfwriteで一度に書き込む方法も考えられます。
補足)
WindowsなどのMS-DOS系のOSでfwriteを上記のようにバイナリデータ的に使用するのであれば、fopen(..., "ab+")としてバイナリオープンにする方が良いと思います。
また、各要素(addr)などには短いデータが含まれるのでしょうから、データの後にCRLFを挿入するのも必要ないように思います。
残りの文字を'\0'でなくスペースで埋めるなら別ですがそのようなデータにするとstrlenで真の文字数がわからないなどの問題が生じます。
Q-56StudyCユーザからの質問
Study C利用させて頂きC言語の勉強をさせて頂いております。
さて、質問ですが、第1回実力試験の1-21の問題についてです。
main()
{
int i;
for(i = 0; i < 40; i++){
if(i/2*2 == i)
printf("O"); ←ここまでは理解できます。
else ←これ以降が理解できません。
printf("X");
}
}
else それ以外という数値にはならない式(i/2*2 ==i)が表示されている事が理解できません。
かなり、的外れな質問かもしれませんが、お手数でなければ教えて頂けないでしょうか。
A
「数値にはならない式が表示...」という意味がよく解らないのですが、elseについて説明します。
elseは下記のように記述する所を簡略に表現できるようにしたものです。
下記の二つの書き方は同じ動作をします。
if(iが偶数なら)
printf("O");
if(iが偶数でないなら)
printf("X");
→
if(iが偶数なら)
printf("O");
elsel
printf("X");
Q-57StudyCユーザからの質問
プログラムの実行エラー行が、赤く反転してとても見にくいのですが設定を変える方法を教えて下さい。
A
色が暗いために見づらいのだとおもいます。少し明るい赤に設定し直したファイルを用意しました。
このファイル(20Kbytes)をダウンロードして「C:\StudyC\bin\」ディレクトリにコピーしてください。
ご自分でカスタマイズしたい方は、MAX EDITORのヘルプをご参照ください(Study C自体はカスタマイズ方法を公開しておりません)。
Study Cユーザの方は、
ここからMAX EDITORをダウンロードすることができます。
Study Cでは、ヘルプ中のme95set.exeはsc95set.exe、me_msw32.defはsc_msw32.defなどと読み替えてください(他にも一部異なる点があります)。
また、sc95set.exeなどのファイルはセットアップ用FD内にあるのもをご使用ください(ハードディスク上にはコピーされていません)。
Q-58StudyCユーザからの質問
「数当ての原理を教えてください。」
手順a)~b)について
a)相手に1~31の好きな数字を選んでもらう。
b)以下の5のカードを相手に渡し、a)で選んだ数字を含むカードを返してもらう。
┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐
│1│3│5│7│ │2│3│6│7│ │4│5│6│7│
├─┼─┼─┼─┤ ├─┼─┼─┼─┤ ├─┼─┼─┼─┤
│9│11│13│15│ │10│11│14│15│ │12│13│14│15│
├─┼─┼─┼─┤ ├─┼─┼─┼─┤ ├─┼─┼─┼─┤
│17│19│21│23│ │18│19│22│23│ │20│21│22│23│
├─┼─┼─┼─┤ ├─┼─┼─┼─┤ ├─┼─┼─┼─┤
│25│27│29│31│ │26│27│30│31│ │28│29│30│31│
└───────┘ └───────┘ └───────┘
┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐
│8│9│10│11│ │16│17│18│19│
├─┼─┼─┼─┤ ├─┼─┼─┼─┤
│12│13│14│15│ │20│21│22│23│
├─┼─┼─┼─┤ ├─┼─┼─┼─┤
│24│25│26│27│ │24│25│26│27│
├─┼─┼─┼─┤ ├─┼─┼─┼─┤
│28│29│30│31│ │28│29│30│31│
└───────┘ └───────┘
以上の情報からa)で選んだ相手の数字を当てることができる。
その方法を教えてください。
よろしくお願いします。
A
2進数を利用して数を当てています。
5枚のカードの1枚目が2進数の1桁目、2枚目が2進数の2桁目、...となります。
選んだ数字を含むカード(返してもらったカード)は該当する2進数の桁が1、数字を含まないカードは該当する2進数の桁が0となります。
たとえば1・2・5枚目のカードを返してもらったとすると、2進数で表記すると10011となります。
これを10進数に変換すると16+2+1=19となります。1・2・5枚目カードにだけ19という数字が含まれています。
Q-59StudyCユーザからの質問
キーボードから連続して整数を受け取り、負の数が入力されたら入力の終了とし、それまでに受け取った0または正の整数の中から最小値と最大値を表示するプログラムをC言語でつくりなさい。
ただし、最初の入力が負の数である場合には、最小値と最大値ともに、その負の数を表示するものとする。
入力値のオーバーフローや整数以外の不正な入力はないものとする。
#include <stdio.h>ではじめると尻が青いとされるそうです。
動けば『可』とのこと。この試験は、アイデアコンテストか!!
模範解答をお願いします。#include <stdio.h>ではじめてもわからなかった。
来年がんばろう!!
Study Cで、試験対策勉強しますのでよろしくお願いします。
A
上記の仕様を満たすプログラムは、次の例のようになります。
ループは、do~while();を使った方が模範解答的かもしれません。
練習に書き換えてみてください。
#include <stdio.h>
main()
{
int min_value, max_value, inp_value;
min_value = max_value = -1;
for(;;){
scanf("%d", &inp_value);
if(inp_value < 0){
if(min_value == -1){
min_value = max_value = inp_value;
}
break;
}
if(min_value == -1 || inp_value < min_value){
min_value = inp_value;
}
if(max_value == -1 || inp_value > max_value){
max_value = inp_value;
}
}
printf("最小 %d、最大 %d\n", min_value, max_value);
}
質問中の「#inclue <stdio.h>ではじめると尻が青い」とは、何のことか理解できません。
Windowsのプログラムなら#inclue <stdio.h>で始まることはないでしょうが、上記の課題なら#inclue <stdio.h>で始まるに決まっています。
Q-60StudyCユーザからの質問
課題1
つぎの関数sampleについて、解答欄に指定した行番号の実行回数をnで表せ。
ただし、x[i]はつぎの構造体を要素の型とする大きさがnの配列である。
配列xの要素の型
struct dada{
int data1;
int data2;
};
関数sample
行番号
↓
1:void sample(struct data x[ ],int n)
2;{
3: int i,j,sum;
4:
5: for(i=0;i<n;i++)
6: x[i].data1=i+1;
7: for(i=0;i<n;i++){
8: sum=0;
9: for(j=i;j<n;j++)
10: sum=sum+x[j].data1;
11: x[i].data2=sum;
12: }
13:}
【解答欄】
行番号 実行回数
5
6
9
10
11
解答欄の記入の仕方からわかりません。
模範解答よろしくお願いします。
A
5 n+1
6 n
9 (n+1)*n/2+n or (n+3)*n/2
10 (n+1)*n/2
11 n
Q-61StudyCユーザからの質問
課題2
nを整数データとするとき、スタックと待ち行列(queue キュー)に対する
操作を次のように定義する。
push(n)・・・スタックにnを積む(例:push(2)・・・整数データ2を積む)
pop・・・スタックからデータを取り出す
enqueue(n)・・・待ち行列にnを入れる(例:enqueue(2)・・・整数データ2を入れる
dequeue・・・待ち行列からデータを取り出す
空のスタックと待ち行列に対して、それぞれ(a),(b)の操作を行った。
それぞれの操作を行った最終結果を図に書き入れよ。
(a)
push(3)→push(5)→pop→push(7)→push(4)→push(9)→pop→pop→push(2)
【解答欄】
├┤
├┤
├┤
├┤
├┤
└┘底(bottom)
(b)
enqueue(5)→enqueue(8)→enqueue(3)→dequeue→dequeue→enqueue(4)
→enqueue(1)→dequeue→enqueu(7)→enqueue(8)
【解答欄】
front↓↓rear
┬┬┬┬┬┬┬┬
┴┴┴┴┴┴┴┴
自信ないので、模範解答よろしくお願いします。
A
StudyCユーザからの質問ですが、同じ方からの質問に既に3回の回答をしているので、オーキッドから回答はいたしません。
どなたか回答していただける方がおりましたら、回答を投稿してください。
Q-62StudyCユーザからの質問
初心者です
申し訳ありませんが、下記の事を教えて下さい。
c言語学習塾 第8回講座
入力待ちの状態です。
scanfの前にprintfで"input data:"のように表示させておいた
ほうが良いと書いてありますが、どこえ、どの様に表示したら
良いのか、お教え下さい。
A
次のようにして表示します。
main()
{
int i;
printf("input data:");
scanf("%d", &i);
print_bar(i);
}
...
Q-63StudyCユーザからの質問
質問です(まだ初心者なので変な質問だったらごめんなさい)
第9講座のstrcmp()の例題の所の
printf("\n%s = \%s\n", str1, str2);
の%sの前の¥の意味が分かりません。
あっても無くても結果は同じでした。
また改行マークの
は最後につけるのだと覚えたのですが、
前にもつけるのでしょうか?教えてください。
A
プログラム例の間違いでしたので訂正しておきます。
ご指摘の通り¥文字は必要ありません。
Q-64StudyCユーザからの質問
localtime()関数で日本時間が求まるのはなぜですか。
たとえば、シドニー(JST+1時間、GMT+10時間)やニューヨーク(JST-14時間、GMT-5時間)の時刻を求めたいときはどうすればいいのですか。
24時を超えたら日付を+1して、31日を超えたら月数を+1して、・・・という処理を書かなければならないのですか。
シドニーやニューヨークの現地でlocaltime()関数を使ったらどうなるのですか。
A
適切な地域のローカル時間を返すのは、OS(WindowsやUNIXなど)のインストール時に、そのコンピュータをどの地域で使用するか指定するからです(ある地域で使用することだけしか考えられていないOSでは、この指定はないかもしれません)。
ただし、通常localtime()関数には地域をプログラム内で変更する別の関数が用意されています。
通常はtzset()という関数を使用して地域の変更を行います。
ANSI Cの規格に定義されていなかったと思うので、使用するコンパイラによって異なっているかもしれません(また、余り一般的な関数では内のでStudy Cにはtzset関数は用意していません)。
tzset()関数を使用しない場合、「24時を超えたら+1して...」の様なやり方では、
閏年を考慮しなければいけないなど色々面倒なので、time()関数の返した値に1*60*60(秒)を足してからlocaltime()関数を呼び出しても良いかもしれません
(夏時間帯が存在する地域ではその考慮も必要になると思います)。
Q-65StudyCユーザからの質問
非常に単純かつ初歩的な質問ですみません。
Study Cの画面印刷ができません。
画面のプリントボタンを押しても、プルダウンメニューから指定しても、「印刷中」の表示が一瞬表示されるだけで、プリンタからは何も出力されません。
会社でLAN接続していて、他の出力指示は問題なく処理されています。
ヘルプを調べましたが、設定方法などの説明が見当たりません(探し方が悪いのでしょうか)。
どうすれば出力できるようになるのか、ご教示ください。
Q-65、さっそくのご回答ありがとうございます。
補足させていただきます。
プリンタは富士通製のFMLBP226という機種です。
ドライバのバージョンはV1.1L30で、最新版であることを確認しています。
クライアントOSはWin95。サーバOSはWinNT4.0で、SPレベルは6か6aです。
ダイアログ・ボックスに表示されるプリンタは、上記の機種です。
これを「通常使用するプリンタ」と設定しており、プロパティ設定も他の文書印刷に使うときと何らいじっていません。
・・・当面、キャプチャで逃げることにします(涙)が、調査方よろしくお願いいたします。
QA-65への再度の補足です。
プリンタとして、同じLANに繋がっている、富士通製のPrintia XL-5800という機種があるのですが、こちらへ出力依頼をしたところ、画面(正確には、画面に表示されている文字)が印字できました。
どうして、FMLBP226では印刷できず、XL-5800では印刷できるのか、同一LAN上にあるのに謎です。
(ドライバも両方とも最新でした)しかし、機種設定を変更すれば印刷ができることがわかりましたので、当件については一応取り下げとします。どうもお騒がせいたしました。
A
画面印刷ボタンを押すと「画面の印刷」ダイアログボックスが表示されると思います。
ここで、「プリンタの設定」ボタンを押すとさらに「プリンタの設定」ダイアログボックスが表示されます。
ここでプリンタの名前が、出力しようとしてるプリンタになっているか確認して、違っていれば変更してください。
他に変更するところはないので、もしそれでも出力されない場合は、
プリンタドライバをダウンロードして最新のもの(もしあれば)に変更(プリンタサーバとローカルマシンの両方)してみることしか対処方法がありません(ドライバを更新したからと言って印刷できるようになるとは限りませんが)。
それでもダメな場合、対処方法は無いと思うのでStudy CのウィンドウをAlt+PrintScreenキーでキャプチャーしてペイントなどのプログラムに貼り付け印刷するなどしてください。
P.S.
プリンタの機種(ドライバのバージョン)、サーバ/クライアントマシンのOSなど教えていただければ一応調査してみます。
上記のプリンタにも対応できました。→Ver1.09bをダウンロードしてください。
Q-66StudyCユーザからの質問
エディタにある文字を範囲指定してコピーしましたが貼り付けできません。
HP上のプログラムをコピーして貼り付けは出来ました。
STUDYCのエディタ上の文字はコピーできないのですか??
A
Study Cの不具合です。Ver1.09bで修正しました。
ユーザーサポートのページをご参照の上必要な方はダウンロードしてください。
Q-67StudyCユーザからの質問
こんにちわ まだ初心者です。
今、問題集をやっているのですが、例題をそのままうって、実行したら、エラーが出てしまいました。
void sum(float x,float y,float *s_p);
void difference(float x,float y,float *d_p);
main()
{
float a,b,s,d;
float *s_p,*d_p;
s_p=&s;
d_p=&d;
a=2.345;
b= 5.678;
sum(a,b,s_p);
printf("%7.3f + %7.3f = %7.3f ",a,b,s);
difference(a,b,d_p);
printf("%7.3f - %7.3f = %7.3f ",a,b,s);
}
void sum(float x,float y,float *z_p)
{
*z_p=x+y;
}
void difference(float x,float y,float *z_p)
{
*z_p=x-y;
}
以上です。で下記のところでエラーメッセージが出てきます。
sum(a,b,s_p);
difference(a,b,d_p);
よろしくお願いします。
A
Study Cの不具合です。Ver1.09cで修正しました。
ユーザーサポートのページをご参照の上必要な方はダウンロードしてください。
P.S.
2個目のprintfのsはdが正しいのではないでしょうか。
printf("%7.3f - %7.3f = %7.3f ",a,b,s);
→
printf("%7.3f - %7.3f = %7.3f ",a,b,d);
Q-68StudyCユーザからの質問
Q-67 で質問したものです。
アップバージョンしようと思ったのですが、すごく馬鹿な事をやってしまって、手動で削除して入れ直そうとしたけど、cV9Csmp.exeが削除できないのです。
助けてください。ごめんなさい。
それから、昨日のご指摘のとおりです。すみません。
よろしくお願いします。
A
ファイルが削除できない原因は、他のプロセスがそのファイルを使用しているか(この原因ならば、リブート後には消せるようになります)、ファイルのプロパティが読み取り専用になっていることが考えられます。
ファイルのプロパティで読み取り専用属性を外してください。
これ以外の原因はちょっと思い当たりません。
Q-69StudyCユーザからの質問
こんにちわ ポインタと関数の所を問題集で勉強中なのですが、どうしても納得がいかないので、どうか教えてください。
void sum(int ,int *,int *,int *);
void func(int ,int *,int *,int *);
void display(int ,int *,int *,int *);
main() {
int a[5]={2,4,6,8,10};
int b[5]={3,6,9,12,15};
int c[5];
int x[5]={12,14,16,18,20};
int y[5]={23,26,29,20,35};
int z[5];
int count=5;
func(count,&x[0],&y[0],&z[0]);
sum(count,&a[0],&b[0],&c[0]);
display(count,&x[0],&y[0],&z[0]);
}
void sum(int n,int *a_p,int *b_p,int *c_p)
{
以下省略...
上記のようなプログラムを例題に似せてつくって、
func(count,&x[0],&y[0],&z[0]);
sum(count,&a[0],&b[0],&c[0]);
display(count,&x[0],&y[0],&z[0]);
の部分をいろいろ変えてみました。
最初、
sum(count,&a[0],&b[0],&c[0]);
display(count,&x[0],&y[0],&z[0]);
にしたら、結果はcは全部0でした。
次は
func(count,&a[0],&b[0],&c[0]);
sum(count,&a[0],&b[0],&c[0]);
display(count,&a[0],&b[0],&c[0]);
この結果はsum での値が出ました。
で、funcとsumの順番をかえたら、結果はfunc の値が出ました。
次に
func(count,&a[0],&b[0],&c[0]);
sum(count,&a[0],&b[0],&c[0]);
display(count,&x[0],&y[0],&z[0]);
にすると、zの部分は0になると思って
いたのですが、func の値がでました。
ポインタというのは、こういう感じなのでしょうか???
ポインタがいまいち頭に入らないのでちょっと納得できないのです。
よろしくお願いします。
A
ポインタによるトラブルではなく、初期化されていない自動変数の値に悩まされているのだと思います。
最後のzの部分は0にはならず(何も値を設定していないので)、未知の値が表示されることになります。
値を代入していない自動変数(この場合は配列z)には全くでたらめな内容がセットされています。
とくにStudy Cで少しずつ改造しながら実行している場合は、前に実行したプログラムがセットした内容が残っていることがあります。
Q-70StudyCユーザからの質問
以下のプログラムをRUNさせたところ、画面にバグが出ました。
これは第2回実力試験の2-5のコード表を作る為に私が作成したプログラムです。
k = (j + 31) * i - (j + i);←の”- (j + i)”のところを追加した時にバグが出始めました。
その部分を消したところバグは消えました。
#include <stdio.h>
main()
{
int i,j,k;
printf(" 10進 16進 文字 10進 16進 文字 10進 16進 文字 \n");
printf("--------------------------------------------------\n");
for(j = 1; j < 33; j++){
for(i = 1; i < 4; i++){
k = (j + 31) * i - (j + i);
printf(" %3d 0x%x ",k,k);
putchar(k);
printf(" ");
}
printf(" \n");
}
}
A
上記のプログラムは、putchar()関数で0x1Eを表示しています。
0x1F(31)以下の文字コードには、特殊な働きがあるため表示が不正になります。
エスケープシーケンスもこの一種です(
ここを参照してください)。
Study Cでは、putchar(0x1E);を実行するとカーソル位置を左上に移動します。
Q-71StudyCユーザからの質問
こんばんわ またちょっと教えてください。
void mani(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p);
void pre(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p);
int main(void)
{
int a,b,s,d,m,n;
a=15;
b=3;
pre(a,b,&s,&d,&m,&n);
return 0;
}
void mani(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p)
{
*s_p=x+y;
*d_p=x-y;
*m_p=x*y;
*n_p=x/y;
}
void pre(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p)
{
mani(x,y,&s_p,&d_p,&m_p,&n_p);
printf("%d %d wa=%d sa=%d sho=%d seki=%d\n",x,y,s_p,d_p,m_p,n_p);
}
今勉強している問題集の例題をかえて上記のように作ってみました。
Study Cで実行するとwarningが出たけど結果は正解がでました。で Visual C++でコンパイルしたら、warningが出て結果は出てきませんでした。
どのように直したら、よいのでしょう。
関数を2つ作って(四則計算するのとプリントするの)、メインの中でポインタ変数を使って実行させてみたいのです。宜しくお願いします。
A
pre()内でのポインタの使用方法が間違っています。下記のように使用します。
void mani(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p);
void pre(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p);
int main(void)
{
int a,b,s,d,m,n;
a=15;
b=3;
pre(a,b,&s,&d,&m,&n);
return 0;
}
void mani(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p)
{
*s_p=x+y;
*d_p=x-y;
*m_p=x*y;
*n_p=x/y;
}
void pre(int x,int y,int *s_p,int *d_p,int *m_p,int *n_p)
{
mani(x,y,s_p,d_p,m_p,n_p);
printf("%d %d wa=%d sa=%d sho=%d seki=%d\n",x,y,*s_p,*d_p,*m_p,*n_p);
}
Q-72StudyCユーザからの質問
構造体の変数へのポインタを宣言するときに、それと同時に動的に確保したアドレスで初期化をしようとすると不都合が起きてしまいます。
#include <stdio.h>
#include <stdlib.h>
struct cell{
char name[20];
int age;
};
int main(void)
{
struct cell *p = (struct cell *)malloc(sizeof(struct cell));
if (p == NULL){
fprintf(stderr,"out of memory\n");
return(1);
}
printf("input name--->");
scanf("%s",p->name);
printf("input age---->");
scanf("%d",&(p->age));
printf("%s %d\n",p->name, p->age);
free(p);
return(0);
}
bcc、gcc、VC++で動作確認済みです。
この用法以外でも、動的に領域を確保、開放を行う(mallocやcalloc、free)、StudyCが
落ちてしまうことがあります(もちろん、bcc、gcc、VC++などの環境では動きますが・・・)。
あと、組み込み関数が少ない(qsort、besearch、systemなど)、組み込みのマクロの宣言が
少ない(RAND_MAX、EXIT_SUCCESS、EXIT_FAILUREなど)ので、異様に使いづらいです。
組み込み関数形式にせずに、各種ヘッダファイルごとに関数、マクロを分けて
機能を強化したほうが、他のCコンパイラとも競合が取れて使いやすくなると思うのですが。
実際、他のコンパイラ用に作成したCソースファイルをSTUDYCで動作させようと思っても、
ヘッダファイル、関数、マクロの関係で上手く動作せず、STUDYC用に書き直さないといけないので非常に不便です。
ステップ実行などの機能はデバッグに非常に有効に使えるのですが、このあたりの不都合が非常に惜しいと思います。
A
最初の構造体の初期化の問題は、Study Cのバグです。近日中に修正版をアップロードする予定です。
動的に領域を確保、開放を行う(mallocやcalloc、free)とStudyCが落ちる件は、試してみましたがそのような状況を再現できませんでした。
再現するプログラムを送っていただければ確認します。
その他の件:Study Cは勉強用なので入門書や初級のC言語解説書に載っているプログラムで多く使われるマクロ、関数などしか増強する予定はありません。
構造体の初期化を修正したVer1.09dをリリースしました。
P.S.
この投稿を行った人が作成したと思われるページを偶然見つけたのでコメントしておきます。
・マクロや組み込み関数は、大学が教材として採用するときに追加/仕様変更依頼があり、これには全て対応しました。
大学に、なぜもっと要望を出さなかったのか尋ねてみたらいかがですか。
・マクロや組み込み関数を追加するのは簡単な作業なので、上記の投稿の内容で具体的に上がっている項目は追加しようとも思っていたのですが、
このページを見てStudy Cを使っていない人の意見とわかったので今回のリリースでは取りやめることにしました。
・bccなどでもCとして使用すれば、stdlib.hをインクルードしなくてもmallocは使えますがC++と間違えていませんか?
・当該ページで、こちらからの回答を無断で引用していますが、その部分は削除してください。
Q-73StudyCユーザからの質問
Q72で質問した者です。
先日の質問に親切に答えていただいてありがとうございます。
今回の質問は、malloc、freeとは直接関係はないのですが、
変数のアドレス関係で問題が生じます。
以下のプログラムは、標準入力より文字(文字列)を入力していき、
入力した順にリストを作成し、'0'が入力された時点で入力を終了し、
次に入力された数字番目の要素をリストから削除するという、
線形リストの基礎の問題です。
動的にメモリを確保した後、構造体の各要素は、
文字変数は入力した文字、自己参照に用いるアドレスはNULLで
初期化しているので、特に問題はないと思われます。
このプログラムはbcc、gcc、VC++で動作確認済みです。
#include <stdio.h>
#include <stdlib.h>
typedef struct List {
struct List *next;
char c;
}cell_t;
/*----------------- prototype -----------------*/
int input_num(int *cell_num);
void remove_cell(int *cell_num);
void del_cell(void); /* all delete */
/*---------------------------------------------*/
cell_t *head;
int main(void)
{
int i, cell_num = 0; /*: number of the cell */
cell_t *now;
head = NULL;
if(input_num(&cell_num)){
printf("No data!!\n");
return(0);
}
remove_cell(&cell_num);
now = head;
/*-- print display --*/
for(i=1;now;i++){
printf("%c",now->c);
now = now->next;
if (i % 20 == 0) putchar('\n');
}
/*-------------------*/
del_cell();
return (0);
}
int input_num(int *cell_num)
{
char temp ;
cell_t *p, *now;
printf("input character\n");
while(1){
scanf("%c",&temp);
if (temp == '\n') continue;
if (temp == '0'){
if (*cell_num == 0) return 1; /* no data */
else
return 0;
}
if((p = (cell_t *)malloc(sizeof(cell_t)) ) == NULL){
fprintf(stderr,"Out of memory\n");
del_cell();
exit(1);
}
/*-- initialize --*/
p->next = NULL;
p->c = temp;
/*----------------*/
/*-- make list --*/
if (*cell_num == 0){
head = p;
now = head;
}
else{
now->next = p;
now = p;
}
/*---------------*/
(*cell_num)++;
}
}
void remove_cell(int *cell_num)
{
int i,remove_cell;
cell_t *now = head, *prev;
while(1){
printf("input remove number of cell--->");
scanf("%d",&remove_cell);
if (remove_cell <= *cell_num && remove_cell > 0) break;
else printf("max = \"%d\"\n",*cell_num);
}
if (remove_cell == 1) {/* remove cell is "head" */
now = head;
head = head->next;
}
else{
for(i=1; i<remove_cell-1; i++) now = now->next;
prev = now;
now = now->next;
/*-- remove --*/
if (now->next) prev->next = now->next;
else prev->next = NULL;
/*------------*/
}
free(now);
return;
}
void del_cell(void)
{
cell_t *now, *del;
now = head;
while(now){
del = now;
now = now->next;
free(del);
}
return;
}
A
これも、Q72と同じバグによる影響です。近日公開予定のバージョンで試してみたところ、問題なく動作しました。
現バージョンでは、自動変数で構造体へのポインタ変数に宣言部で初期化(非定数)を行うと不具合が発生します。
上記のプログラムでは、remove_cell()関数の「cell_t *now = head,」がこれに相当します。
この部分を
cell_t *now;
now = head;
とすれば、現バージョンでも動作します。
←修正済みなので、新バージョンをダウンロードしてください。
Q-74StudyCユーザからの質問
質問1:SET INCLUDE が実行できない。
SET INCLUDE=C:\StudyC\include を実行したところ、以下のエラーメッセージがでます。
ファイル’SET’(またはその構成ファイル)が見つかりません。パスおよびファイル名が正しいか、必要なライブラリがすべて利用可能かどうか、確認してください。
というメッセージがでますが、原因がわかりません。
StudyCのセットアップはデフォルトで行っています。
質問2:VC6への移植がうまくいきません。
C言語ゲームプログラミング 第2回講座のプログラムを実行したところ以下のエラーがでます。
なおgraph.hはVCのインクルードファイルフォルダへコピーして実行しました。
以下略
質問3:STUDYCの関数、たとえばgraph.h にはどのような関数が用意されていて、パラメータの設定をどのように行うかなどのマニュアルはありませんか。
A
質問1:Study Cを起動してコマンドラインでSET ...と実行しても問題ありませんでした。
また、autoexec.obtにSET ...と入れても問題ありませんでした。
上記の状況が発生した手順を教えてください。
質問2:ゲーム用グラフィック関数のVC用ライブラリは用意していないので、移植はできません。
将来ライブラリを提供する予定はありますが、具体的な予定はたっておりません。
質問3:blistコマンドで一覧を表示して、さらにblist gl_setpixelのようにすれば個々の関数の引数の並びだけは表示されます。
多くは、gl_の部分を除いた関数名と同じ関数が、Windowsに用意されているのでVCのヘルプなどを参照してください。
これも将来WEB上に解説ページを作成する予定ですが、具体的な予定はたっておりません。
Copyright(C) 1996-2003 ㈱オーキッド
コンピュータ関連のメニューページに戻る
お問い合わせ先