C言語何でも質問掲示板


アンケートにご協力下さい → >> アンケートフォーム <<

規約と使い方

 
   無題   
     ・[9004] バグ 
     ・[9009] toyo 
     ・[9012] Lbfuvab 
     ・[9016] Hermit 
     ・[9055] Lbfuvab 
   ポインタの宿題   
     ・[8989] バグ 
     ・[8990] バグ 
     ・[8992] なぎ 
     ・[8993] バグ 
     ・[8996] アヤコ 
     ・[9001] アヤコ 
     ・[9008] なぎ 
     ・[9028] アヤコ 
     ・[9031] アヤコ 
     ・[9040] 管理人 
   borlandC++画像の表示   
     ・[9018] 管理人 
   初歩的な質問ですTT   
     ・[8998] 管理人 
     ・[9005] 初心者 
   このプログラムの・・ ....   
     ・[8997] 管理人 
     ・[8999] C言語が苦手な人 
   セーブ・ロードの方法 ....   
     ・[8981] 管理人 
     ・[8982] Justy 
     ・[8994] 黒猫 
   関数の問題で疑問点+ ....   
     ・[8962] YuO 
     ・[8963] ひろろ軍曹 
     ・[8965] 徹夜 
     ・[8966] ひろろ軍曹 
     ・[8967] バグ 
     ・[8968] ひろろ軍曹 
     ・[8969] DRAGON 
     ・[8970] 徹夜 
     ・[8971] ひろろ軍曹 
     ・[8972] ひろろ軍曹 
     ・[8973] バグ 
     ・[8974] ひろろ軍曹 
     ・[8983] Justy 
     ・[8984] なぎ 
     ・[8985] YuO 
     ・[8991] なぎ 
   エラーがよくわかりま ....   
     ・[8988] Justy 
   2分探索木による探索 ....   
   strstrについて   
     ・[8849] box 
     ・[8851] なぎ 
     ・[8928] yossiy 
     ・[8941] なぎ 
     ・[8964] yossiy 
   意味不明な挙動(雑談ス ....   
     ・[8946] Justy 
     ・[8955] 管理人 
     ・[8958] 大工 
     ・[8959] 管理人 
     ・[8960] Justy 
     ・[8961] 大工 
   ファイルから文字列の ....   
     ・[8947] バグ 
     ・[8948] hana 
     ・[8949] バグ 
     ・[8950] バグ 
     ・[8951] box 
     ・[8952] hana 
   ○×ゲーム   
     ・[8932] box 
     ・[8937] 管理人 
     ・[8942] バグ 
   文字列と配列の問題で ....   
     ・[8935] がんも 
     ・[8940] toyo 
   位分け   
     ・[8893] box 
     ・[8895] 管理人 
     ・[8897] さっかん 
     ・[8898] 管理人 
     ・[8906] さっかん 
     ・[8907] バグ 
     ・[8908] バグ 
     ・[8909] Justy 
     ・[8910] 管理人 
     ・[8911] Justy 
     ・[8912] さっかん 
     ・[8913] さっかん 
     ・[8914] バグ 
     ・[8915] box 
     ・[8916] バグ 
     ・[8917] さっかん 
     ・[8918] バグ 
     ・[8919] バグ 
     ・[8921] Justy 
     ・[8922] バグ 
     ・[8924] さっかん 
     ・[8925] box 
     ・[8926] Justy 
     ・[8930] さっかん 
     ・[8931] 初心者A 
     ・[8934] YuO 
     ・[8936] さっかん 
     ・[8938] box 
     ・[8939] さっかん 
   16進数のデータをファ ....   
     ・[8899] 管理人 
     ・[8900] フリオ 
     ・[8905] 管理人 
     ・[8920] C言語はじめました 
     ・[8923] 管理人 
     ・[8927] フリオ 
   四則演算プログラムに ....   
     ・[7823] 管理人 
     ・[7826] Justy 
     ・[7827] 管理人 
     ・[7828] @とんぷぅ〜 
     ・[7829] @とんぷぅ〜 
     ・[7834] 管理人 
     ・[7835] box 
     ・[7836] 管理人 
     ・[7838] @とんぷぅ〜 
     ・[7842] box 
     ・[7843] 管理人 
     ・[7847] @とんぷぅ〜 
     ・[7849] Justy 
     ・[7852] @とんぷぅ〜 
     ・[7855] @とんぷぅ〜 
     ・[7856] box 
     ・[7857] @とんぷぅ〜 
     ・[7858] box 
     ・[7859] @とんぷぅ〜 
     ・[7860] box 
     ・[7862] @とんぷぅ〜 
     ・[7864] box 
     ・[7866] @とんぷぅ〜 
     ・[7869] box 
     ・[7874] @とんぷぅ〜 
     ・[7876] Justy 
     ・[7878] 管理人 
     ・[7880] @とんぷぅ〜 
     ・[7881] 管理人 
     ・[7886] @とんぷぅ〜 
     ・[7903] Justy 
     ・[7904] @とんぷぅ〜 
     ・[7905] @とんぷぅ〜 
     ・[7906] 管理人 
     ・[7907] 管理人 
     ・[7908] 管理人 
     ・[7909] 管理人 
     ・[7916] @とんぷぅ〜 
     ・[7921] Justy 
     ・[7922] @とんぷぅ〜 
     ・[7925] 管理人 
     ・[8014] @とんぷぅ〜 
     ・[8015] 管理人 
     ・[8016] Justy 
     ・[8017] 管理人 
     ・[8018] @とんぷぅ〜 
     ・[8020] 管理人 
     ・[8021] Justy 
     ・[8023] @とんぷぅ〜 
     ・[8027] 管理人 
     ・[8033] Justy 
     ・[8037] @とんぷぅ〜 
     ・[8038] 管理人 
     ・[8040] 管理人 
     ・[8041] 管理人 
     ・[8052] Justy 
     ・[8074] @とんぷぅ〜 
     ・[8075] 管理人 
     ・[8076] @とんぷぅ〜 
     ・[8077] 管理人 
     ・[8078] Justy 
     ・[8079] @とんぷぅ〜 
     ・[8080] Justy 
     ・[8081] @とんぷぅ〜 
     ・[8082] 管理人 
     ・[8083] @とんぷぅ〜 
     ・[8089] Justy 
     ・[8091] @とんぷぅ〜 
     ・[8092] Justy 
     ・[8093] @とんぷぅ〜 
     ・[8095] 管理人 
     ・[8099] @とんぷぅ〜 
     ・[8100] TT414 
     ・[8101] @とんぷぅ〜 
     ・[8102] 管理人 
     ・[8103] @とんぷぅ〜 
     ・[8104] 管理人 
     ・[8105] @とんぷぅ〜 
     ・[8106] 管理人 
     ・[8107] 管理人 
     ・[8108] 管理人 
     ・[8109] 管理人 
     ・[8110] @とんぷぅ〜 
     ・[8111] @とんぷぅ〜 
     ・[8114] 管理人 
     ・[8161] @とんぷぅ〜 
     ・[8162] 管理人 
     ・[8163] 管理人 
     ・[8164] @とんぷぅ〜 
     ・[8165] 管理人 
     ・[8166] @とんぷぅ〜 
     ・[8167] 管理人 
     ・[8168] Justy 
     ・[8169] @とんぷぅ〜 
     ・[8178] Justy 
     ・[8189] @とんぷぅ〜 
     ・[8190] Justy 
     ・[8201] @とんぷぅ〜 
     ・[8218] Justy 
     ・[8282] @とんぷぅ〜 
     ・[8290] Justy 
     ・[8293] @とんぷぅ〜 
     ・[8298] Justy 
     ・[8302] @とんぷぅ〜 
     ・[8304] Justy 
     ・[8312] @とんぷぅ〜 
     ・[8316] Justy 
     ・[8319] @とんぷぅ〜 
     ・[8322] バグ 
     ・[8324] @とんぷぅ〜 
     ・[8325] Justy 
     ・[8329] @とんぷぅ〜 
     ・[8337] Justy 
     ・[8338] @とんぷぅ〜 
     ・[8339] Justy 
     ・[8342] @とんぷぅ〜 
     ・[8343] Justy 
     ・[8344] @とんぷぅ〜 
     ・[8345] @とんぷぅ〜 
     ・[8346] Justy 
     ・[8348] @とんぷぅ〜 
     ・[8349] Justy 
     ・[8350] @とんぷぅ〜 
     ・[8351] @とんぷぅ〜 
     ・[8357] Justy 
     ・[8393] @とんぷぅ〜 
     ・[8394] Justy 
     ・[8396] @とんぷぅ〜 
     ・[8397] Justy 
     ・[8398] @とんぷぅ〜 
     ・[8399] Justy 
     ・[8400] @とんぷぅ〜 
     ・[8401] @とんぷぅ〜 
     ・[8402] Justy 
     ・[8403] @とんぷぅ〜 
     ・[8404] Justy 
     ・[8405] @とんぷぅ〜 
     ・[8406] Justy 
     ・[8407] @とんぷぅ〜 
     ・[8408] Justy 
     ・[8420] @とんぷぅ〜 
     ・[8423] Justy 
     ・[8429] @とんぷぅ〜 
     ・[8434] Justy 
     ・[8440] @とんぷぅ〜 
     ・[8441] Justy 
     ・[8443] Comp 
     ・[8445] @とんぷぅ〜 
     ・[8446] @とんぷぅ〜 
     ・[8447] @とんぷぅ〜 
     ・[8450] @とんぷぅ〜 
     ・[8467] @とんおうぅ〜 
     ・[8468] @とんぷぅ〜 
     ・[8481] Justy 
     ・[8488] @とんぷぅ〜 
     ・[8493] Justy 
     ・[8550] @とんぷぅ〜 
     ・[8551] Justy 
     ・[8554] keichan 
     ・[8557] @とんぷぅ〜 
     ・[8558] Justy 
     ・[8559] @とんぷぅ〜 
     ・[8561] Justy 
     ・[8608] @とんぷぅ〜 
     ・[8609] Justy 
     ・[8611] @とんぷぅ〜 
     ・[8613] Justy 
     ・[8615] @とんぷぅ〜 
     ・[8616] @とんぷぅ〜 
     ・[8630] Justy 
     ・[8642] @とんぷぅ〜 
     ・[8643] asd 
     ・[8644] @とんぷぅ〜 
     ・[8645] Justy 
     ・[8903] @とんぷぅ〜 
     ・[8904] 管理人 

Name: Lbfuvab  ..かけだし(2,193ポイント)   Date: 2007/07/01(日) 22:51   No:9003       
Title: 無題    
コンパイラはbcc55で開発環境としてBCC Developerを使っているのですが
以下のコードを打ち込んだときエラーが発生しました。(リンク時に)
Error: 外部シンボル '_main' が未解決(C:\BORLAND\BCC55\LIB\C0X32.OBJ が参照

コードは
#include <windows.h>


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
char szClassNme[] = "firstSDK";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst,LPSTR lpszCmdLine, int nCmdShow){
HWND hWnd;
MSG msg;
WNDCLASS myProg;
myProg.style = CS_HREDRAW | CS_VREDRAW;
myProg.lpfnWndProc=WndProc;
myProg.cbClsExtra =0;
myProg.cbWndExtra =0;
myProg.hInstance =hInstance;
myProg.hIcon =NULL;
myProg.hCursor =LoadCursor(NULL, IDC_ARROW);
myProg.hbrBackground =GetStockObject(WHITE_BRUSH);
myProg.lpszMenuName =NULL;
myProg.lpszClassName =szClassNme;
if (!RegisterClass(&myProg))
return FALSE;
hWnd = CreateWindow(szClassNme,
"はじめの一歩",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, msg, wParam, lParam));
}
return (0L);
}

どこが間違っているのか分かりません。
どうか教えてください


924ポイント を手に入れた。


Name: バグ  ..熟練のプログラマー(53,267ポイント)   Date: 2007/07/01(日) 23:15   No:9004     
Title: Re:無題    
おそらく、プロジェクトの設定が、WINDOWSアプリではなく、コンソールアプリになっているからではないでしょうか?

30ポイント を手に入れた。

Name: toyo  ..かけだし(2,171ポイント)   Date: 2007/07/02(月) 09:02   No:9009     
Title: Re:無題    
一般にC, C++のプログラムは main( ) 関数から始まりますよね。
Windowsもコンソールアプリはmain( )で始まります。
ところが画面にWindowとして表示されるいわゆるWindowsアプリはmain( )ではなくWinMain( )関数から始まります。
コンパイルの際にはコンソール用なのかWindows用なのかをコンパイラに指示しないといけません。
BCC Developerではメニューの「プロジェクト」->「プロジェクト設定」でコンソールアプリケーションかWindowsアプリケーションかを指定できます。


138ポイント を手に入れた。

Name: Lbfuvab  ..かけだし(2,243ポイント)   Date: 2007/07/02(月) 13:57   No:9012     
Title: Re:無題    
すいませんでした。
BCC Developerを一度消してダウンロードしなおしたので
デフォルトプロジェクトがコンソールに成ってました。(謝


50ポイント を手に入れた。

Name: Hermit  ..初心者(8,691ポイント)   Date: 2007/07/02(月) 18:28   No:9016     
Title: Re:無題    
ここも、http://www9.plala.or.jp/sgwr-t/ も、マルチポストは禁止のようです。
今後はそのあたりも気をつけましょう。


28ポイント を手に入れた。

Name: Lbfuvab  ..かけだし(2,254ポイント)   Date: 2007/07/03(火) 16:47   No:9055     
Title: Re:無題    
すいませんでした。


11ポイント を手に入れた。



Name: アヤコ  ..ぴよぴよ(173ポイント)   Date: 2007/06/29(金) 11:57   No:8986       
Title: ポインタの宿題    
はじめまして
学校でポインタの宿題が出ましたが、ポインタがまだ理解できず提出に間に合うか不安です。
どなたか説明つきで教えてください!
よろしくお願いします。

課題は、
「ソートプログラムにおいて、もとの配列を変更することなく、ソートした結果を出力するプログラムを作成せよ。(ポインタの配列を用いる)」




#include <stdio.h>
void swap(/*ここを作成*/)
{
/*ここを作成*/
}

void move(/*ここを作成*/)
{
/*ここを作成*/
}

#define NUM 10

int main(void)
{
int soten[NUM]={84,95,60,100,83,72,93,85,65,98};
int *pt[NUM];
int i,j;
for (i=0; i<NUM; i++){
/*ポインタの配列の初期値を代入*/
pt[i]=&soten[i];
}
/*初期状態を出力*/
printf("original: ");
for (i=0; i<NUM; i++){
printf("%d ", soten[i]);
}
printf("\n ");
for (i=0; i<NUM; i++){
printf("%d ", *pt[i]);
}
printf("\n");
/*ソートする*/
for(i=NUM-1;i>=0;i--){
for (j=0;j<i;j++){
move(&pt[j],&pt[j+1]);
}
}
/*ソート終了後の状態を出力*/
printf("after sort: ");
for(i=0;i<NUM;i++){
printf("%d ", soten[i]);
}
printf("\n ");
for(i=0;i<NUM;i++){
printf("%d ", *pt[i]);
}
printf("\n");
return 0;
}


173ポイント を手に入れた。


Name: バグ  ..熟練のプログラマー(53,106ポイント)   Date: 2007/06/29(金) 13:30   No:8989     
Title: Re:ポインタの宿題    
すみません、1つ確認なのですが…
ポインタを使わずに配列の中身をソートして、表示する事はできますか?
もし、それが可能ならば、そのプログラムを提示してみてください。


14ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(53,286ポイント)   Date: 2007/06/29(金) 13:41   No:8990     
Title: Re:ポインタの宿題    
move(&pt[j],&pt[j+1]);

この部分なのですが、出題者の意図がよく分からないです…。
ポインタの勉強だとしても、ポインタのポインタを渡す必要があるのか…?(^_^;)
ひょっとして、ワザと難しく(というか、ややこしく)してるのかもしれません(-_-)


2倍のポイントを手に入れた! 180ポイント を手に入れた。

Name: なぎ  ..プログラマー(25,688ポイント)   Date: 2007/06/29(金) 15:49   No:8992     
Title: Re:ポインタの宿題    
普通の配列のソートが、

1) soten[j] と soten[j + 1] の大小を比較する
2) 並びが反対なら、soten[j] と soten[j + 1] を入れ替える

という処理の流れですが、ポインタ経由でソートすることで、元の配列の位置は保持しようということですね。
でうので、普通のソートの上記の部分が、

1) *(pt[j]) と *(pt[j + 1]) を比較する
2) 並びが反対なら、pt[j] と pt[j + 1] を入れ替える

という流れになります。
入れ替えるものが、ポインタなので、入れ替え関数に渡すのは、ポインタのポインタである必要があります。

ということでしょう。
普通の配列のソートができていて、move() と swap() の引数の型がわかれば、普通の配列版を書き直せばいいのかなと思いますが。



298ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(53,237ポイント)   Date: 2007/06/29(金) 15:56   No:8993     
Title: Re:ポインタの宿題    
ああ、なるほど!!
ポインタの中身ではなく、ポインタそのものを交換させたいという意味でしたか…(^_^;)


49ポイント を落としてしまった。

Name: アヤコ  ..ぴよぴよ(190ポイント)   Date: 2007/07/01(日) 08:41   No:8996     
Title: Re:ポインタの宿題    
ありがとうございます。
がんばってみます。


17ポイント を手に入れた。

Name: アヤコ  ..ぴよぴよ(247ポイント)   Date: 2007/07/01(日) 22:17   No:9001     
Title: Re:ポインタの宿題    
今日、一日かけて考えましたが、ポインタ自体がまだ理解できずポインタのポインタまでたどり着けませんでした。
もう少しヒントをいただけないでしょうか?
よろしくお願いします。


57ポイント を手に入れた。

Name: なぎ  ..プログラマー(25,940ポイント)   Date: 2007/07/02(月) 08:51   No:9008     
Title: Re:ポインタの宿題    
ポインタが理解できていないのか、そもそも、ソートのプログラムがわからないのかというところなのですが。

バグさんがお書きのように、「ポインタを使わない場合のソートのプログラムを示してみてください」
というところがスタートになります。
その上で、

1) soten[j] と soten[j + 1] の大小を比較する
2) 並びが反対なら、soten[j] と soten[j + 1] を入れ替える

という部分があれば、

1) *(pt[j]) と *(pt[j + 1]) を比較する
2) 並びが反対なら、pt[j] と pt[j + 1] を入れ替える

にかきなおしてみます。
というところなのですが。

※ただ、変数の型の問題があるので、このあと、もうひとつかふたつステップが必要になるかも知れませんが。


2倍のポイントを手に入れた! 252ポイント を手に入れた。

Name: アヤコ  ..ぴよぴよ(455ポイント)   Date: 2007/07/02(月) 23:43   No:9028     
Title: Re:ポインタの宿題    
ソートについて調べてみました。

今日わかった事は、バブルソートを使っているのではないかということです。

サブ関数のひとつはこんなような感じでしょうか?
引数とかはわかりません。

void move( ){
int tmp,j;
if(pt[j]>pt[j+1){
tmp=pt[j];
pt[j]=pt[j+1];
pt[j+1]=tmp;
}
}


また、main関数の中にswap()の関数呼び出しが無いのもわかりません。
アドバイスよろしくお願いします!


208ポイント を手に入れた。

Name: アヤコ  ..ぴよぴよ(687ポイント)   Date: 2007/07/03(火) 00:13   No:9031     
Title: Re:ポインタの宿題    
swap と ソートが別になっている例をみつけました。
ただ、課題のmain関数にswap()の呼び出しがありませんでした。
move()関数の中にswap()関数の呼び出しを入れるのでしょうか?



void bubble_sort(int *ptr, int n)
{
int i, j;

for(i=0; i<n-1; i++){
for(j=n-1; j>i; j--){
if(*(ptr+j-1) > *(ptr+j)){
swap((ptr+j-1), (ptr+j));
}
}
}
}

void swap(int *ptr1, int *ptr2)
{
int w;

w = *ptr1;
*ptr1 = *ptr2;
*ptr2 = w;
}


232ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(380,616ポイント)   Date: 2007/07/03(火) 02:30   No:9040     
Title: Re:ポインタの宿題    
>main関数の中にswap()の関数呼び出しが無いのもわかりません。

ということですが、コードを見て、そのコードの意味を理解すればそのような疑問も消えるはずです。
main関数で呼ぶのではないかという疑問をお持ちになるのはちょっとよくわかりませんけど、以下のようなプログラムが上記に出てきますよね。

tmp=pt[j];
pt[j]=pt[j+1];
pt[j+1]=tmp;

ここの処理一体何をやっています?
そしてswap関数内では何をやっています?
結局同じことをやっていますよね。


swap関数というのはその名前からわかるとおり、引数にした2つの数をいれかえる関数です。
ptr1とptr2を受け取っていますね。いったんwに変数の中身を保存していれかえています。
bubble_sort内で数値の比較をしたとき、値を交換すべきときになったらこの関数を呼び出して交換しているのです。

swap関数が無いのは、関数をよばなくてもそれと同じことをしているからです。
処理をわけたのが後に投稿されたものです。

上記プログラムではbubble_sortがmoveにあたるわけです。
swap関数はmoveから呼ぶならswap関数をmoveより上に書いてくださいね。
もし下に書くなら宣言が必要です。

コードの意味を一つ一つおって何をしているのか理解しなければプログラムは組めませんから1行ずつ何をしているのか意味を理解するようにしてみてください。


255ポイント を手に入れた。



Name: のき  ..ぴよぴよ(502ポイント)   Date: 2007/07/02(月) 18:47   No:9017       
Title: borlandC++画像の表示    
#include "DxLib.h"
char st1[]="画像の保存場所が違うか、ファイル名が違うため、表示できません。";
char st2[]="正常に認識されています。";

int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode( TRUE ) ;
if( DxLib_Init() == -1 ) return -1;


if(LoadGraphScreen( 0 , 0 , "char.PNG" , TRUE ) == -1)
DrawString(50,220,st1,GetColor(255,255,255));
else
DrawString(50,220,st2,GetColor(255,255,255));


WaitKey() ;
DxLib_End() ;
return 0 ;
}
ゲームの館の説明どおりに画像の表示をしようと試してみたのですが画像の保存場所が違うかファイル名が違うため表示されませんとなります。
保存場所もファイル名も確認したのですがあっているはずなのですが、それ以外の問題としてなにがありえるのでしょうか?
状況が伝わりにくい投稿かもしれませんが、はじめたばかりなのでよくわからないので、やさしくおねがいしますm(__)m


502ポイント を手に入れた。


Name: 管理人 [URL]  ..伝説のハッカー(379,961ポイント)   Date: 2007/07/02(月) 19:16   No:9018     
Title: Re:borlandC++画像の表示    
char.pngの位置をDebugフォルダの中か、Debugフォルダの一つ上か、どちらか2種類の状況でやってみてください。
書いてあるフォルダの位置が違うのかもしれません(_ _|||)


76ポイント を手に入れた。



Name: 初心者A  ..ぴよぴよ(394ポイント)   Date: 2007/07/01(日) 00:53   No:8995       
Title: 初歩的な質問ですTT    
初めまして初心者です・・・
ゲームプログラミングの館からDXのライブラリダウンロードでVisualC++の方をダウンロードしたのですが
手順通り【サンプルプログラム実行用】フォルダの【DxLib.sln】を開いたのですけど
[Visual Studio変換ウィザードへようこそ]
現在開いているソリューションまたはプロジェクトは旧バージョンのVisual Studioで作成されたのもです。
このバージョンで使用される形式に変換してください。ソリューションまたはソリューションのプロジェクト
が1つでも変換された後は、旧バージョンで編集、ビルド、または実行できません。以下略

と、いう感じのものが出て進めていくと一応はF5を押してコンパイルまで出来るのですが【はい】を押すと
ビルドエラーが出て最後に成功したビルドを実行しますか?【はい】をすると
指定したファイルは見つかりませんでした。と出ます。
ここから進めません・・・
こんな初歩的な質問をして恥ずかしく申し訳ないのですが教えてもらえましたら助かります
Microsoft Visual C++ 2005 Express Edition-日本語 をインストールしました。


348ポイント を手に入れた。


Name: 管理人 [URL]  ..伝説のハッカー(379,885ポイント)   Date: 2007/07/01(日) 12:49   No:8998     
Title: Re:初歩的な質問ですTT    
こんにちは。
フリーのコンパイラを使ったときは別の設定が必要なんです。

http://homepage2.nifty.com/natupaji/DxLib/dxuse_vc2005express.html

ここを参考にしてみてください。


62ポイント を手に入れた。

Name: 初心者  ..初心者(5,577ポイント)   Date: 2007/07/02(月) 00:03   No:9005 解決!     
Title: Re:初歩的な質問ですTT    
出来ました!本当にありがとうございます^^


16ポイント を手に入れた。



Name: C言語が苦手な人  ..ぴよぴよ(846ポイント)   Date: 2007/06/27(水) 21:29   No:8953       
Title: このプログラムの・・・    

#include <stdio.h>
main(void) {

int n, amari, x, i, m, y, h;
int a[100];

printf("N ha?");
scanf("%d", &n);

x = 1;
a[x] = amari;
amari = x % n; // amari 余りを計算
printf("%d.", x / n); // x÷n 商を表示

for(i = 0; i <= 1000; i++) {

for(y = i;y >= 0;y--){
if(a[y] == amari){
h = 1;
break;
}
}
if(amari==0){
printf("%d", x/n);
break;
}
else if(h == 1){
break;
}
else{
printf("%d", x/n);
}

x = amari * 10; // x←amari×10
amari = x % n; // amari 余りを計算

}
return 0;
}

これは、数値を入力してもらい、その値で1を割り逆数を計算して、割り切れるか循環するかを判断し、割り切れたら結果を表示し、循環なら循環節を表示させるプログラムを作っているのですが、計算してみると割り切れるほうはちゃんと計算されるのですが、循環のほうが循環節の途中で切れたり、余分に表示されたりします。いろいろいじってみたのですがわからないので、どなたかわかる方回答よろしくお願い致します。
※プログラムのつくりなどでわからない点などありましたら出来る限りお答えしますのでよろしくお願いします。


575ポイント を手に入れた。


Name: 管理人 [URL]  ..伝説のハッカー(379,823ポイント)   Date: 2007/07/01(日) 12:48   No:8997     
Title: Re:このプログラムの・・・    
回答が遅くなってしまってすみません(_ _|||)

循環小数の表示方法がわからないのでしょうか?
数学には強くないのではっきりとはいえないですけど、恐らく循環小数の循環する桁は割るほうの桁数に比例刷るんじゃないかと思います。
例えば一桁で割るなら、循環小数で、次に同じ数字が来たらそこまでが循環小数ですよね。
例えば
1割る7のとき、割るほうは一桁です。

0.142857142857142857....

このように、1/10の位が1であり、次に1が出てきたところまでが循環小数です。
しかし1/6のように

0.1666666...

という場合もあり、1/100の位から循環する事もあるので注意が必要です。
この位も割るほうの桁数に比例するように思います。

一桁の数字で割っているということは、最大でも10桁の循環小数にしかならないはずです。
この要領で、

1/ 253の場合

0.003952569169960474308300395256916996047430830039525691699604743083......


答えはこうなります。循環小数の中に同じ数字が何度か出てきますけど、そこまでが循環小数ではないですよね。
今回割る数字が多かったので、循環小数も桁が多くなったのだと思います。

各桁は文字列として格納しておけば比較がしやすいと思います。


0. 1 4 2 8 5 7 1 4 2 8
↑ ↑
同じ数字が出てきたところを発見し、そこから一つずつずらしてパターンを比較してみてはいかがでしょうか。

0. 1 4 2 8 5 7 1 4 2 8
↑ ↑
0. 1 4 2 8 5 7 1 4 2 8
 ↑ ↑
0. 1 4 2 8 5 7 1 4 2 8
  ↑ ↑

割る桁数に比例した桁まで調査したら終了すると良いと思います。

 


688ポイント を手に入れた。

Name: C言語が苦手な人  ..ぴよぴよ(874ポイント)   Date: 2007/07/01(日) 16:15   No:8999     
Title: Re:このプログラムの・・・    
回答ありがとうございます。
いろいろ試してるところなので参考にさせていただきます。
またわからないことがありましたら質問させていただくので回答よろしくお願いします。


28ポイント を手に入れた。



Name: 黒猫  ..かけだし(1,172ポイント)   Date: 2007/06/28(木) 18:52   No:8975       
Title: セーブ・ロードの方法・・    
セーブ・ロードの方法がまったくわかりません。
セーブ・ロードの概念みたいなものを
どなたか教えていただけませんか?







26ポイント を手に入れた。


Name: 管理人 [URL]  ..伝説のハッカー(379,135ポイント)   Date: 2007/06/29(金) 01:08   No:8981     
Title: Re:セーブ・ロードの方法・・    
何のデータをセーブロードするかによると思いますけど、もっとも簡単な方法はテキスト形式でファイル出力、読み込みする方法ではないでしょうか?
例えばRPGのセーブ・ロードだとして書きます。

体力、レベル、現在のエリア番号、現在の座標x、現在の座標y

こんな風にデータの順番を仕様として決めておきます。そして例えば
現在体力が230,レベルが13,エリア番号が3,x=10,y=30だとすると

230,13,3,10,30

こんな風にファイル出力すればいいですよね。
ファイルについてはfopen関数を利用するとよいでしょう。

http://www9.plala.or.jp/sgwr-t/c/sec17.html

ファイルに出力したら、今度は読み込みです。
fgetsなどで、

230,13,3,10,30

のデータを読み込んだら、それぞれの値をゲームのデータとして使ってやればいいわけです。
特にゲームプログラミングに限った業ではなく、普通にCの標準関数を利用して出来ると思いますよ。


255ポイント を手に入れた。

Name: Justy  ..ハッカー(130,744ポイント)   Date: 2007/06/29(金) 02:24   No:8982     
Title: Re:セーブ・ロードの方法・・    
>セーブ・ロードの方法がまったくわかりません
 プログラミング用語としてはシリアライズ・デシリアライズと言いますが、
この手の話は結構奥が深いです。

 特にどこまで考慮するのか、によって実装方法や難易度が変わってきます。
 例えば、テキスト形式にするのかバイナリ形式にするのか、
異なるプラットフォームでも読めるようにするのか、
バージョン互換をどこまでとるのか、とか。

 そんな事情もあって、いろんな人たちがいろんな方法を考案しています。


 で、基本的にシリアライズはテキスト形式かバイナリ形式かのどちらかになります。
 それぞれの利点・欠点は以下の通りです。

・ テキストの場合
 テキストエディタで中身を見られる。しかも内容を理解しやすい。
 異なるプラットフォームでも読みやすい。
 データを解釈するのに(文字列から数値への変換などで)若干時間がかかる
 データの改ざんが容易である。

・ バイナリ形式の場合
 中身を見るのにバイナリエディタが必要。
 当然データの改ざんするにもバイナリエディタが必要。
 (普通のバイナリエディタでは 16進数表示なので)intなどの数値はそれなりに判るが、
float/double型はぱっと見てもそれが一体幾つなのか判りづらい。
 異なるプラットフォームでは(エンディアンなどの問題で)そのままでは
正しく読み込めない可能性がある。
 比較的高速に読める。


 状況や工夫次第でそれぞれの利点・欠点は解消・緩和・消失したりするので
必ずしも上の通りにはならないのですが、概ねそんな感じです。


 簡単な例として既に構造体を理解されているようでしたら、バイナリ形式でばっさりと
ファイルに保存してしまうのが簡単で、構造体のメンバが増減しても
(古いデータを読もうとさえしなければ)何もする必要はありません。


#include <stdio.h>

#include <string.h>

// 対象のデータ
typedef struct Data
{
int year;
int month;
int day;
float pi;
char name[0x10];
} Data;

// 書き込み
static int save_data(const Data *data)
{
// 書き込み用バイナリファイルとして開く
FILE *fp;
if((fp = fopen("serialize.dat", "wb")) == NULL)
return 0;

// 一気に書き込む
fwrite((const void *)data, sizeof(Data), 1, fp);

fclose(fp);
return 1;
}

// 読み込み
static int load_data(Data *data)
{
// 読み込み用バイナリファイルとして開く
FILE *fp;
if((fp = fopen("serialize.dat", "rb")) == NULL)
return 0;

// dataの中身を空(0)にしておく
memset((void *)data, 0, sizeof(Data));

// 一気に読み込む
fread((void *)data, sizeof(Data), 1, fp);

fclose(fp);
return 1;
}

// data1の中身をファイルに書き出し、
// そのファイルから data2に読み込み
int main(void)
{
static const Data data1 = { 2007, 6, 29, 3.14159f, "test"};
Data data2;

// data1をファイルに書き出す
if(save_data(&data1))
{
// data2にファイルから読み出す
if(load_data(&data2))
{
// 双方の表示してみる
printf("data1 = %d/%d/%d (%f) %s\n",
data1.year, data1.month, data1.day,
data1.pi, data1.name);
printf("data2 = %d/%d/%d (%f) %s\n",
data2.year, data2.month, data2.day,
data2.pi, data2.name);
}
}
return 0;
}


1,083ポイント を手に入れた。

Name: 黒猫  ..かけだし(1,175ポイント)   Date: 2007/06/29(金) 21:27   No:8994     
Title: Re:セーブ・ロードの方法・・    
なるほど・・・。

つまりファイルを出力がセーブの役割をしていて、
出力したファイルを読み込むことがロードの役割をしているのですね!

いままで構造体の使いどころを理解していなかったので(というか使ったことあったっけなぁ・・w)
構造体をより理解できるようにしたいと思います。




3ポイント を手に入れた。



Name: 徹夜  ..かけだし(1,668ポイント)   Date: 2007/06/28(木) 00:52   No:8957       
Title: 関数の問題で疑問点+分からない演習課題    
まず 画面に「こんにちは。」と表示して改行を行う関数
void hello(void){/*・・・・*/}を作成せよ。という問題がまったく分からないです。



次に二乗値を返すプログラムで、入力する(int main)の部分はいいのですが
int sqr(int x)
{
return(x*x);
}
ここまでは教科書で与えられています。
演習問題
int型整数の三乗値を返す関数
int cube(int x){/*・・・*/}を作成せよ。
という問題を
int cube(int x)
{
return(x*x*x);
}
と持ってきました。
合っているのか分からない前にsqrとcubeの違いが分からないです。

もう1つの演習で
int型の整数の4乗値を返す関数
int pow4(int x){/*・・・*/}を作成せよ
ただし関数sqrを利用すること。
という問題で
int sqr(int x)
{
return(x*x*x*x);
}
こう持ってきましたが
int pow4(int x)を持ってきていないから違うと思うし、演習2題ともやっていることが単純すぎるので違うと思うのですが、先が見えてきません。
すべてint xの部分はscanfで持ってきます。(int main )の中で。


これらすべての問題でライブラリ関数は使用禁止とされています。使用していいのは<stdio.h>


聞きたいことが分かりにくいと思うのですがお願いします。



512ポイント を手に入れた。


Name: YuO  ..初心者(8,571ポイント)   Date: 2007/06/28(木) 03:15   No:8962     
Title: Re:関数の問題で疑問点+分からない演習課題    
根本的に関数がわかっていないのでしょうか。


> まず 画面に「こんにちは。」と表示して改行を行う関数
> void hello(void){/*・・・・*/}を作成せよ。という問題がまったく分からないです。

分割してみます。
・関数がどうこうを無視して「こんにちは。」と表示するプログラムを書ける
・そのプログラムに何もしない関数helloを追加することができる
・そのプログラムが何もしない関数helloを呼び出すようにすることができる
・関数helloが「こんにちは。」を表示するように変更することができる
あなたはどこまでできますか?


> 合っているのか分からない前にsqrとcubeの違いが分からないです。

見てわかるとおり,sqrはx * xを計算し,cubeはx * x * xを計算します。
というか自分で書いておいて違いがわからないのはなぜ?


> int pow4(int x)を持ってきていないから違うと思うし、演習2題ともやっていることが単純すぎるので違うと思うのですが、先が見えてきません。

xの4乗は(xの2乗)の2乗であるという数学的な部分はわかっていますか?
これがわかれば,sqrを使って書くのは難しくないと思いますが……。


2倍のポイントを手に入れた! 202ポイント を手に入れた。

Name: ひろろ軍曹  ..入門者(4,088ポイント)   Date: 2007/06/28(木) 10:54   No:8963     
Title: Re:関数の問題で疑問点+分からない演習課題    
まだまだ自分も突っ込めるLvじゃないと思いますが、ちょっと突っ込みを
突っ込みに突っ込みをしてくれる方は大募集していますw

> まず 画面に「こんにちは。」と表示して改行を行う関数
> void hello(void){/*・・・・*/}を作成せよ。という問題がまったく分からないです。

これ以外に難しく見えて簡単でしたw自分もまだC初めて1ヶ月ぐらいですけどググるとよく出てきます
C言語 自作関数  などで検索すると1ページ目に結構あります。

プログラムは上から順番に読み込んでいくということを頭にやってみるといいかも知れません。
また全てはmain関数が始まりであり終わりであると言うことも忘れずに。

関数を作るって言う響きが結構難しく感じますがYuOさんが段階わけしてくださったようにできるか確かめると
どこまでわかっててどこまでわからないかがわかると思います。
(自分もわからないところだらけなんですがねw)

> 合っているのか分からない前にsqrとcubeの違いが分からないです。

YuOさんが仰られている通り2乗3乗でしょう

sqrはスクウェア square
cubeはキュービックもしくはキューブ cubic cube
だと思います

>int pow4(int x){/*・・・*/}を作成せよ
>ただし関数sqrを利用すること。
ヒントはreturn のところにあるような
(数学的に表現してます)
(x*x*x*x) = (x^2) * (x^2)      *x^○はxの○乗の意

コレで(sqr*sqr)で出来ると思います。

まだ初心者の域を脱してない自分が偉そうに言うのもアレなんで「ちゃんとした説明などが出来る」他の方にお任せします
そもそもここに書くなという声があがりそうだorz


417ポイント を手に入れた。

Name: 徹夜  ..かけだし(1,757ポイント)   Date: 2007/06/28(木) 14:13   No:8965     
Title: Re:関数の問題で疑問点+分からない演習課題    
YuO様
そのプログラムが何もしない関数helloを呼び出すようにすることができる
・関数helloが「こんにちは。」を表示するように変更することができる
ここから分からないです。

YuO様、ひろろ軍曹様
下の関数の部分は理解できました。ありがとうございます。


89ポイント を手に入れた。

Name: ひろろ軍曹  ..入門者(4,450ポイント)   Date: 2007/06/28(木) 14:35   No:8966     
Title: Re:関数の問題で疑問点+分からない演習課題    
あー、自分も良くわからなくなってきた('A`) 日本語を勉強しないと・・・orz

>・関数がどうこうを無視して「こんにちは。」と表示するプログラムを書ける
#include <stdio.h>
int main(void)
{
  printf("こんちわ\n");
  return 0;
}

>・そのプログラムに何もしない関数helloを追加することができる
#include <stdio.h>
void hello(void)
{
  return 0;
}

int main(void)
{
  printf("こんちわ\n");
  return 0;
}

>・そのプログラムが何もしない関数helloを呼び出すようにすることができる
#include <stdio.h>
void hello(void)
{
  return 0;
}

int main(void)
{
  hello();
}

>・関数helloが「こんにちは。」を表示するように変更することができる
#include <stdio.h>
void hello(void)
{
  //「こんにちは。」を表示する
  return 0;
}

int main(void)
{
  hello();
}

ってことだと思います

プロトタイプ宣言にするにしろmain関数を後に書くにしろ
>・関数helloが「こんにちは。」を表示するように変更することができる
というのを

・さっき呼び出した何もしない関数helloで「こんにちは」と表示させるプログラムに変更することができる
と自分は勝手に変換してました(ぁ

多分あってるとは思いますが戻り値・引数のあたりが自分は微妙なのでなんともorz

こんなLvで質問に答えていいのやら・・・自分の勉強も兼ねて答えてみたのですがマズそうだったら削除お願いしますorz


362ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(52,906ポイント)   Date: 2007/06/28(木) 15:39   No:8967     
Title: Re:関数の問題で疑問点+分からない演習課題    
横レスですが…

void hello(void)
{
  //「こんにちは。」を表示する
  return 0;
}

void型の関数で、戻り値を設定するのはマズイのではないでしょうか?


67ポイント を手に入れた。

Name: ひろろ軍曹  ..入門者(4,489ポイント)   Date: 2007/06/28(木) 15:43   No:8968     
Title: Re:関数の問題で疑問点+分からない演習課題    
( Д)゜ ゜

return 0;じゃないです

return;ですorz

指摘ありがとうございます


39ポイント を手に入れた。

Name: DRAGON  ..ぴよぴよ(202ポイント)   Date: 2007/06/28(木) 15:55   No:8969     
Title: Re:関数の問題で疑問点+分からない演習課題    
同じく横レスすみまそ・・


void hello(void)
{
  //「こんにちは。」を表示する
  return 0;
}


私は、voidの場合はreturnはつけませんなぁ。

この問題、もうほとんど答えができてるような気がしますが・・


124ポイント を手に入れた。

Name: 徹夜  ..かけだし(1,891ポイント)   Date: 2007/06/28(木) 16:55   No:8970     
Title: Re:関数の問題で疑問点+分からない演習課題    
最初の下の問題も解決できていませんでした。
こんな感じなのかなと作ってみましたがエラーがかかってしまいます

#include<stdio.h>
int sqr(int x)
{
return(x*x);
}
int pow4(int x)
{
return(sqr*sqr);
}


int main()
{
int a;
printf("整数を入力してください\n");
printf("整数:");scanf("%d",&a);
printf("入力された値の4乗は%dです",pow4(a));
return(0);
}

逆にvoid hello(void)の方はプログラムができました。


134ポイント を手に入れた。

Name: ひろろ軍曹  ..入門者(4,635ポイント)   Date: 2007/06/28(木) 16:55   No:8971     
Title: Re:関数の問題で疑問点+分からない演習課題    
ん〜厳密にはどうなんでしょうかねぇ・・・・
自分はvoid型の関数にはEOF(エンドオブファンクション)の意味でreturn;をつけてますが・・・

引数、返り値がないvoid型なのでreturnだけにしてつけてますが付いてても付いてなくても一緒なのかしら
それともreturn;自体がマズいのでしょうかねぇ・・・

ちょっと調べてみます(・w・)ノ


146ポイント を手に入れた。

Name: ひろろ軍曹  ..入門者(4,717ポイント)   Date: 2007/06/28(木) 17:07   No:8972     
Title: Re:関数の問題で疑問点+分からない演習課題    

#include<stdio.h>

int pow4(int x)
{
int sqr = x*x;
return (sqr*sqr);
}


int main(void)
{
int a;
printf("整数を入力してください\n");
printf("整数:");
scanf("%d",&a);
printf("入力された値の4乗は%dです",pow4(a));
return 0;
}


これでできましたがどうなんだろうか。。。ちょっと自信ないですわ

return (sqr*sqr);
これがポインタの扱いされます
sqrが何をあらわしているか定義されてない為だと思われます

このままだと整数以外のアルファベットや記号入力されたときにその対応しているアスキーコードの数で4乗されてしまうような


82ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(53,092ポイント)   Date: 2007/06/28(木) 17:15   No:8973     
Title: Re:関数の問題で疑問点+分からない演習課題    
>>徹夜さん
どのようなエラーかも書くと答える側からしても答えやすいと思いますよ(^-^)



int pow4(int x)
{
return (sqr * sqr);
}



この部分、引数が指定されずにsqr関数を呼び出しているのが原因だと思います。

>>ひろろ軍曹さん
出力される答えは合っていると思いますが…

>int型の整数の4乗値を返す関数
>int pow4(int x){/*・・・*/}を作成せよ
>ただし関数sqrを利用すること。

問題文のこの箇所を満たせていないですね…惜しいです(^_^;)


186ポイント を手に入れた。

Name: ひろろ軍曹  ..初心者(5,024ポイント)   Date: 2007/06/28(木) 17:37   No:8974     
Title: Re:関数の問題で疑問点+分からない演習課題    
Σ(゜Д゜)
とんでもない前提条件を見落としてたorz

#include<stdio.h>

int sqr(int x)
{
return(x*x);
}

int pow4(int x)
{

return (ここにある答えが入ります); return( sqr(x) * sqr(x) );
}


int main(void)
{
int a;
printf("整数を入力してください\n");
printf("整数:");
scanf("%d",&a);
printf("入力された値の4乗は%dです",pow4(a));
return 0;
}

これでいかがなもんでしょうか・・ってオレがやってどうするorz
なので問題の部分は削除しましたw


*void型はreturn;でも問題ないとどっかのサイトに書いてありましたorz


307ポイント を手に入れた。

Name: Justy  ..ハッカー(131,215ポイント)   Date: 2007/06/29(金) 02:42   No:8983     
Title: Re:関数の問題で疑問点+分からない演習課題    
 横レスですが。

void型はreturn;でも問題ないとどっかのサイトに書いてありましたorz
 そのサイトに書かれている通り、戻り値が voidなら関数の最後に "return;"が
有っても無くても同じです。


 ちなみに私もつけない方です。結果が同じなら書かない方が楽なので。

 で、他はどうかなぁ、とちょっといくつか手持ちのソースコードで
戻り値が voidの時 returnをつけているかどうか、
それぞれ1,2ファイルずつチョイスして調べてみました。

 MSVC7.1 crt・・・なし
 BCC5.5.1 のStdLib・・・なし
 dmalloc・・・なし
 COLLADA・・・なし
 irrlicht・・・なし
 DxLib・・・なし 
 DirectX9.0cのサンプル・・・なし
 zlib・・・なし
 unrar・・・なし
 ICU・・・なし
 xerces・・・ほとんどなし(1つだけあった)
 tinyxml・・・なし
 Adobe Acrobat SDKのサンプル・・・なし
 Adobe Photoshop SDK 6.0のサンプル・・・なし
 Camellia・・・有ったり無かったり
 libvorbis・・・なし
 DVDコンバータ・・・なし
 Quake3・・・なし
 ToHeart2(PC)・・・なし

 う〜ん、圧倒的になしが多いようですね。
 何かの慣習なんでしょうかね。


471ポイント を手に入れた。

Name: なぎ  ..プログラマー(25,233ポイント)   Date: 2007/06/29(金) 08:47   No:8984     
Title: Re:関数の問題で疑問点+分からない演習課題    
return は、ニュアンスとしては、

・関数の途中から強制的に抜ける(これは、一般的な意味では、良くない設計のと見なされる)
・読み出し元に値を返す

という用途に使うので、返値が void の関数の場合、return は無いことが多いですね。


98ポイント を手に入れた。

Name: YuO  ..初心者(8,639ポイント)   Date: 2007/06/29(金) 11:15   No:8985     
Title: Re:関数の問題で疑問点+分からない演習課題    
> ・関数の途中から強制的に抜ける(これは、一般的な意味では、良くない設計のと見なされる)

えーっと,なぜ「一般的な意味では、良くない設計と見なされる」のでしょうか。
処理が終了した時点で関数から抜けるのは当然だと思いますが。
# ガード節をreturnしなかったら,ネストが深くてやってられなくなる。


68ポイント を手に入れた。

Name: なぎ  ..プログラマー(25,390ポイント)   Date: 2007/06/29(金) 15:37   No:8991     
Title: Re:関数の問題で疑問点+分からない演習課題    
>> ・関数の途中から強制的に抜ける(これは、一般的な意味では、良くない設計のと見なされる)
> えーっと,なぜ「一般的な意味では、良くない設計と見なされる」のでしょうか。

「一般的な意味では」というのは、「そうなっていたら、処理の流れを検討せずに何となく書いたという可能性がある」という意味です。
ですから、うまく設計した上で、途中で抜けるのがベストという判断があれば、「一般的な意味では」に相当しません。


ちょうど、「一般的な意味では、goto は良くない設計の兆候である」というのと同じです。
これも、goto を回避するあまり、かえってわかりにくくなるのは本末転倒ですから。

これに限らず、「一般的には」という前置きは、「当てはまらない例は山ほどある」ということですから。


157ポイント を手に入れた。



Name: MONO  ..ぴよぴよ(55ポイント)   Date: 2007/06/29(金) 11:59   No:8987       
Title: エラーがよくわかりません・・・    
c(4) : error C2449: '{' を見つけました (関数のヘッダーがないかもしれません。

c(9) : error C2059: 構文エラー : '}'

このようなエラーはどうすればいいのですか?
できれば早めに返事を・・・


55ポイント を手に入れた。


Name: Justy  ..ハッカー(131,353ポイント)   Date: 2007/06/29(金) 13:15   No:8988     
Title: Re:エラーがよくわかりません・・・    
 ソースを全部出してもらわないと正確な判断はできませんが、適当に推測すると
4行目の関数を書いたときに

 void function(void);

{
....
}


 のように余計な ;をつけていませんか?


138ポイント を手に入れた。



Name: マサキ  ..かけだし(1,777ポイント)   Date: 2007/06/28(木) 21:20   No:8977       
Title: 2分探索木による探索 2    
ファイルを二つ同時に添付できなかったので、こちらにプログラム中で開くテキストファイルを添付しておきます。

26ポイント を手に入れた。




Name: yossiy  ..入門者(2,852ポイント)   Date: 2007/06/23(土) 02:10   No:8847       
Title: strstrについて    
strstrについての課題です。
strstr関数について調べてはみたのですが、数を数えるのをどうやって作ればよいか見当もつきません。
説明もお願いします。



次のプログラムの英文の文章の中に冠詞の[the]の数をstrstr関数を使って数えるプログラムを作成する。
thenなどは数えないようにする。



#include <stdio.h>
#include <string.h>
int main(void)
{
int i,len;
char *found;
char a[]="Chiba University was founded in 1949, unifying several regional former national colleges and schools such as Chiba Medical College and Chiba Normal School. Its fundamental mission since then has been, as encapsulated by the inscription on the University Bell, ad altiora semper (always toward the higher), to equip students with the ability to make mature and informed judgments while nurturing and guiding their creativity. Pursuing these goals of excellence has resulted in Chiba University becoming one of the leading academic research centers of Japan.";

len = strlen(a);
for(i=0;i<len;i++){
found = strstr(a+i, "the");
if ((found != NULL) && (found == a+i)){
printf("%s\n", a+i);
}
}
return 0;
}





355ポイント を手に入れた。


Name: box  ..比類無きプログラマー(72,182ポイント)   Date: 2007/06/23(土) 05:49   No:8849     
Title: Re:strstrについて    
「"the"の数を格納するための変数」(※)を用意します。

for文によるループの中で「"the"が見つかったら」という
判定を行なっています。そこに、(※)の値をインクリメントする
処理を加えます。

そのループを抜けたら、(※)の値を出力します。

なお、"then"などを数えないのでしたら、strstr()の第2引数の最後に
空白1文字を加えねばならないと思います。


144ポイント を手に入れた。

Name: なぎ  ..プログラマー(25,243ポイント)   Date: 2007/06/23(土) 09:25   No:8851     
Title: Re:strstrについて    
strstr() は、もともと、「文字列が見つかったらその位置を、char * で返す」という仕様です。
これが、「先頭からのバイト数」になってないのは、取っつきは悪いのですが、なかなか便利なのですね。

たとえば、

int i = 0;
char *p = a;

while((p = strstr(p, "the ")) != NULL)
{
i++;
p++;
}

こんなループでカウントすることができます。

1)p の調査したい点(最初は、文字列の先頭)から、見て、最初の "the " の位置を求める
2)"the " が存在しなかったら、ループ終了(strstr() の返値が NULL になるから)
3)i をカウントアップ
4)次の調査開始点を、今見つかった、"the " の先頭の次(具体的には、今見つかった "the " の 'h' の位置)において、再度調査

こんな意味合いです。
あと、p++; で、調査開始点をずらしていますが、ここは、"the " の次("the " のスペースの次)で、 p += 4
でも良いかもしれません。




278ポイント を手に入れた。

Name: yossiy  ..入門者(3,376ポイント)   Date: 2007/06/26(火) 18:27   No:8928     
Title: Re:strstrについて    
ご指導ありがとうございます。
友人の助けもかりてなんとかできました。

もうひとつ質問です。

[the]と[The]両方ともカウントするためには同じような文を2つけばよろしいのでしょうか?
もしくは、もっとスマートなやり方があるのですか?
教えてください!




#include <stdio.h>
#include <string.h>
int main(void)
{
int i=0,len;
char *found;
char a[]="Chiba University was founded in 1949, unifying several regional
former national colleges and schools such as Chiba Medical College and Chiba
Normal School. Its fundamental mission since then has been, as encapsulated by
the inscription on the University Bell, ad altiora semper (always toward the
higher), to equip students with the ability to make mature and informed
judgments while nurturing and guiding their creativity. Pursuing these goals of
excellence has resulted in Chiba University becoming one of the leading
academic research centers of Japan.";

found = a;
while((found = strstr(found, "the ")) != NULL)
{
i++;
found++;
}

printf("[the]の個数%d個\n",i);
return 0;
}


524ポイント を手に入れた。

Name: なぎ  ..プログラマー(25,135ポイント)   Date: 2007/06/27(水) 08:50   No:8941     
Title: Re:strstrについて    
The も the もカウントするということですが、もっと一般的に、大文字小文字の区別無くカウントするということであれば、よく使われるのは、

・元の文字列を(たとえば、toupper() などで)すべて大文字にそろえておく
・その後で、THE でカウントする

という処理です。
もちろん、事前にすべて小文字にそろえる(tolower() などで)のも同じ考え方になります。





108ポイント を落としてしまった。

Name: yossiy  ..入門者(3,398ポイント)   Date: 2007/06/28(木) 13:54   No:8964 解決!     
Title: Re:strstrについて    
ありがとうございました。

がんばって勉強します。


22ポイント を手に入れた。



Name: 管理人 [URL]  ..伝説のハッカー(378,685ポイント)   Date: 2007/06/27(水) 14:11   No:8943       
Title: 意味不明な挙動(雑談スレ)    

学部生に「突然プログラムが変な動きをするから見て欲しい」と言われたので見てみました。

すると、シェル画面がプログラムを実行すると突然意味不明な中国語の羅列のような画面にかわったり、
特定のprintf文の最初の文字が表示されなくなったり意味不明な挙動をしていました。

print文の最初の文字が表示されないと言うのは

printf("Count\n");
printf("Count\n");



Count
ount

こんな感じになるんです。しかし2番目を改行すると

printf("Count\n");

printf("Count\n");



Count
Count

正常に表示されたり、意味がわかりませんでした・・。
何が原因でなっているのか、一つ一つ見ていったところ、
文字コードに-50が入ったものを使用している部分がありました。
以下のような感じです。

char b[4]="abc";
b[2]=-50;
printf("%s",b);

これを実行すると何故か次からprintf文の最初の文字が表示されなくなったり、
シェル画面が中国語になったりしていました。
原因はよくわからないのですが、ウィンドウズではなりません・・。
linuxはよくわからない挙動をするので、質問に答えるのが結構大変です^^;


447ポイント を手に入れた。


Name: Justy  ..ハッカー(129,416ポイント)   Date: 2007/06/27(水) 16:54   No:8946     
Title: Re:意味不明な挙動(雑談スレ)    
>原因はよくわからないのですが
 うーん、実際やってみないとわかんないですけど、何となく端末が受け取った後の処理で
何かがずれてしまって以後間違ったまま解釈していったのではないでしょうか。
 例えば EUC-JPだったとして、0xCE(-50)が第一バイトに 次の 0x00が第二バイトであると
(そんな文字コードはないのに)解釈されてしまったとか。


 そういうあからさまにおかしい文字列を突っ込んだ場合はともかくとして、
Windows/Linux問わず、文字コードを決めつけて作られているプログラムを
実行したりすると普通に化けますよね。


 ちなみに

    char b[]="テスト";

printf("%s",b);


 なシンプルなものでも Widows+MSVC7.1で、UTF-8/UTF-16(bom付き)で保存したソースをビルドして
実行すると見事に化けます(w


198ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(378,867ポイント)   Date: 2007/06/27(水) 23:19   No:8955     
Title: Re:意味不明な挙動(雑談スレ)    
なるほど。
しかし突然中国語?のような漢字だらけのシェル画面に豹変したときはびっくりしました^^;
resetとコマンドすると直ることが判明したんですが、入力中もresetに相当する意味不明な漢字が表示されるので怖いですw

学生がコードのprintfの書いている行を1段ずらすとコンパイルがうまくいくと言っているのを聞いて、
いや〜それは関係ないだろうと思ってしまいましたが、
色々な可能性を考えるべきですね^^;


182ポイント を手に入れた。

Name: 大工  ..上級者(20,438ポイント)   Date: 2007/06/28(木) 01:09   No:8958     
Title: Re:意味不明な挙動(雑談スレ)    
お久しぶりです。

unix やら linuxの話っぽいのでちょっと質問・・・・

-lmってどういう意味のオプションでしたっけ?

最近Javaばっかりなので忘れてしましました><。


76ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(378,880ポイント)   Date: 2007/06/28(木) 01:27   No:8959     
Title: Re:意味不明な挙動(雑談スレ)    
私はlinuxをほとんど使わないのですが、それは数学のmath.hをインクルードする時に使うオプションではなかったでしょうか?

13ポイント を手に入れた。

Name: Justy  ..ハッカー(129,661ポイント)   Date: 2007/06/28(木) 01:31   No:8960     
Title: Re:意味不明な挙動(雑談スレ)    
printfの書いている行を1段ずらすとコンパイルがうまくいくと言っているのを
 不思議ですねぇ。

 たしかに実際問題 C/C++で書いたコードが正しくコンパイルされないことも多々はあります。
 そういうときは、コンパイラにアセンブリコードを出力させて調べると・・・
今回の場合ですとprintfの行を変えて、吐き出されたコードを比較すると
どうなっているのかわかると思います。

 gccなら -Sオプションだったかと思います。


-lmってどういう意味のオプションでしたっけ?
 -lはライブラリのリンクの指定で、-lmなら libm.aをリンクします。


245ポイント を手に入れた。

Name: 大工  ..上級者(20,523ポイント)   Date: 2007/06/28(木) 01:49   No:8961     
Title: Re:意味不明な挙動(雑談スレ)    
管理人さま・Justyさま>

返信ありがとうございます

libm.aが分からなくてググッてみたらなんとコマンド一覧(?)のページにたどり着けました!!

ここで修行してきます!



85ポイント を手に入れた。



Name: hana  ..ぴよぴよ(415ポイント)   Date: 2007/06/27(水) 16:39   No:8944       
Title: ファイルから文字列の読み込み    
いま、テキストファイルから文字列を読み込む勉強をしています。
いろいろ調べていると1文字づつとか1行づつ読み込んだりする方法はありますが、
テキストファイルの文字列を3文字づつ読み込んだりする方法ってあるのですか?
ちなみにテキストファイルはアルファベットの文章になっていて、配列に読み込もうと思ってます。
どなたか教えてください。


137ポイント を手に入れた。


Name: バグ  ..熟練のプログラマー(52,694ポイント)   Date: 2007/06/27(水) 17:31   No:8947     
Title: Re:ファイルから文字列の読み込み    
ありますよ〜♪(^-^)
fgets関数を利用すると読み込みたい文字数を指定できます。
下のプログラムを実行する前に、適当なテキストファイルを準備して下さい。

<サンプル例>

#include <windows.h> /* GetCurrentDirectoryを使用する為に必要 */
#include <stdio.h>

void main(void)
{
int nIndex = 0;
char szPath[MAX_PATH], szBuf[20][10];
FILE* pFile;

GetCurrentDirectory(MAX_PATH, szPath);
strcat(szPath, "\\Test.txt");

/* ファイルのオープン処理 */
if ((pFile = fopen(szPath, "rt")) == NULL)
{
return;
}

/* ファイルの中身を4文字(4文字目は'\0'になるので、実際は3文字です)ずつ読み込む */
/* 読み込み作業をファイルの終端が来るまで(fgets関数が失敗するまで)繰り返す */
while (fgets(szBuf[nIndex], 4, pFile) != NULL)
{
/* 読み込んだ文字列を表示 */
printf("%s\n", szBuf[nIndex]);
nIndex++;
}

/* ファイルのクローズ処理 */
fclose(pFile);
}


313ポイント を手に入れた。

Name: hana  ..ぴよぴよ(619ポイント)   Date: 2007/06/27(水) 19:32   No:8948     
Title: Re:ファイルから文字列の読み込み    
バグさんありがとうございます。
早速、テキストファイルを作って、プログラムをためさせてもらいました。
・・・が、コンパイルは通るんですがその後の実行結果

/* 読み込んだ文字列を表示 */
  printf("%s\n", szBuf[nIndex]);
  nIndex++;

ここのところが表示されません(>_<)
パソコンの調子が悪いのでしょうか?

ちなみにOSはwindowsとUNIX両方ためしましたが、どっちもだめでした。
あと、読み込みたいファイルの大きさは約4Kbyteです。


204ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(52,781ポイント)   Date: 2007/06/27(水) 20:08   No:8949     
Title: Re:ファイルから文字列の読み込み    
GetCurrentDirectory(MAX_PATH, szPath);
strcat(szPath, "\\Test.txt");

この部分でファイルの入っている場所と名前を指定しています。
ですので、この2行を消して、hanaさんが読み込みたいファイルの場所と名前を指定するように書き替えてみて下さい(^^ゞ


87ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(52,737ポイント)   Date: 2007/06/27(水) 20:10   No:8950     
Title: Re:ファイルから文字列の読み込み    
あ、それから、このプログラムはWINDOWS専用ですので、あしからず…。
GetCurrentDirectory関数を使用しなければ、動くとは思いますけど…


44ポイント を落としてしまった。

Name: box  ..比類無きプログラマー(73,679ポイント)   Date: 2007/06/27(水) 20:11   No:8951     
Title: Re:ファイルから文字列の読み込み    
ファイルのオープンに失敗して、プログラムが終了している、
ということはありませんか?


30ポイント を手に入れた。

Name: hana  ..ぴよぴよ(723ポイント)   Date: 2007/06/27(水) 21:05   No:8952     
Title: Re:ファイルから文字列の読み込み    
TO バグさん、boxさん
 再度確認しましたが、ファイルの名前等は大丈夫でした。

 わたしの認識不足で

 GetCurrentDirectory(MAX_PATH, szPath);
 strcat(szPath, "\\Test.txt");

のところで、「\\」は何でも入れていいって意味にとってました。
「\\」を入れたら無事に実行結果が出ました。

眠いですがもう少しがんばって詰めていきたいと思います。


104ポイント を手に入れた。



Name: さいもん  ..ぴよぴよ(183ポイント)   Date: 2007/06/26(火) 19:54   No:8929       
Title: ○×ゲーム    

むかし懐かしい○×ゲームを作ってみようと思いました。
○×ゲームとはこんなのです。

○| | 
 | | 
 | |


○| | 
 | | 
 | |×


○| | 
 | | 
○| |×


○| | 
 |×| 
○| |×

○| | 
○|×| 
○| |×

○の勝利!
3つ連続で並べると勝ちです。
これ敵のアルゴリズムを考えているのですが、なかなかわかりません・・。

現在全てのパターンについて全てif文で制御しているため、ものすごい長さのコードになってしまって、
可読性も皆無です・・。
入力は普通に0-0とか入力すると左上が選択されるとかって感じで入力してprintfで結果を表示しています。

こういうプログラムはどうやったらスマートにかけますか?
初心者ですので、難しいご回答はわからないかもしれませんが、よろしくお願いします。



183ポイント を手に入れた。


Name: box  ..比類無きプログラマー(73,426ポイント)   Date: 2007/06/27(水) 00:07   No:8932     
Title: Re:○×ゲーム    
私自身、詳しいことはわからないのですが、
どうも「ミニマックス法」や「α-β法」というキーワードについて
調べてみるとよさそうです。

ただ、3×3の○×ゲームは、双方が最善を尽くすと
引き分けになるような気がするのですけれど…。何となく。


110ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(378,238ポイント)   Date: 2007/06/27(水) 02:17   No:8937     
Title: Re:○×ゲーム    
○×ゲームですか!
私も作りました。
あれはプログラミングを初めてすぐの事でした。
私も同じ事で悩みました。
いい方法が思いつかず、ものすごい量のif文を書いた覚えがあります。
たった○×ゲーム一つで千行位書いたような・・。

結局完成はしました。
すべてのパターンを根性でif文で書いたら全部かけました。

結果後の番の人は絶対に勝てないという結論になりました^^;
COM同士で勝負すると毎回引き分けになりました。
・・と具体的な答えがかけないのですが・・。


239ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(52,356ポイント)   Date: 2007/06/27(水) 09:06   No:8942     
Title: Re:○×ゲーム    
下記のサイトのC言語編に参考になりそうな記事がありますよ(^-^)

猫でもわかるプログラミング
http://www.kumei.ne.jp/c_lang/


44ポイント を手に入れた。



Name: がんも  ..ぴよぴよ(850ポイント)   Date: 2007/06/27(水) 00:10   No:8933       
Title: 文字列と配列の問題です    
ぜひ教えてください!

問題は

文字列の長さを求める関数 str_len() を作成しなさい.str_len() は,ある文字列の先頭アドレスを実引数として与えられたとき,その文字列の長さ(最後の 0 を含まない byte数)を返す関数です.例えば,

int n1, n2; static char a[] = "ALPHABET";

n1 = str_len(a); n2 = str_len("abcd");

とすれば n1 に 8 が,n2 に 4 がそれぞれ代入されます.なお,この関数の第1行を

unsigned int str_len(char *c)

と定めます("char *c" は "char c[]" としても同じです.コンパイラは,どちらも「c は char型のポインタ変数である」と解釈します).

(ヒント)for文などを用いて *(c + i) が 0 となる直前までの byte数を調べます.



関数だけ作ればいようですが、一応scanfで文字の入力する形で作ってみました。
for文の使い方がよくわからなかったので使わなかったのですが…
コンパイルはできましたがうまく作動しません。
また作ってみたものの理解してるかはあやしいです;;
ぜひアドバイスをお願いします!



#include <stdio.h>

unsigned int str_len(char *c)
{
int i = 0;
do{
i = i++;
}while( *(c + i) != 0);

return i;

}

int main(void)
{
char a[100];
unsigned int n;

printf("文字列を入力して下さい。\n");

scanf("%s",a);

n = str_len(a);

printf("文字列の長さは%uです。",n);
}


2ポイント を手に入れた。


Name: がんも  ..かけだし(1,148ポイント)   Date: 2007/06/27(水) 00:38   No:8935     
Title: Re:文字列と配列の問題です    
すみません もうひとつ聞きたいことが。先ほどの問題の次の問題です。


加減算を表わす一行の文字列を入力した結果,その加減算を実行して計算値を出力するプログラム kagenzan.c を作りたいとします.kagenzan.c は,例えば

1234+62-32+224 [RET] ← 入力

= 1488 ← 出力

あるいは,

-26-39+14 [RET] ← 入力

= -51 ← 出力

などのように動作するプログラムです([RET] = リターンキー押下).

このような目的に使用される関数に atoi() があります(標準関数として用意されている).例えば,

char a[] = "1234+62-32+224"; int n;

n = atoi(a);

とすれば,n には値 1234 が代入されます.つまり atoi() は,文字列の最初に置かれた数値のみを int型に変換して出力するわけです.したがって,次は文字列 "1234" の byte数 4 を加えて n += atoi(a + 4); とすれば値 "+62" が n に加算され,さらにn += atoi(a + 7); により値 "-32" が n に加算されます.

このようにして atoi() を使用してゆけば,最後には "1234+62-32+224" の結果を得ることができます.この場合,atoi() の他に数値を表わす文字列の長さを求める関数 str_len2() が必要になります.

そこで問題8−3です.関数 str_len2() を作成しなさい.str_len2() は,先に作成した関数 str_len() が文字列の長さを 0 の直前まで数えるのに対し,0 および '+', '-' のいずれかの直前まで数える点が異なります.



とのことなのですが、この説明ではatoi()の使い方があまり理解できませんでした;;
よかったらこの問題についても教えていただけるとありがたいです。


298ポイント を手に入れた。

Name: toyo  ..かけだし(2,033ポイント)   Date: 2007/06/27(水) 07:56   No:8940     
Title: Re:文字列と配列の問題です    
i = i++;
これはコンパイラによってiが違ってくる可能性があります。
i = i + 1;

i++;
ですね。

戻り値がunsigned intなので i も unsigned int にしたほうが良いと思います。

do {
} while ( );
だと空文字列のとき動作が変になるのでwhile ( )ループの方が良いのでは。

以上を踏まえて
unsigned int str_len(char *c)
{
unsigned int i = 0;
while( *(c + i) != 0){
i++;
}
return i;
}


136ポイント を手に入れた。



Name: さっかん  ..かけだし(1,394ポイント)   Date: 2007/06/24(日) 22:22   No:8892       
Title: 位分け    
早速ですが、再び質問させていただきます;;

位分けってありますよね?例1000000000⇒1,000,000,000(位分けというのかわかりませんが;)
十桁までの数字を入れれば位分けをしてくれる関数を作りたいのですが、自分なりに作ってみたのですが途中でわからないところがあるのでご教授下さい。

数字を受け取る(例:1852078004)

4つに分ける。(1と852と78と4に分ける)
1000000000未満、1000000以上なら3つにわける。
1000000未満、1000以上なら2つにわける。
1000未満ならそのまま(負数は考えません)。

間に「,」を加えて数値は数字として文字配列に格納する。(a[0]:'1' a[1]:',' a[2]:852 a[3]:','・・・・・a[7]:'4')

0をつけて格納する(1⇒1、852⇒852、78⇒078、4⇒004)
【↑この方法がいまいち分かりません;ご教授お願いします!】

文字を返す

以上です。もしも回りくどいことをしているならもっと簡単な方法を教えて欲しいのですが、基本的なことしかわからないため、あまり高度な技は理解しにくいかもしれませんので、よろしくお願いします。


397ポイント を手に入れた。


Name: box  ..比類無きプログラマー(73,169ポイント)   Date: 2007/06/24(日) 22:50   No:8893     
Title: Re:位分け    
> 数字を受け取る(例:1852078004)

入力を数値で受け取ると、1つ問題点があります。

10桁までに対応するということは、0〜9999999999
(99億9999万9999まで)に対応したいのですよね。
ところが、コンピュータの(32ビットの)世界では、
unsigned long型の最大値でも43億に満たない値です。

入力を文字列で受け取るようにすれば、少なくとも
この問題点からは解放されます。

入力する文字列は、通常、'0'〜'9'の数字からなる長さが1〜10の文字列です。
このルールに反する場合の対応も考えておく方がよいでしょう。

正しい仕様の文字列を受け取り、それを3桁ずつカンマで区切るには、
文字列の長さが
 ・1〜3の場合
 ・4〜6の場合
 ・7〜9の場合
 ・10の場合
となるケースについて考えるか、または、文字列の長さを3で割ったあまりが
 ・0の場合
 ・1の場合
 ・2の場合
となるケースについて考えるか、あるいは両者を組み合わせるか、でありましょう。


200ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(377,364ポイント)   Date: 2007/06/25(月) 00:26   No:8895     
Title: Re:位分け    
もし、コンマを表示したいだけなら下のように考えました。

数字で受りたいのならLONGLONG型を使ってみてはいかがでしょう。
windows.hをインクルードする必要がありますが。

また、文字列に格納してから必要なときにコンマをうちながら表示すれば簡単ではないでしょうか?
サンプル作ってみました。
きっともっといい方法があるのでしょうけど、パッと考えてこんな感じはどうかなと思ったので書きました。


#include <stdio.h>
#include <windows.h>

void conma(LONGLONG n){
int i=0,j,s;
char st[20];

while(1){
st[i++]='0'+n%10; //一桁ずつ格納
if(n<10)
break;
n/=10;
}
i--;
for(j=i,s=0;j>=0;j--,s++){
printf("%c",st[j]);
if(i%3==s%3 && j!=0)//iは桁数。3桁ずつコンマをうつ、かつ最後の行ではコンマをうたない
printf(",");
}
}

int main(){
int i=0;
LONGLONG n;
n=10000000000;
conma(n);
return 0;
}

 
用意した配列の数より多くなりそうなら処理をやめたり、他必要なエラー処理は必要に応じて行ってください。

質問内容でよくわからないとおっしゃっている部分もサンプルにでてくる

st[i++]='0'+n%10; //一桁ずつ格納

この辺見ていただければ解決するのではないでしょうか。


180ポイント を手に入れた。

Name: さっかん  ..かけだし(1,700ポイント)   Date: 2007/06/25(月) 01:35   No:8897     
Title: Re:位分け    
返信が遅くなってすいません><;
boxさんの言うとおり一回文字列に直して格納したほうが安全ですね!ルールに反した場合のエラー処理は一応elseの時という感じで用意してます。
管理人さんのプログラムをそのまま貼り付けてコンパイルしてみたら
warning:integer constant is too large for "long" type
という警告が表示されたんですが、これはLONGLONG型がlong型と読みとられたから格納しきれなかったのですか??
あと警告だけだったので実行できると思って実行したら、ほんの一瞬だけ10,000,000,000と出てすぐ消えてしまいました。この前にもこんなことがあって、その時は¥nで改行を入れたらちゃんと消えずに表示されたので、今回もforを出た後にprintf("\n");で改行を入れたらちゃんと表示されました。これはどういうことなんでしょうか??


306ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(377,364ポイント)   Date: 2007/06/25(月) 03:23   No:8898     
Title: Re:位分け    
う〜ん、、、そういう経験は無いのですが、、、
コンパイラは何ですか?
OS等環境を教えてもらえたら何か調べようがあるかもしれません。


Name: さっかん  ..かけだし(1,749ポイント)   Date: 2007/06/25(月) 14:34   No:8906     
Title: Re:位分け    
windowsでsygwinというものを使っています。
あと何度もすいませんが
warning:integer constant is too large for "long" type
という警告は上に書いたような意味としてとらえて良いのでしょうか?


49ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(51,599ポイント)   Date: 2007/06/25(月) 14:45   No:8907     
Title: Re:位分け    
試しに、LONGLONGの部分を__int64に書き換えてみて下さい。
テストなんで、うまく動くかどうか保証はありませんけど…(^_^;)


50ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(51,635ポイント)   Date: 2007/06/25(月) 14:46   No:8908     
Title: Re:位分け    
ひょっとしたら、64bit整数型がサポートされていない環境なのかもしれません…

36ポイント を手に入れた。

Name: Justy  ..ハッカー(129,022ポイント)   Date: 2007/06/25(月) 15:14   No:8909     
Title: Re:位分け    
 その警告は多分 gcc(cygwinでしょうかね)をつかっているからで、
n=10000000000の代入のところで、数字の部分を 10000000000LLとかにすれば
直るかもしれません。


72ポイント を落としてしまった。

Name: 管理人 [URL]  ..伝説のハッカー(378,146ポイント)   Date: 2007/06/25(月) 15:22   No:8910     
Title: Re:位分け    
なるほど、LLをつける必要があるんですか^^;
しかし何故改行すると正常に表示されるんでしょうね・・。


35ポイント を手に入れた。

Name: Justy  ..ハッカー(129,140ポイント)   Date: 2007/06/25(月) 15:39   No:8911     
Title: Re:位分け    
>何故改行すると正常に表示されるんでしょうね・

 printfとかの出力ストリームって呼んだらすぐに表示されることは保証していません。
 
 大抵行単位でバッファリングしているので、その場合改行コードがあるか、
入力ストリームからの読み込みがあるとかしないと出力されません。

 なので、強制的に出力する fflush()があります。


118ポイント を手に入れた。

Name: さっかん  ..かけだし(2,146ポイント)   Date: 2007/06/25(月) 16:04   No:8912     
Title: Re:位分け    
それ不思議なんですよ〜^^;
一回LLつけてやってみますね!
あと次々と質問攻めで失礼ではあると思うのですが・・・

#include<stdio.h>
#include<string.h>
char place(int number,char buf[7][10]);
int main()
{
int x;
char y[7][10];
x=123456;
place(x,y);
printf("%s\n",y[0]);
return 0;
}
char place(int number,char buf[7][10]){
int a,b;
char num[7][10];
a=number*1000;
b=number-a*1000;
sprintf(num[0],"%d",a);
strcpy(num[1],",");
sprintf(num[2],"%d",b);
}

このプログラムを実行したら何も表示されないんですが、何故でしょうか?
あと今printfにy[0]を出力させているんですが、ひとつの%sに一気にy[0]とy[1]とy[2]を出力させることはできますか?
やはりfor文を使ったり、"%s%s%s",y[0],y[1],y[2]と書くしかないのでしょうか?
一気に質問してしまいましたが、よろしくお願いします!!


397ポイント を手に入れた。

Name: さっかん  ..かけだし(2,105ポイント)   Date: 2007/06/25(月) 16:08   No:8913     
Title: Re:位分け    
>justyさん
残念ながら難しくて理解しにくいのですが、頭に叩き込んでおきます!
ご説明ありがとうございます!!


41ポイント を落としてしまった。

Name: バグ  ..熟練のプログラマー(51,686ポイント)   Date: 2007/06/25(月) 16:35   No:8914     
Title: Re:位分け    
place関数内でオーバーフローしてますね。

123456 * 1000 * 1000 = 123456000000

この値はint型に収められる範囲を大きく超えてしまっています。
それで起こっている現象だと思われます。


51ポイント を手に入れた。

Name: box  ..比類無きプログラマー(73,248ポイント)   Date: 2007/06/25(月) 16:53   No:8915     
Title: Re:位分け    
> このプログラムを実行したら何も表示されないんですが、何故でしょうか?

place関数で定義しているnum[][]は、同関数の中だけで有効です。
sprintf関数やstrcpy関数を使ってセットした内容は、
place関数から抜けた時点で雲散霧消しています。


79ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(51,715ポイント)   Date: 2007/06/25(月) 17:00   No:8916     
Title: Re:位分け    
>>boxさん
あ、本当ですね…オーバーフローよりも、もっと根本的な部分に気付いてなかったとは…(^_^;)


29ポイント を手に入れた。

Name: さっかん  ..かけだし(2,136ポイント)   Date: 2007/06/25(月) 17:26   No:8917     
Title: Re:位分け    
あ!numではなくてbufを使わなきゃいけませんよね!
初歩的なミスでした;すいません;;
えと、main内のprintfでyに入った物を全部表示させたいのですが、y[0]から一個ずつ%sで出していくしかないんですよね?


31ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(52,097ポイント)   Date: 2007/06/25(月) 17:49   No:8918     
Title: Re:位分け    
>>えと、main内のprintfでyに入った物を全部表示させたいのですが、y[0]から一個ずつ%sで出していくしかないんですよね?

うーん、2次元配列を1次元配列に変更すればいいかと思いますよ。どうしても2次元配列でないといけないのであれば、別に1次元のバッファを用意して、strcat関数等で文字列を連結させるとか…どうでしょう?

下記サンプルは前者の方法を採用したものです。


#include <windows.h>
#include <stdio.h>
#include <string.h>

void place(LONGLONG number, char buf[4096]);

int main()
{
LONGLONG x;
char y[4096];

x = 123456;
place(x, y);
printf("%s\n", y);

return 0;
}

void place(LONGLONG number, char buf[4096])
{
LONGLONG a, b;

a = number * 1000;
b = number - a * 1000;

sprintf(buf,"%d, %d",a, b);
}


382ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(52,264ポイント)   Date: 2007/06/25(月) 17:57   No:8919     
Title: Re:位分け    
もう1つのサンプルです(^-^)


#include<stdio.h>
#include<string.h>

void place(unsigned long number,char buf[7][10]);

int main()
{
unsigned long x;
char y[7][10], z[70];

x=123456;
place(x,y);
sprintf(z, "%s%s%s", y[0], y[1], y[2]);
printf("%s\n", z);

return 0;
}

void place(unsigned long number,char buf[7][10])
{
unsigned long a, b;

a = number * 1000;
b = number - a * 1000;

sprintf(buf[0], "%d", a);
strcpy(buf[1], ",");
sprintf(buf[2], "%d", b);
}


167ポイント を手に入れた。

Name: Justy  ..ハッカー(129,099ポイント)   Date: 2007/06/25(月) 18:24   No:8921     
Title: Re:位分け    
>sprintf(buf[0], "%d", a);
 aや bは unsigned longなので、"%d"ではなく "%lu"になります。


41ポイント を落としてしまった。

Name: バグ  ..熟練のプログラマー(52,312ポイント)   Date: 2007/06/25(月) 19:05   No:8922     
Title: Re:位分け    
え?そうなんですか?(汗)

整数型は全部"%d"でいけるのかと思ってました(;^_^A

実際、今回のも普通に表示されていますし、これまでも不具合とか無かったので…(^^ゞ


48ポイント を手に入れた。

Name: さっかん  ..かけだし(1,945ポイント)   Date: 2007/06/25(月) 21:58   No:8924     
Title: Re:位分け    
入力する数字が一億になると、yの配列が7つ(コンマを入れるため)必要になって配列を使う量が変わってくるので何個の時にも対応してprintfを使えるように、前者のサンプルを参考にしたいと思います。その前者のサンプルで
sprintf(buf,"%d, %d",a, b);
とありますが、%dと%dの間の,は数字の位分けするためのコンマを表しているんですよね?
あとbが4だった時に0を二つつけて004として格納しなければならないのですが、このように一次元配列の場合でも可能ですか?


191ポイント を落としてしまった。

Name: box  ..比類無きプログラマー(73,316ポイント)   Date: 2007/06/25(月) 23:20   No:8925     
Title: Re:位分け    

書式文字列を決める際の参考になるでしょうか。

#include <stdio.h>

int main(void)
{
int i, j, k;

for (i = 0; i <= 1000; i += 1000) {
for (j = 0; j <= 99; j++) {
k = i + j;
if (k < 1000)
printf("%3d ", k);
else
printf("%d,%03d ", k / 1000, k % 1000);
if (k % 10 == 9)
putchar('\n');
}
putchar('\n');
}
return 0;
}



68ポイント を手に入れた。

Name: Justy  ..ハッカー(129,218ポイント)   Date: 2007/06/26(火) 01:13   No:8926     
Title: Re:位分け    
>実際、今回のも普通に表示されていますし、これまでも不具合とか無かったので…(^^ゞ
 まぁ、実際のところ sizeof(int) == sizeof(unsigned long)なら「大抵」は大丈夫ですが、
そうとも符号の有無も違うので内部の挙動が若干変わりますし、
long型が 8バイトな環境も多く存在しますので出来るだけフォーマット指定は
実際の型に合わせておいた方がいいかと思います。


http://www.itmedia.co.jp/enterprise/articles/0506/14/news003_2.html


119ポイント を手に入れた。

Name: さっかん  ..かけだし(2,041ポイント)   Date: 2007/06/26(火) 21:12   No:8930     
Title: Re:位分け    
返信が大分遅れてしまってすいません;;
皆さんアドバイス有難う御座います!少し難しくて分からないところもありますので、自分なりに調べて参考にさせていただきます。一応今夜頑張ってみます。また分からないところが出てきたらその時はよろしくお願いします。



96ポイント を手に入れた。

Name: 初心者A  ..ぴよぴよ(46ポイント)   Date: 2007/06/26(火) 22:29   No:8931     
Title: Re:位分け    
こんなの作ってみました。


char buff[256];
int len;
int i;

for(;;)
{
fgets(buff, sizeof(buff), stdin);
/* 後ろの余計な制御文字を除去 */
for(i = (int)strlen(buff) - 1; i >= 0 && buff[i] < ' '; i--)
{
buff[i] = '\0';
}
/* 終了条件は改行のみ入力 */
if(*buff == '\0')
{
break;
}
/* 頑張って表示して見る */
len = (int)strlen(buff);
for(i = 0; i < len; i++)
{
if((len - i) % 3 == 0 && i > 0)
{
printf(",");
}
printf("%c", buff[i]);
}
printf("\n\n");
}


46ポイント を手に入れた。

Name: YuO  ..初心者(8,369ポイント)   Date: 2007/06/27(水) 00:25   No:8934     
Title: Re:位分け    
ほぼ与太話として見ていただければよいです。

えーっと,国際化対応のために<locale.h>というものがありまして,
その中に,localeconvという関数があります。

で,これで得られるstruct lconvには
・decimal_point
・thousands_sep
・grouping
という金額以外の値を整形出力するためのメンバが存在します。
# setlocaleされたLC_NUMERICで変更されます。

わかりやすいのはdecimal_pointで,アメリカや日本なら.ですが,フランスやドイツなどでは,だったりします。
# これは,printfでも確認できます。

ところが,これを実際に使うと死ぬほど面倒なことになります。
# groupingの取り扱いが面倒……。
で,便利な方法は……標準ライブラリには用意されていません。

時間があれば,挑戦してみるのも面白いと思いますよ。
ちなみに,別の掲示板の過去ログに,私が昔格闘した結果 (通貨なのでもっとややこしい) があったりします。
まぁ,退屈しのぎにでもなれば。
http://f4.aaa.livedoor.jp/~pointc/log679.html


421ポイント を手に入れた。

Name: さっかん  ..かけだし(2,063ポイント)   Date: 2007/06/27(水) 00:40   No:8936 解決!     
Title: Re:位分け    
おかげさまでプログラムは完成しました!(がむしゃらに作ったので287行になりましたが;)
助けていただいた皆さんに心から感謝いたします。
また分からないところがあったらよろしくお願いします!


22ポイント を手に入れた。

Name: box  ..比類無きプログラマー(73,649ポイント)   Date: 2007/06/27(水) 05:19   No:8938     
Title: Re:位分け    
いったん投稿いたしましたが、
解決した後の投稿としては内容が不適切であるため、
お見せするのを控えます。
失礼いたしました。


223ポイント を手に入れた。

Name: さっかん  ..かけだし(2,095ポイント)   Date: 2007/06/27(水) 07:39   No:8939 解決!     
Title: Re:位分け    
いえいえ、どうかお気になさらないで下さい。
boxさんも色々と有難う御座いました!


32ポイント を手に入れた。



Name: C言語はじめました  ..ぴよぴよ(62ポイント)   Date: 2007/06/25(月) 01:10   No:8896       
Title: 16進数のデータをファイルから読込む    
 こんばんは。
 貴HPの”if文とfor文、簡単な関数扱いしか知らない人でも簡単に…”の文面を見て力を得ました。
 現在、ゲーム基本編まで読み終え、自分なりにソースをいじくってみたりしながらC言語の勉強をしています。

 今度、各ラウンド毎にマップデータを書き換えて表示するプログラムを組もうと思っています。
 例えば、16×16のマップデータがあるとして、”00,2A,3C,…”のように書いて、それをテキストファイルに
保存しておき、必要に応じて二次元配列(Map[x][y])に読込むというものなのですが…VBほど楽にはいかず困っ
ています。

 とりあえず、”fopen”や”printf”を使ってデータを読込むということはわかるのですが、そこから先が
わかりません。
 テキストデータを16進数で保存しているので、文字列で受け取ってから整数に変換すると思うのですが、VBの
”Val("&h"+変数)”みたいな変換方法はあるのでしょうか?もし、なんらかの関数があるならば教えてください。
よろしくお願いします。


62ポイント を手に入れた。


Name: 管理人 [URL]  ..伝説のハッカー(377,632ポイント)   Date: 2007/06/25(月) 03:32   No:8899     
Title: Re:16進数のデータをファイルから読込む    
こんばんは。
HPの方みてくださってありがとうございます^^

ファイルから読み込んだ文字列はもちろん数値に変換できます。

http://www.geocities.jp/ky_webid/c/044.html

こちら参考になると思います。
たとえば10進数でかかれけた整数の文字列を数値に変換するときはatoi関数を使います。
好きな基数に変換できるstrtolもありますので参考にしてください。

また、printfを使ってデータを読み込むという意味がよくわからないのですが、
データはどんな風に入っていますか?
1つのデータがちゃんと1つの配列に1つの文字列として入っていたら変換は簡単です。
もし12,3,45,6,7みたいにデータがまるごと配列にはいってて、それを変換するなら別途処理が必要です。
とりあえず

00,2A,3C....と入っていて、1行単位で丸ごと配列に入っているなら「,」の部分を\0に変換して沢山文字列があるように見せかける方法もあります。
必要ならそちらも紹介します。


268ポイント を手に入れた。

Name: フリオ  ..中級者(11,811ポイント)   Date: 2007/06/25(月) 05:33   No:8900     
Title: Re:16進数のデータをファイルから読込む    
 
 データのフォーマットが固定なら、こんな方法もあります。


#include <stdio.h>

#define MAPSIZE 6

int main(void)
{
FILE *fp = fopen("test.txt", "r");
int hex[MAPSIZE][MAPSIZE], i, j;

if(fp == NULL) return 1;
for(i = 0; i < MAPSIZE; i ++){
for(j = 0; j < MAPSIZE; j ++){
fscanf(fp, "%x,", &hex[i][j]);
printf("%02x ", hex[i][j]);
}
putchar('\n');
}
fclose(fp);
return 0;
}



test.txt

00,2A,3C,4d,5e,6f
7a,8b,9c,ad,be,cf
d0,e1,f2,03,14,25
36,47,58,69,7a,8b
9c,ad,be,cf,d0,e1
f2,03,14,25,36,47

 


240ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(378,111ポイント)   Date: 2007/06/25(月) 13:30   No:8905     
Title: Re:16進数のデータをファイルから読込む    
最初から16進数で受け取ってよく、データの形がフリオさんのおっしゃる通り固定であれば、フリオさんのおっしゃる方法がいいと思いますが、私が書いた方法のサンプル書いたので一応紹介します。
これは特にファイルから読み込むとき以外にも使う方法なので、知ってて損は無いと思います。

文字列というのは、示したアドレスから終端記号が入っている所までをさすということを利用すればこんな使い方が出来ます。


#include <stdio.h>
#include <stdlib.h>

int main(){
int i=0,j;
char st[20]="7a,8b,9c,ad,be,cf,";

while(st[i]!='\0'){
if(st[i]==',')
st[i]='\0';
i++;
}

for(j=0;j<i;j+=3)
printf("&st[%2d] - %s -> %x\n", j, &st[j], strtol(&st[j], NULL, 16));

return 0;
}

実行結果

&st[ 0] - 7a -> 7a
&st[ 3] - 8b -> 8b
&st[ 6] - 9c -> 9c
&st[ 9] - ad -> ad
&st[12] - be -> be
&st[15] - cf -> cf




こんな感じで最初入っています。

[0] [1] [2] [3] [4] [5] [6] [7] [8]
----------------------------------------------
| 7 | a | , | 8 | b | , | 9 | c | , |
----------------------------------------------
これをコンマを終端記号に置換すると
----------------------------------------------
| 7 | a | \0 | 8 | b | \0 | 9 | c | \0 |
----------------------------------------------
↑ ↑ ↑
こうなります。だから[0],[3],[6]のアドレスを示せばそこから終端記号までの文字列が示せるというわけです。



 


437ポイント を手に入れた。

Name: C言語はじめました  ..ぴよぴよ(0ポイント)   Date: 2007/06/25(月) 18:11   No:8920 解決!     
Title: Re:16進数のデータをファイルから読込む    
 こんなにも早く回答をいただけるとは、感激です!!
 回答をみながら、自分が全く見当違いな思い込みをしていることに気が付きました。
 printfはただの表示用関数ですね。
 恥ずかしい!!!!
 今回はデータを16進数で書き、マップの大きさも固定にしているので、フリオさんの回答のように
fscanf関数で書き換えたら動きました。
 管理人さんとフリオさん、ありがとうございました。


98ポイント を落としてしまった。

Name: 管理人 [URL]  ..伝説のハッカー(377,999ポイント)   Date: 2007/06/25(月) 19:47   No:8923     
Title: Re:16進数のデータをファイルから読込む    
よかったですね。

>マップの大きさも固定にしているので、

別にマップの大きさは固定じゃなくても、大丈夫ですよ。
マップの大きさはがわればMAPSIZEを変えたら大丈夫です。
フリオさんのおっしゃるのは「フォーマットがちゃんと決まっているか」って事だと思います。
つまり、これはデータがあって、コンマがあって、データがあって、コンマがあって、
というぴったりこの通りの記述の仕方じゃないとうまくいかないからです。
まぁ突然コンマがピリオドになることも無いと思うのでこの方法がいいと思いますよ。


147ポイント を落としてしまった。

Name: フリオ  ..中級者(11,953ポイント)   Date: 2007/06/26(火) 08:02   No:8927     
Title: Re:16進数のデータをファイルから読込む    
 
 "strtol"を使うならこんな感じでしょうか。


#include <stdio.h>
#include <stdlib.h>

#define MAPSIZE 6
#define STRMAX 256

int main(void)
{
FILE *fp = fopen("test.txt", "r");
int hex[MAPSIZE][MAPSIZE], i, j;
char *head, *end;
char str[STRMAX];

if(fp == NULL) return 1;
for(i = 0; fgets(str, STRMAX, fp); i ++){
head = end = str;
for(j = 0; *end != '\n' && *end; j ++){
hex[i][j] = strtol(head, &end, 16);
printf("%02x ", hex[i][j]);
head = end + 1;
}
putchar('\n');
}
fclose(fp);
return 0;
}

 


142ポイント を手に入れた。



Name: @とんぷぅ〜  ..中級者(11,281ポイント)   Date: 2007/05/22(火) 13:55   No:7821       
Title: 四則演算プログラムについて    
いつもお世話になっております@とんぷぅ〜です。
今回も四則演算のプログラムなのですが、条件としては

@括弧を用いた計算を可能にする。
Aスペースを入れなくても計算できるようにする。
Bどんな整数を入力しても計算結果が正しく表示されるようにする。

というものなんですが、Aについては1 + 1 = 2を1+1=2でも計算
できるようにするということです。これはコマンドライン引数
から取得する方法でも可能なんでしょうか?

Bについては具体的に、桁の数を20や30にしても計算できるように
するということなんですが、これは型といったことを全く無視して
行うのでしょうか?どうすればよいのか全く思いつきません。

皆様よろしくお願いします。


296ポイント を手に入れた。


Name: 管理人 [URL]  ..伝説のハッカー(332,111ポイント)   Date: 2007/05/22(火) 15:53   No:7823     
Title: Re:無題    
まず、四則演算を計算するには、スタックが有効ではないかと思いますが、スタックの利用方法についてはよろしいでしょうか?
(どこから解説すればよいかが変わってきますので)
あと、スタックで計算する場合、
1 + 1

1 1 +
になりますが、後者のままではよくないのでしょうか?

昔似たような投稿がありました。
http://www.play21.jp/board/formz.cgi?action=res&resno=2821&page=&lognum=10&id=dixq&rln=2980
Justyさんのお書きになったサンプルは時間がたったため自動削除されてしまったようですが、
スタックを使った四則演算プログラムならすぐ作れます。


21ポイント を手に入れた。

Name: Justy  ..ハッカー(103,140ポイント)   Date: 2007/05/22(火) 16:27   No:7826     
Title: Re:無題    
# @とんぷぅ〜さん
取得する方法でも可能なんでしょうか?
 問題なく可能です。
 複数のコマンドライン引数で与えられた計算式でも、1つの文字列に結合するか、
要素毎に分離するかしてしまえば楽に処理できるはずです。


どうすればよいのか全く思いつきません
 桁数が大きい数値の演算をするには、1つの手として多倍長整数を使うというのがあります。
 ググれば出てきますので、調べてみてください。



# 管理人 さん
時間がたったため自動削除
 懐かしいスレですね。
 あー、添付した物は過去ログ行きになると消えるんですね。
 消えてくれると嬉しい物もあったりするので、助かるといえば助かります(w


233ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(332,345ポイント)   Date: 2007/05/22(火) 16:40   No:7827     
Title: Re:無題    
LONGLONG型を使ってみるのもいいかと思います。


#include <stdio.h>
#include <windows.h>

int main(){
int i;
LONGLONG a=1;
for(i=1;i<64;i++)
printf("2^%-2d = %I64d\n",i,a*=2);
return 0;
}

実行結果
2^1 = 2
2^2 = 4
2^3 = 8

・・・(略)

2^60 = 1152921504606846976
2^61 = 2305843009213693952
2^62 = 4611686018427387904
2^63 = -9223372036854775808

 
 


234ポイント を手に入れた。

Name: @とんぷぅ〜  ..中級者(11,402ポイント)   Date: 2007/05/22(火) 17:17   No:7828     
Title: Re:無題    
管理人さん。レスありがとうございます。

申し訳ございませんが、スタックについては後入れ先出しの
データ構造ということしか理解しておりません。

11+というのは、引数に11+と入力し計算結果が2になる
ということなのでしょうか?

桁数についてはint型で扱うことが出来ない範囲も計算したい
(20桁どうしの掛け算など)のですが、文字列扱いにして
計算すれば良いのでしょうか?質問ばかりですみません。


121ポイント を手に入れた。

Name: @とんぷぅ〜  ..中級者(11,608ポイント)   Date: 2007/05/22(火) 17:29   No:7829     
Title: Re:無題    
管理人さん。Justyさん。お世話になっております。
<<Justyさん
多倍長整数とは難しそうですが、調べてみます。
引数については結合か分離で可能なのですね。
ご回答ありがとうございました。

<<管理人さん
今回は一応何桁でも計算できるというのが目的で(あまり
長すぎてもアレなので、40桁まで扱いたいです。)
long long型だと扱える数値の数にどうしても、限りが
あるため、今回は使用出来ないのです。文章が分かりにくくて
すみませんでした。


206ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(332,565ポイント)   Date: 2007/05/22(火) 19:58   No:7834     
Title: Re:無題    
あら・・、学校でスタックを使ったサンプルを作ってたのに、忘れてて帰ってきてしまった(T_T
すみません、、、。
しかし今回の課題を見るとスタックを使った方法では実現出来そうにないですね。

1 + 1

1 1 +
と入力する事になりますが、スペースをなくすと11になってしまいますし。
http://www.google.co.jp/search?hl=ja&q=%E9%80%86%E3%83%9D%E3%83%BC%E3%83%A9%E3%83%B3%E3%83%89&lr=
この辺を参考に調べてみてください。

私はスタックを利用した四則演算しかパッと思いつかないのですが、
サンプルをもう一度作ってみます。

後は全てカッコや四則演算子を全て個別に一つずつ解析していく方法しか思いつきませんが、
それは賢くないですよね。。


220ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,214ポイント)   Date: 2007/05/22(火) 20:09   No:7835     
Title: Re:無題    
数値用のスタックと演算子(カッコを含む)用のスタックを
別々に用意すれば、逆ポーランド記法を使わなくても、
一般的な数式の書き方に対応できるように思います。


48ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(333,624ポイント)   Date: 2007/05/22(火) 20:24   No:7836     
Title: Re:無題    

スタックについてはご存知のようですので、そのまま
スタックを使った四則演算のサンプルを提示します。
以下のような計算式は
(1+1) * (2+2) / (4-2)
このように書きます。
1 1 + 2 2 + * 4 2 - /

実行計算過程はこのようになります。
1 1 + 2 2 + * 4 2 - /
データ: 1
データ: 1 1
データ: 2
データ: 2 2
データ: 2 2 2
データ: 2 4
データ: 8
データ: 8 4
データ: 8 4 2
データ: 8 2
データ: 4
4

以下サンプルプログラムです。

#include <stdio.h>
#include <stdlib.h>

#define RET 0
#define NUMBER 1
#define PLUS 2
#define MINUS 3
#define MULT 4
#define DIV 5
#define OTHER 6

#define stack_size 100

int stack[stack_size];
int sp;

void push(int x){//配列要素番号を1増やして引数を格納する。
if (sp < stack_size-1)
stack[++sp] = x;
else {
printf("スタックがいっぱい。 \n");
exit(1);
}
}

int pop(){//返り値に配列要素を返して配列要素番号を1減らす
if (sp >= 0)
return stack[sp--];
else {
printf("スタック空っぽエラー.\n");
exit(1);
}
}

void print_stack(){
int i;
if (sp < 0) {
printf("スタックがからっぽ\n");
return;
}
printf("データ: ");
for(i=0; i<=sp; i++)
printf("%d ", stack[i]);
printf("\n");
}

int gettoken(int *num){
int c, n;
while ((c = getchar()) == ' ' || c == '\t');//スペースを読み飛ばす
switch(c){
/*ここから入力文字列を数値に変換*/
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = c - '0';//文字を数値に変換
while(1) {//入力された文字列を数値に変換
c = getchar();//1文字取得
if ('0' <= c && c <= '9'){//0〜9まで
n = 10*n + c - '0';
}
else {
break;
}
}
*num = n;
/*ここまで*/
return NUMBER;

//読んでいる入力情報によって返り値を分岐
case '+' : return PLUS;
case '-' : return MINUS;
case '*' : return MULT;
case '/' : return DIV;
case '\n': return RET;
default : return OTHER;
}
}

int main(){
int token, num, x;
token = gettoken(&num);//numに数値を入れ、tokenに識別番号を入れる。
sp =-1; //sp初期化
while(token != RET) {//tokenが改行で無い限り
switch(token){
case NUMBER: push(num); break;//数値ならプッシュ
case PLUS : push(pop() + pop());//プラスなら2つ取り出して取り出した2つを格納する。
break;
case MINUS : x = pop();
push(pop() - x);
break;
case MULT : push(pop() * pop());
break;
case DIV : x = pop();
if (x != 0) {
push(pop() / x);
break;
}
else {
printf("0割り禁止\n");
exit(1);
}
case OTHER : printf("不正な文字\n");
exit(1);
}
print_stack();
token = gettoken(&num);
}
if (sp+1== 1)
printf("%5d\n", pop());
else {
printf("シンタックスエラー\n");
exit(1);
}
return 0;
}
 
 


1,059ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(15,490ポイント)   Date: 2007/05/22(火) 22:07   No:7838     
Title: Re:無題    
管理人さん。boxさんありがとうございました。

>後は全てカッコや四則演算子を全て個別に一つずつ解析していく方法しか
私も調べたところ、この方法が一番いいのかと思ったのですが、あまり賢い
方法ではないかもしれませんね。

>数値用のスタックと演算子(カッコを含む)用のスタックを別々に用意
そんな方法があるのですね。しかし難しそうですね。
スタックについてもまだまだ勉強しなければいけないですね。

>スタックを使った四則演算のサンプル
サンプルありがとうございました。動かしてみたんですが、やはり逆ポーランド
ではなく、一般的な表記法 1 + ( -5 ) = -4になるような方法じゃないと無理
みたいです。

ちなみに以前作成したサンプルです。関数化してない為見にくいと思いますが
これは整数型の四則演算を行うプログラムです。扱える範囲を2147483647〜-2147483648としています。
これにベースに上記の3つの条件を付け足したプログラムを作成しろということなんですが、
これまではオーバーフローばかりを気にしていたのに、今度は全く逆に何桁
でも計算出来るようにすると言ったギャップにとまどっています(笑)

/****************************************	


* *

* NAME 【sisokenzan.c】 *

* SYNOPSIS【sisokenzan lop op rop】*

* *

*****************************************/

#pragma warning ( disable : 4996 )

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>

int main ( int argc, char *argv[] )
{
int max = INT_MAX; // 表現可能な最大値
int min = INT_MIN; // 表現可能な最小値

long long lop; // 左のオペランドに入力する値
long long rop; // 右のオペランドに入力する
long long mod; // 除算の余り
long long result; // 計算結果を格納

char *check; // 変換不可能な文字を格納
char op; // 入力する演算子

// 引数の個数チェック
if ( argc != 4 ) {
printf ( "usage : %s lop(Left operand) op(Operator) rop(Right operand)\n", argv[0] );
exit ( 0 );
}

// 引数を整数型に変換
lop = atoi ( argv[1] );
rop = atoi ( argv[3] );

// 引数の取得(配列中の先頭文字)
op = ( argv[2][0] );

// lopが整数であるか文字であるかのチェック
lop = strtol ( argv[1], &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' ) {
printf ( "error : Please input the integer\n" );
exit ( 0 );
}

// lopに範囲を超えた値が入力された場合
} else {
printf ( "error : The range of the int type is exceeded\n" );
exit ( 0 );
}

// ropが整数であるか文字であるかのチェック
rop = strtol ( argv[3], &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' ) {
printf ( "error : Please input the integer\n" );
exit ( 0 );
}

// lopに範囲を超えた値が入力された場合
} else {
printf ( "error : The range of the int type is exceeded\n" );
exit ( 0 );
}
if ( strlen ( argv[2] ) >= 2 ) {
printf ( "error : Please input the operator correctly\n" );
exit ( 0 );
}

// 演算子ごとに計算
switch ( op ) {
case '+' :
result = lop + rop;
break;

case '-' :
result = lop - rop;
break;

case '*' :
result = lop * rop;
break;

case '/' :
if ( rop == 0 ) {
printf ( "error : 0 division is a prohibition\n" );
exit ( -1 );
}

// 除算のオーバーフローを考慮
if ( ( lop == min ) && ( rop == -1 ) ) {
printf ( "error : The overflow learns by experience\n" );
exit ( 0 );
}
result = lop / rop;
mod = lop % rop;

// 割り算の結果として余りが出なかった場合
if ( mod == 0 ) {
printf ( "%lld %c %lld = %lld", lop, op, rop, result );
exit ( 0 );

// 割り算の結果として余りが出た場合
} else if ( mod != 0 ) {
printf ( "%lld %c %lld = %lld余り%lld", lop, op, rop, result, mod );
exit ( 0 );
}
break;

default:
printf ( "error : Please input either of operator '+', '-', '*', '/'\n" );
exit ( 0 );
}

// 加、減、乗算のオーバーフローを考慮
if ( ( result > max ) || ( result < min ) ) {
printf ( "error : The overflow learns by experience\n" );
exit ( 0 );
}

// 数値1 演算子 数値2 = 演算結果の形式で出力する
printf ( "%lld %c %lld = %lld", lop, op, rop, result );
exit ( 0 );
}
 
 

長くなってしまって申し訳ありません。



2倍のポイントを手に入れた! 3,882ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,404ポイント)   Date: 2007/05/22(火) 23:01   No:7842     
Title: Re:無題    
数値と演算子とを必ず空白で区切っているのであれば、
argv[] から取り出せますが、今行なおうとしているのは、
スペースがなくても(そして、あっても)
正しく計算できるようにすることですよね。

ということは、コマンドライン引数を使うのではなく、
fgets() か何かで1行分を取ってきて、
中にスペースがあったら無視して、
1文字ずつ見ていきながら数値と演算子に分けて、
スタックに格納しながら計算していく、という必要があるのではないでしょうか。


190ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(333,815ポイント)   Date: 2007/05/23(水) 00:13   No:7843     
Title: Re:無題    
コマンドラインから行う方がよけいに面倒な処理になると思います。
どうしてもコマンドラインから行いたいなら複数にわかれている文字列を一度全部ひとまとまりにした方がいいかもしれません。

カッコを含むスタックを個別に用意する方法がよくわからないので、boxさんの方がずっといい回答をなさると思うのですが、
私は上記方法がダメなら、一つずつ個別に判定していく方法しか思いつきません、すみません(_ _|||)


191ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(15,822ポイント)   Date: 2007/05/23(水) 00:52   No:7847     
Title: Re:無題    
管理人さん。boxさん。レスありがとうございます。

<スペースがなくても(そして、あっても)
これはスペース無しだけの場合ならコマンドライン引数を
取得する方法で可能なのでしょうか?

<コマンドラインから行う方がよけいに面倒な処理になると思います
そうですよね。すごく大変そうです。明日もう一度確認してみますね。

<カッコを含むスタックを個別に用意する方法
私もこれを考えたのですが、どうコーディングしようか考え中です。

皆様の意見を参考にしながら、明日もう一度調べてみます。
そしてたぶんまた来ます(笑)

ちなみに、@〜Bまで一度に出来ればいいのでしょうけど、私には
難しそうなので、まずどの条件からクリアすればよいのかアドバイス頂ければ
幸いです(もしくは一度にやった方がよいのでしょうか?)
よろしくお願いします。


332ポイント を手に入れた。

Name: Justy  ..ハッカー(103,859ポイント)   Date: 2007/05/23(水) 01:27   No:7849     
Title: Re:無題    
多倍長整数とは難しそうですが
 たしかに多倍長整数を効率よく処理するルーチンをいきなり書くのは大変かもしれませんが、
多少効率を無視していいのなら比較的簡単です。

 小学校の頃に加減乗除の筆算って習いませんでしたか?
 加算なら縦に2つの数字を並べて下の桁から1桁ずつ対応した桁同士を処理し、
溢れたら溢れた分を次の桁に、ってアレです。

 アレをそのままプログラムに落とし込めば・・・40桁限定なら、10進数での桁数、
各桁の数字(40個の配列)、符号の情報を構造体にして管理すればかなり簡単に
多倍長整数を扱えるはずです。



引数については結合か結合
 どちらかといったら結合の方がいいかもしれませんね。
 ついでにスペースやタブなどの空白が含まれていたら削りながら
結合すると、必要な式の部分だけが残ってより解析しやすくなるはずです。



スペース無しだけの場合ならコマンドライン引数を取得する方法で可能なのでしょうか?
 式が入っている引数の数の分だけ文字列を結合するのが面倒であれば、
最悪、コマンドラインから与える式を ""(ダブルクォーテーション)で囲めば1つの
引数として式が main関数に入ってきますよ。


@〜Bまで一度に出来ればいいのでしょうけど
まずどの条件からクリアすればよいのか
 んー、私なら、

1 まず本当にコマンドラインから式を受け取る必要があるのかどうか
 必要があるなら、コマンドライン引数から文字列の結合を行い式を組み立てる。
 必要がないなら、適当にユーザーに入力させる
 
2 桁数の問題

3 最後に括弧を含む式の解析。

 ですね。


719ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(15,897ポイント)   Date: 2007/05/23(水) 10:08   No:7852     
Title: Re:無題    
Justyさん。レスありがとうございました。

大変参考になりました。出来るか不安ですが
とにかくやってみます。ありがとうございました。

管理人さん。boxさん。Justyさん。
お礼を忘れていました。すみませんでした。


75ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(15,963ポイント)   Date: 2007/05/23(水) 13:45   No:7855     
Title: Re:無題    
お世話になっております@とんぷぅ〜です。やはりコマンドラインから
式を受け取る必要があり、スペース有りor無しの場合でも計算できるように
しないといけないみたいです^^;



66ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,507ポイント)   Date: 2007/05/23(水) 13:58   No:7856     
Title: Re:無題    
ということは、コマンドライン引数で受け取った文字列から
スペースを取り除いた形で1つの文字列にまとめ、
その文字列を1バイトずつ見ていき、
 ・'0'〜'9' の場合
 ・'+', '-', '*', '/' の場合
 ・'(', ')' の場合
 ・その他の文字の場合
に分けて考えていけばよいと思います。


103ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(16,011ポイント)   Date: 2007/05/23(水) 14:06   No:7857     
Title: Re:無題    
boxさんレスありがとうございます。

<スペースを取り除いた形で1つの文字列にまとめ
すみません。この部分の意味が理解できません。どう
いったことなのでしょうか?


48ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,601ポイント)   Date: 2007/05/23(水) 14:14   No:7858     
Title: Re:無題    
<<スペースを取り除いた形で1つの文字列にまとめ

失礼しました。当方が勘違いしておりました。
複数のコマンドライン引数に分かれている文字列群には
スペースを含みません。
というわけで、sprintf()あたりを使って、単純に結合すればよいです。


94ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(16,105ポイント)   Date: 2007/05/23(水) 14:25   No:7859     
Title: Re:無題    
boxさん。度々ありがとうございます。

<sprintf()あたりを使って、単純に結合すればよいです。
sprintfで結合した場合、以下のような結果を求められる
ということですよね?

例.コマンドラインから受け取った引数が 1 * 2の3つの場合

引数に空白無し
ファイル名.exe 1*2 = 2

引数に空白有り
ファイル名.exe 1 * 2 = 2


94ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,858ポイント)   Date: 2007/05/23(水) 15:15   No:7860     
Title: Re:無題    
何だか話がちぐはぐになってきた気がしています。

>コマンドラインから受け取った引数が 1 * 2の3つの場合

3つ、つまりargv[1]〜argv[3]に受け取ったということは、
1と*と2の間にそれぞれスペースがあった、ということです。
したがって、

>引数に空白無し
>ファイル名.exe 1*2 = 2

こちらのケースはありません。

>引数に空白無し
>ファイル名.exe 1*2 = 2

こうなるのは、1と*と2を続けて(スペースを空けずに)書いたときで、
この場合、argv[1]に"1*2"という内容を格納しています。


1と*と2の間にそれぞれスペースを空けて書いたのなら
argv[1]〜argv[3]の3つを結合して最終的に"1*2"という文字列を
組み立てればよいです。
一方、1と*と2をスペースなしに書いたのなら、
見るべきところはargv[1]だけなので、最初から"1*2"という文字列を得ています。

いずれにせよ、argv[1]〜argv[n]のn個(nは1以上)の文字列を結合して
数式の文字列(途中にスペースがない)を得ればよいのです。
その後、文字列の中身の解析を行ないます。


257ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(16,973ポイント)   Date: 2007/05/23(水) 16:54   No:7862     
Title: Re:無題    
boxさんありがとうございました。

<1と*と2の間にそれぞれスペースを空けて書いたのなら
argv[1]〜argv[3]の3つを結合して最終的に"1*2"という文字列を
組み立てればよいです。

これはコマンドライン引数をargv[1]〜argv[3]まで取得したという
ことですよね?それなら結合しなくても結果は出るのではないでしょうか?
どうしても結合するということが理解できません。

<いずれにせよ、argv[1]〜argv[n]のn個(nは1以上)の文字列を結合
して数式の文字列(途中にスペースがない)を得ればよいのです。

コマンドライン引数を取得して実行する方法は普通、プロンプトで
引数にスペースを空けて行いますよね? 例 1 + 1
それが引数にスペースを空けないで実行するということが
やはり引っかかってきます。 例 1+1

1 + 1の場合は引数がargv[1]〜argv[3]に格納されていることは
理解できるのですが、1+1の場合は一つの文字列としてargv[1]のみ
に格納されているといった考えでよいのでしょうか?
もしその考えが合っているならば、引数のチェック(この場合だと)
if ( argc != 4 ) {
printf ( "usage : %s lop(Left operand) op(Operator) rop(Right operand)\n", argv[0] );
exit ( 0 );
}
この部分からおかしいということなのでしょうか?
混乱してきました。知識不足で申し訳ありません。
文章がおかしい部分も多々あると思いますが、よろしくお願いします。



2倍のポイントを手に入れた! 868ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,934ポイント)   Date: 2007/05/23(水) 17:13   No:7864     
Title: Re:無題    
このスレッドの最初の投稿で、
「スペースを入れなくても計算できるようにしたい」旨
書かれていますね。
これと、

>それが引数にスペースを空けないで実行するということが
>やはり引っかかってきます。 例 1+1

これとは矛盾していませんか?
結局どうしたいのでしょうか?


76ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(17,051ポイント)   Date: 2007/05/23(水) 17:40   No:7866     
Title: Re:無題    
boxさん。レスありがとうございます。

分かりにくくてすみません。結局引数で1+1 としても、1△+△1としても
四則演算出来るようにしたいです(この場合ならどちらも2になるようにしたいということです)
(△はスペースです。)




78ポイント を手に入れた。

Name: box  ..比類無きプログラマー(68,963ポイント)   Date: 2007/05/23(水) 20:37   No:7869     
Title: Re:無題    
> 結局引数で1+1 としても、1△+△1としても

ということでしたら、私の本日15:15の投稿の
最後の3行をもう一度ごらんください。


29ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(17,125ポイント)   Date: 2007/05/24(木) 00:18   No:7874     
Title: Re:無題    
管理人さんタイトル変更ありがとうございました。
タイトルつけるの忘れてました^^;

boxさんレスありがとうございます。
文字列の結合、解析あたりが理解できていないのですね。
ご指摘ありがとうございました。頑張ります〜。


74ポイント を手に入れた。

Name: Justy  ..ハッカー(103,380ポイント)   Date: 2007/05/24(木) 01:46   No:7876     
Title: Re:無題    
 @とんぷぅ〜さん、この課題は多分例によって上司の方に出されたものだと思うのですが、
この問題は少し敷居が高い感じがします。

 前と同じように新人研修の課題ですか?


>どうしても結合するということが理解できません
 もう既に理解されているかもしれませんが、一応簡単に。

 > xxxx.exe 1+3 (- 4 *-2 )

 この状態で実行すると
 
 argv[1] ・・・ "1+3"
 argv[2] ・・・ "(-"
 argv[3] ・・・ "4"
 argv[4] ・・・ "*-2"
 argv[5] ・・・ ")"

 という状態で main関数に文字列が渡ってきます。

 これを解析する場合、変数が複数に分かれているので、とても扱いづらい状態です。
(表示することを考えても5つもあると面倒ですよね? ましてや実行してみないといくつに
わかれているかはわからない)

 そこで、

combine[] ・・・"1+3(-4*-2)"

 とこのように1つの文字列にして纏めてしまえば、解析・表示が楽になる、
というわけです。
 これが文字列の「結合」です。



# ちなみに挙動としてはこんな感じですかね? (calc_test.exe)





07/05/24 22:32 バージョンアップ


479ポイント を落としてしまった。

Name: 管理人 [URL]  ..伝説のハッカー(334,599ポイント)   Date: 2007/05/24(木) 03:07   No:7878     
Title: Re:無題    
バイトで遅くなりました・・((グッタリ
お力になれず、すみません、、。

あ、コマンドラインの受け取った文字列達をまとめると言うのはJustyさんの仰ったとおりです。

コマンドラインの入力値を一つの文字列にまとめるプログラムのサンプルだけお書きします。



#include <stdio.h>
#include <stdlib.h>
#define N 1000

int main( int argc , char *argv[ ] ){
int i,j,s=0;
char st[N];

for(i=1;i<argc;i++){
j=0;
while(argv[i][j]!=NULL)
st[s++]=argv[i][j++];
}

st[s]='\0';
printf("%s\n",st);

return 0;
}


実行結果

C:\test3\Debug>test3 (1+2) * (a /b - 1) /2.1 +1
(1+2)*(a/b-1)/2.1+1
 
 
省きましたけど途中に
 

if(s>=N){
printf("多すぎ");
exit(99);
}
 
 
とか実際は書いた方がいいと思います。

おやすみなさいませ・・zzZZ


308ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(17,372ポイント)   Date: 2007/05/24(木) 08:56   No:7880     
Title: Re:無題    
Justyさん。管理人さん。レスありがとうございました。

<前と同じように新人研修の課題ですか?
はい(。´Д⊂)今回は「今までより難しいよ」としっかり
言われておりました。まだポインタや構造体等etc理解出来て
いないので、Cのサイトと格闘中です。

結合について、具体的に書いていただきありがとうございました。
大変分かりやすかったです。

<バイトで遅くなりました・・((グッタリ
お疲れ様です。いつもお世話になってます。
サンプルありがとうございました。Justyさんにいただいた物も
含めて動かしてみます。


247ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(334,862ポイント)   Date: 2007/05/24(木) 09:37   No:7881     
Title: Re:無題    
あ、途中配列要素数の所に++使っている部分が解り難かったかも知れませんので、
補足です。
以下を見てもらえたら解るとおり、i++は値が評価された後で1増やす。
++iはまず最初に1増やすと言う事です。
つまり、式の中で[i]とiを指定してその後、i++;と2行に分けて書くのと同じ事です。



#include <stdio.h>

int main(){
int i=0;
char st[]="123456";

printf("%c\n",st[i++]);
printf("%c\n",st[i++]);
printf("%c\n",st[i++]);
printf("%c\n",st[i++]);

return 0;
}

実行結果
1
2
3
4

#include <stdio.h>

int main(){
int i=0;
char st[]="123456";

printf("%c\n",st[++i]);
printf("%c\n",st[++i]);
printf("%c\n",st[++i]);
printf("%c\n",st[++i]);

return 0;
}

実行結果
2
3
4
5


 
 


263ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(17,564ポイント)   Date: 2007/05/24(木) 10:23   No:7886     
Title: Re:無題    
管理人さん。レスありがとうございました。

「i++」は、iが評価されてからインクリメント
「++i」は、インクリメントされてからiが評価

この違いなのですね、基本ですがおろそかにしていました。
こういう細かい所も大変勉強なります。ありがとうございます。


2倍のポイントを手に入れた! 192ポイント を手に入れた。

Name: Justy  ..ハッカー(103,294ポイント)   Date: 2007/05/24(木) 13:40   No:7903     
Title: Re:無題    
はい(。´Д⊂)今回は「今までより難しいよ」としっかり 言われておりました
 今時の新人研修はここまでやりますか・・・。
 このレベルの課題は2,3年目くらいにならないと、なかなか作れるものじゃないですよ。

 多分上司の方は「どこまで作れるか」「どう解決しようとしたのか」「何かできないのか」を
見ているのでしょうね。


167ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(17,834ポイント)   Date: 2007/05/24(木) 13:49   No:7904     
Title: Re:無題    
>多分上司の方は「どこまで作れるか」「どう解決しようとしたのか」「何かできないのか」見ている
 思い通りに動くようになったら、コードを1文ずつ説明して、
 どんな考えで作ったのか報告しなければならないので、
 恐らくそういうことを見ているのだと思います。

まあ正直しんどいですが、頑張ります〜。Justyさん。これからもよろしくお願いします。


126ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(17,957ポイント)   Date: 2007/05/24(木) 15:11   No:7905     
Title: Re:無題    
すみません。管理人さんのコードで分からない
部分があるのですが、コメントをいただけない
でしょうか?

for(i=1;i<argc;i++){

j=0;

while(argv[i][j]!=NULL)

st[s++]=argv[i][j++];

}

上記のwhile部分が具体的にどう連結に結びつくのでしょうか?
あとst[s]='\0';配列をヌルを入力しているのはなぜなのでしょうか?
よろしくお願いします。


123ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(337,485ポイント)   Date: 2007/05/24(木) 15:20   No:7906     
Title: Re:無題    

例えば今、
int a[10];
で宣言すると、初期化をしていないので、中身はゴミが入っていますね。

[0] [1] [2] [3] [4]............
--------------------------..........
|  |  |  |  |  |..........
--------------------------..........



--------------------------
|ゴミ|ゴミ|ゴミ|ゴミ|ゴミ|
--------------------------

a[0]='a';
a[1]='b';
a[2]='c';

と代入すれば

[0] [1] [2] [3] [4]
--------------------------
| a | b | c |ゴミ|ゴミ|
--------------------------

こんな感じになります。
コンパイラは入っているものがゴミなのか、代入した値なのかわかりませんから、
%s(終端記号までの文字列を表示せよ)で表示すると、終端記号まで探して表示しますから、ゴミまで表示されます。
ですから'c'を代入したところで文字列を終わりにしたいならちゃんと終端記号をいれてやらないと

a[3] = '\0';
[0] [1] [2] [3] [4]
--------------------------
| a | b | c | \0 |ゴミ|
--------------------------

文字列がどこまでなのかわかりません。
今回は%sで表示すると、[2]までの値が表示されるはずです。

文字列の最後には必ず終端記号が必要です。

char a[10]="abc";

と宣言してもちゃんとコンパイラがa[3]='\0';してくれているので、きちんと表示できるのです。
終端記号をいれずに表示してみてください。ゴミも表示されるはずです。
 
 


658ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(337,743ポイント)   Date: 2007/05/24(木) 15:29   No:7907     
Title: Re:無題    
サンプルです。


#include <stdio.h>

void main(){
int i;
char a[32];
a[0]='a';
a[3]='b';
a[7]='c';
printf("%s",a);
// for(i=0;i<32;i++)
// printf("%d-%d\n",i,a[i]);
return ;
}

実行結果

ab@"@cfH北P@


 
 
こちらの環境では[0][3][7]にたまたまNULLが入っていたので、他の値に書き換えました。
表示不可能な意味不明文字になります。
コメントアウトをはずすことで、最初どんな値が入っているか確認できます。


258ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(337,788ポイント)   Date: 2007/05/24(木) 15:31   No:7908     
Title: Re:無題    
argcとargvの仕組みについては理解していますか?コマンドラインの入力文字がどのように格納されるか理解していますか?

45ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(337,798ポイント)   Date: 2007/05/24(木) 15:43   No:7909     
Title: Re:無題    
argvは2次元配列だと思って、そのそれぞれにスペースで区切った文字列が入るイメージを思い浮かべればいいです。


test.exe (3+ 1)/23-9 + 41*2

char argv[5][10];

strcpy(argv[0],"test.exe");
strcpy(argv[1],"(3+");
strcpy(argv[2],"1)/23-9");
strcpy(argv[3],"+");
strcpy(argv[4],"41*2");

 
 
実際こうではないですが、こういうイメージです。
ん〜逆にややこしいですかね。

まぁとにかく

argv[1] [2] [3] [4]
"(3+" , "1)/23-9" , "+" , "41*2"

にわかれている文字列を

st
"(3+1)/23-9+41*2"

にしたいんです。
で、

st[0] = argv[1][0];

をすると "(" が入るのはわかりますよね?argv[1][1]は "3" argv[1][2]は "+" argv[1][3]はヌルです。
これがヌルではない間コピーします。すると最初の文字列がコピーできます。
stに入れた添え字はそのままに、次に新しい文字列 "1)/23-9" を格納すると連続してコピーできます。
それを最後までコピーしていって、最後にヌル文字いれれば全部コピー完了した文字列の出来上がりです。

 
 


10ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(18,053ポイント)   Date: 2007/05/24(木) 18:31   No:7916     
Title: Re:無題    
管理人さん。レスありがとうございました。

argc、argvについて細かく調べた所、より理解が深まりました。
ただ、奥が深かったのでもう少し、ポインタ、配列、文字列の絡みを学習してきます。
特に多次元配列になるとテンパってしまって(汗)

p.s Justyさんが配布してくれたプログラムのような
動きに少しでも近づけるように頑張ります。






96ポイント を手に入れた。

Name: Justy  ..ハッカー(103,746ポイント)   Date: 2007/05/24(木) 22:42   No:7921     
Title: Re:無題    
思い通りに動くようになったら、コードを1文ずつ説明して、
 うわー、それはキッツイですね。
 それじゃぁ、曖昧な部分があったら速攻で突っ込まれますからね、大変だ。


Justyさんが配布してくれたプログラムのような
動きに少しでも近づけるように頑張ります。
 計算結果しか出していないんで、どれだけ参考になるかわかりませんが、
@とんぷ〜さんのプログラムが完成した際の結果の検証くらいには使えるかと。


 あ、そうそう。
 ちょっとバグがあったので上のプログラムを更新してあります。 
 一見無限桁の演算ができるようにみえて、実は理論的に5万桁以上同士の乗算をしたときに
計算結果が希におかしくなる問題があったのでこっそり修正しました。

 まだ何か結果がおかしいようでしたら言って下さい。


452ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(18,432ポイント)   Date: 2007/05/24(木) 23:44   No:7922     
Title: Re:無題    
Justyさんレスありがとうございました。

<ちょっとバグがあったので
そうなんですか!Justyさんのような方でも
バグがあるんでしたら私は。。。(笑)
更新ありがとうございました<(_ _)>


89ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(338,634ポイント)   Date: 2007/05/25(金) 01:06   No:7925     
Title: Re:無題    
2次元配列になったからといって特に難しい事はないですよ。
配列の先頭アドレスが[0]から順に入っていった配列が上にもう一つあるということです。

char st[4][10]={
{"abcdef"},
{"ghijkl"},
{"mnopqr"},
{"stuvwx"}
}

 
 
st[0]は"abcdef"をさしていて、
st[1]は"ghujkl"をさしています。
st[0][0]は'a'をさしていて、
st[2][1]は'n'をさしています。

理論は難しくなくてもなれていないと難しく感じるものですよね。
要は慣れですので、とにかく色んな配列のサンプルを実行したり、
自分でプログラムを書いてドンドンコンパイルする事が一番だと思います。
頑張ってください。


226ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(18,798ポイント)   Date: 2007/05/28(月) 10:52   No:8014     
Title: Re:無題    
管理人さん。レスが遅れて申し訳ありませんでした。

質問があるのですが、例えば1+1として(スペース無し)の場合
argv[1]に1+1が入っているので、その文字列を解析して、数値なら
'1'と'+'と'1'という具合に解析をして計算させれば良いのでしょうか?

解析が出来ず、困っています。isdigit関数などを使用して数値かの
判別をすれば良いのでしょうか?質問ばかりで申し訳ありませんが
よろしくお願いします。


2倍のポイントを手に入れた! 366ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(348,114ポイント)   Date: 2007/05/28(月) 13:16   No:8015     
Title: Re:無題    
1文字ずつ調査すればいいのではないでしょうか?
例えば
argv[1][0]には今「1」が入っていますよね?
argv[1][0+1]には「+」が入っています。
この数字と文字を分けたいということなんですよね?

現在調査している要素が文字なら、そこで調査を一時停止して、そこまでを一つの文字列とし、
atoiなどを用いて文字を数値に変換します。

調査を開始して、次は文字のはずですから、1文字とってきて演算子として記憶する、次はカッコか数値のはずですからそれ以外ならエラー、などではどうでしょうか?

つまり、今

char st[]="123+456*-";

こんな文字列が入っているとします。

st[0]を調査、数値なので、次へ
st[1]を調査、数値なので、次へ
st[2]を調査、数値なので、次へ
st[3]を調査、記号なので[2]までを一つの文字列として、その文字列を数値に変換。どこかへ保存。
st[3]は演算子としてどこかに保存。
(st[4]はカッコか数値のはず。)
st[4]を調査、数値なので、次へ
st[5]を調査、数値なので、次へ
st[6]を調査、数値なので、次へ
st[7]を調査、記号なので、[6]までを一つの文字列として、その文字列を数値に変換。どこかへ保存。
st[7]は演算子としてどこかに保存。
(st[8]はカッコか数値のはず。)
st[8]を調査、カッコでも数値でもないのでエラー終了。

こんな感じでどうでしょう?


417ポイント を手に入れた。

Name: Justy  ..ハッカー(104,170ポイント)   Date: 2007/05/28(月) 13:39   No:8016     
Title: Re:無題    
# @とんぷぅ〜さんへ
例えば1+1として(スペース無し)の場合
argv[1]に1+1が入っているので、その文字列を解析して
 argv[2]以降に一切「式」が入っていないことが保証できるのであれば、argv[1]を解析してください。


数値なら '1'と'+'と'1'という具合に解析をして計算させれば良いのでしょうか?
 基本的にはそうです。
 ただ、括弧付きを扱うのであれば計算の順番を正しく判定する必要があります。



isdigit関数などを使用して数値か判別をすれば良いのでしょうか?
 数値かどうかなら yes。



# 管理人さんへ
?st[8]を調査、カッコでも数値でもないのでエラー終了。
 式が "123+456*-"ならエラーになりますが、"123+456*-5"ならエラーにはならないですよね?


354ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(348,274ポイント)   Date: 2007/05/28(月) 14:18   No:8017     
Title: Re:無題    
Justyさん、
-5をかけるとき、
a*(-5)とかかないと数学的な式としておかしくないでしょうか?
私は数式でマイナスを書けるとき必ず括弧を書きますけど、省略できるんです?
しかし数学的な式として入力するなら
2a
という入力もありにしないといけなく・・。
どこまで実現するべきかは仕様によりますね。
もし*-という連続を許すならそこのエラー処理は必要ないと思います。


160ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(19,138ポイント)   Date: 2007/05/28(月) 14:31   No:8018     
Title: Re:無題    
管理人さん。Justyさん。お世話になっております。

>argv[1][0+1]には「+」が入っています
この[0+1]というのはどういうことなのでしょうか?

>この数字と文字を分けたいということなんですよね?
はい。数字であるならatoiなどで、数値に変換して計算
可能な状態にするようにしたいです。

>argv[2]以降に一切「式」が入っていないことが保証できるのであれば、argv[1]を解析してください。
今回は引数が最大でも4つになる( 1 + 1 = 2 )ので、スペースを入れない場合argv[1]のみになります。
(考え方が間違っていたらすみません)

>括弧付きを扱うのであれば計算の順番を正しく判定する必要があります。
今のところまず、括弧や桁数を意識しないで、スペース有りor無しで普通に
四則演算が出来るコードを書いてみようと思います。

ちなみに2007/05/22(火) 22:07でのコードを元に作成しているのですが、
コードを根本的に変えていかなければならないのでしょうか?

ちなみに解析で文字列を読み込む際に、コマンドライン引数から読み込む
ことは可能なのでしょうか?getcharなどを読み込みに使うと入力待ちに
なってしまう為、よろしくないです。

長々となってしまい申し訳ありません。よろしくお願いいたします。


340ポイント を手に入れた。

Name: 管理人  ..伝説のハッカー(348,521ポイント)   Date: 2007/05/28(月) 14:44   No:8020     
Title: Re:無題    
キーボードからの入力を必要としないならgetcharは必要ないでしょう。
もうすでに配列に文字列がはいっているのですから、配列要素を一つずつ調べたら同じ事です。
コマンドラインから可能かという質問は前にもお答えしましたよね?
複数にわかれた文字列を一つにするプログラムのサンプルもお書きしたと思います。
括弧なしの計算なら簡単です。
私の書いたスタックに合うように文字列をおいてやればいいだけです。
しかし括弧つきに応用が出来ませんから、もし括弧を実現すべきなのなら1からほかの考え方で作ったほうがよさそうです。
すみませんが、私には括弧つき計算でいい方法が思いつきません。


230ポイント を手に入れた。

Name: Justy  ..ハッカー(104,446ポイント)   Date: 2007/05/28(月) 15:04   No:8021     
Title: Re:無題    
# 管理人さん
私は数式でマイナスを書けるとき必ず括弧を書きますけど、省略できるんです
 一応省略しても「式」的には正しく読みとれそうですが。

 たしかに言われてみれば "3*(-5)"では省略はしない方がいいのかもしれませんね。
 でも "-5*3"の時は省略しますね。
 う〜む。この場合も括弧つけた方がいいでしょうか。"(-5)*3"みたいに

 あとは()の前に付く場合ですね。 "4 * -(1 + 5)"とか。


>どこまで実現するべきかは仕様によりますね
 ですね。



# @とんぷぅ〜さん
括弧や桁数を意識しないで、スペース有りor無しで普通に
四則演算が出来るコードを書いてみようと思います
 つまり括弧はなし、桁数はlong longの範囲で、スペースの有無はどちらでも、ということですね。


コードを根本的に変えていかなければならないのでしょうか
 最終的なコードは大幅に異なるものになりそうです。
 が、上記の条件(括弧なしとか)であれば延長線上でいけそうな気がします。


コマンドライン引数から読み込む ことは可能なのでしょうか?
 今までどこから読み込んでいたのでしょうか?


276ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(19,526ポイント)   Date: 2007/05/28(月) 15:50   No:8023     
Title: Re:無題    
管理人さん。Justyさん。レスありがとうございます。

>もうすでに配列に文字列がはいっているのですから、配列要素を一つずつ調べたら
はい。その通りなのですが、その「調べる」ということが理解出来ておりません。
何が分かっていないからなのでしょうか?


>私の書いたスタックに合うように文字列をおいてやればいいだけ
スタックについてのサンプルありがとうございました。しかし今回
どうしても、自分でコーディングしたソースを元に作りたいのです。
(スペース有りor無しだけについて)


>コマンドライン引数から読み込む ことは可能なのでしょうか?
すみません。コピペでミスをしてしまいました。意味不明なことを
言ってすみませんでした。


>つまり括弧はなし、桁数はlong longの範囲で、スペースの有無はどちらでも、ということですね。
はい。そういうことになります。


>どこまで実現するべきかは仕様によりますね
明記するのを忘れておりました。すみません。
今回は 1 + 2 - 3などの3項演算?はしないので、括弧による優先順位は関係ありません。
括弧をつける基準としては入力された数値が負数の場合は括弧で括るということだけで大丈夫です。


>数値かどうかなら yes
isdigitを使ってargv[1]に入っている文字列を解析しようと
思ったのですが、中々上手くいきません。。


こんなに有用な意見を頂いているのにやりたいことがパッと出てこない為、
皆様に大変迷惑を掛けてしまってすみません。



388ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(348,887ポイント)   Date: 2007/05/28(月) 18:24   No:8027     
Title: Re:無題    
すみません、ちょっと忙しくてお返事がちまちまになりそうです。

>しかし今回どうしても、自分でコーディングしたソースを元に作りたいのです。

人のプログラムを理解するのは大変ですし、自分で書いたほうが力になるので出来ることならそちらがいいと思います。
アルゴリズムはどのように考えています?
スタック使うのでしょうか?

> 1 + 2 - 3などの3項演算?はしないので

という意味がよくわからなかったのですが、今単純に「1+2」とか「3*2」とか3つ以上の数値は入力しないということなのでしょうか?(そんな簡単な事じゃないですよね^^;

>こんなに有用な意見を頂いているのにやりたいことがパッと出てこない為、皆様に大変迷惑を掛けてしまってすみません。

具体的なアドバイスが出来ていないので、わからなくても仕方ないと思いますし、遠慮なく情報交換しましょう。
結構最初の仕様を実現するのは難しいように思います。


162ポイント を手に入れた。

Name: Justy  ..ハッカー(104,605ポイント)   Date: 2007/05/28(月) 18:42   No:8033     
Title: Re:無題    
>括弧をつける基準としては入力された数値が負数の場合は括弧で括るということだけで大丈夫です。
 なるほど、そこまでシンプルになれば相当簡単になりますね。
 スタックも不要ですね。

 2007/05/22(火) 22:07のソースから改良する、ということでしたが
この規模まで小さくなったら1から書き直した方が早そうな気もします。

 スペース有りor無しでも動くように、文字列の結合から着手してみてはどうですか?


>isdigitを使ってargv[1]に入っている文字列を解析しようと思ったのですが、中々上手くいきません
 どううまくいかないのでしょうか。


159ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(19,803ポイント)   Date: 2007/05/28(月) 20:53   No:8037     
Title: Re:無題    
管理人さん。Justyさん。レスありがとうございます。

"管理人さん"

>今単純に「1+2」とか「3*2」とか3つ以上の数値は入力しないということなのでしょうか?
はいそうです。こんなことで質問して申し訳ありません。
ちょっと課題が難しいのでまずここからやってみてっていう感じになりました。

>結構最初の仕様を実現するのは難しいように思います。
そうですね〜。最終的には最初の仕様になると思います。

"Justyさん"

>スペース有りor無しでも動くように、文字列の結合から着手してみてはどうですか?
こちらは管理人さんから頂いたサンプルを使用しているのですが、単純に
sprintf ( str, "%s", argv[1] )等でも良いのでしょうか?はたまたstrcat等を
使用するのか?その辺が疑問です。

>isdigitとargvでは型が違うので、上手くいかずに困っています。argvに入っている
文字列を1文字ずつ確認するには違う関数を使うのでしょうか?もしくはargvに入っている
文字列を切り出してから、1文字ずつ解析を行うのでしょうか?トークンあたりを調べて
みたのですが、あまり理解出来ませんでした。

長々失礼しました。


277ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(349,179ポイント)   Date: 2007/05/28(月) 21:00   No:8038     
Title: Re:無題    
とんぷ〜さんの回答を拝見するに、ちょっとトークンなどのライブラリ関数を用いずに、
文字列と配列、アドレスや文字コードなどの勉強もかねて、配列1つ1つを操作するプログラムを書いた方がいいように思います。
ライブラリ関数を用いるより自分で配列の内容を確認しながら作っていった方が仕組みがよくわかりますしね。

ちょっと戻って1から基本を見つめなおしましょう。
文字列というものは配列要素[0]から'\0'が入っている配列要素までをひとまとまりとするとかその辺の事をしっかりおさらいしてください。
きっと基本があやふやだと応用を効かせようとしたとき無理が来てわからなくなってしまうと思いますので。

では
「1+1」
が文字列として存在するとき
「1」「+」「1」にわけて2次元配列に格納する事から始めましょう。
単純に四則演算だけならすごく簡単ですから。


292ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(349,551ポイント)   Date: 2007/05/28(月) 21:14   No:8040     
Title: Re:無題    
サンプルを書きました。
入力はスペース無しで2つの値の四則計算のみという条件です。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void main(void){

int i=0,x[3];
char st[]="1+1",c;

while(st[i]!='\0'){
if( !(st[i]>='0' && st[i]<='9') ){
c=st[i];
st[i]='\0';
x[0]=atoi(st);
x[1]=atoi(&st[i+1]);
break;
}
i++;
}

printf("%d %c %d = ",x[0],c,x[1]);

switch(c){
case '+': x[2]=x[0]+x[1]; break;
case '-': x[2]=x[0]-x[1]; break;
case '*': x[2]=x[0]*x[1]; break;
case '/': x[2]=x[0]/x[1]; break;
}
printf("%d",x[2]);
}

実行結果

1 + 1 = 2


 
 


372ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(350,060ポイント)   Date: 2007/05/28(月) 21:24   No:8041     
Title: Re:無題    
 

st
|-[0]---[1]---[2]---[3]--|
| 1 | + | 1 | \0 |
|------------------------|

stの中身は上のような配置になっています。

while(st[i]!='\0'){

で終端記号を見つけるまで順に配列の中身を調査していきます。
まず[0]です。

if( !(st[i]>='0' && st[i]<='9') ){

という意味は今調査している配列要素の中身が文字コード「0」から「9」までの間ではなかったら
と言う意味です。数字か数字じゃないかという事ですね。
今回はスペースなし、記号は四則演算子しか入らないという条件の元これで可能です。

今[0]は「1」ですから条件にマッチせず、i++により[1]に調査対象が移動します。

[1]は「+」ですからif文の条件にマッチします。

c=st[i];

これでcに演算子を格納します。

st[i]='\0';

これにより、演算子までを一つの文字列として区切ります。
ただ今以下のようになっています。

st
|-[0]---[1]---[2]---[3]--|
| 1 | \0 | 1 | \0 |
|------------------------|

stと書くと[0]のアドレスの事です。&st[0]は配列の先頭アドレスで、文字列は[0]から始まり[1]で終わる文字列です。
一方文字列というのは示したアドレスから進んで終端記号が見つかるまでのひとまとまりですから、
[2]のアドレスを示せば、[2]から[3]までの文字列が示せる事になります。
ですから

x[0]=atoi(st);
x[1]=atoi(&st[i+1]);

で、それぞれ2つの値が格納できる事がわかりますか?stと書いてありますが、
x[0]=atoi(&st[0]);

x[0]=atoi(st);
は同じ意味です。

break;

で処理を抜けます。
後は条件によって計算し、表示しているだけです。
おわかりになるでしょうか。

変にライブラリ関数を使うより配列の扱い方を勉強しながら順々に作ってみてはいかがでしょうか。
仕組みを理解しながら作っていった方が応用が効く様に思います。

また、サンプルの文字列はいろいろ変更してみて確認してください。

例)
char st[]="4358-358";

実行結果

4358 - 358 = 4000


 
 


509ポイント を手に入れた。

Name: Justy  ..ハッカー(104,976ポイント)   Date: 2007/05/28(月) 22:11   No:8052     
Title: Re:無題    
単純にsprintf ( str, "%s", argv[1] )等でも良いのでしょうか?
はたまたstrcat等を 使用するのか?その辺が疑問です。
 後者の方が判りやすいとは思いますが、どちらでもOKです。


isdigitとargvでは型が違うので、上手くいかずに困っています。
argvに入っている文字列を1文字ずつ確認するには違う関数を使うのでしょうか?
 その関数で合ってますよ。
 
#include	<stdio.h>

#include <string.h>
#include <ctype.h>

int main(int argc, char *argv[])
{
if(argc >= 2)
{
size_t n, length;
const char *p = argv[1];
length = strlen(p);
for(n=0; n<length; ++n)
{
char c = p[n];
printf("%d文字目は [%c] ... ", n+1, c);
if(isdigit(c))
printf("%s\n", "数字");
else
printf("%s\n", "数字以外");

}
}
return 0;
}


 argv[1]の中を1文字1文字解析して、数字かそれ以外かを判定しています。
 一応 isdigit(c)という形にまとめましたが、cは p[n]なので、isdigit(p[n])としても
isdigit(argv[1][n])としても正しく動くはずです。


371ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,009ポイント)   Date: 2007/05/29(火) 16:51   No:8074     
Title: Re:無題    
管理人さん。Justyさん。レスありがとうございました。
ネットにトラブルがあり、レスが大変遅れて申し訳ありません。

"管理人さん"

>ちょっと戻って1から基本を見つめなおしましょう。

そうですね。今まで行き当たりバッタリで課題を行っていたので、
苦手と思う部分や、面倒と思う所を省いていました。今ままで配列にアクセス
するコードを書いた機会があまり無く、配列とループのセットが苦手なことが分かりました。
得に添え字が変数に置き換えられた多次元配列とループなどが、ソースを見てもパッと理解
することが出来ません。

ちなみに配列名は配列の先頭要素のアドレスを指すという部分なのですが
st[0]なら0のアドレスを指すということは分かります。ではargv[1][0]ならば
argv[1][0]のアドレスを指すのでしょうか?それともargv[0][0]?
すみません。テンパってきました。ただ管理人さんの説明のおかげで上記サンプル
はなんとか理解できました。


"Justyさん"

>const char *p = argv[1];

この1行はどういった意味なのでしょうか?
それと、よく見かけるsize_t型についてなんですが、一体
どのような場合に使われるんでしょうか?


ちなみに今現在の仕様なら、文字列を連結せずに
出来るような気がするのですが無理ですか?
(スペース有りなら今までのソースを元にして、無しなら
argv[1]に入っている文字列を文字に分けて解析して数値ならば)
という具合です。おかしい部分があったら言って下さい。



2倍のポイントを手に入れた! 1,206ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(353,344ポイント)   Date: 2007/05/29(火) 17:40   No:8075     
Title: Re:無題    
>st[0]なら0のアドレスを指すということは分かります。

いえ、違います。st[0]のアドレスは&st[0]で示せます。st[0]と書くと[0]自身のデータを示します。
char st[10];
などで宣言した配列を「st」と書くと&st[0]の意味になります。すなわちst配列の先頭アドレスです。
以下を見てください。



st[4]

st [0] [1] [2] [3]


st[3][4];

st[0]-> [0][0] [0][1] [0][2] [0][3]
st[1]-> [1][0] [1][1] [1][2] [1][3]
st[2]-> [2][0] [2][1] [2][2] [2][3]


 
 
上の1次元配列において、stと示すと[0]のアドレスを指します。
下の2次元配列において、

st[0]とさすと、st[0][0]〜st[0][3]までの1次元配列と考えられる配列の先頭アドレスすなわち&st[0][0]を指します。

st[1]とさすと、st[1][0]〜st[1][3]までの1次元配列と考えられる配列の先頭アドレスすなわち&st[1][0]を指します。

以下のように宣言すると、以下のように確保されます。


char st[4]="123";

|-[0]---[1]---[2]---[3]--|
| 1 | 2 | 3 | \0 |
|------------------------|

printf("%s",st);
と書くと「123」が表示されるのは、stが&st[0]をさしているからです。
つまりstの部分はそこから右をまとまりとしたいアドレスを書けばいいわけですから、
printf("%s",&st[2]);
こう書いてもいいわけです。
こうすると「3」が表示されます。

では応用で、2次元配列で考えて見ます。
2次元配列であろうと、3次元であろうと、配列は連続したアドレスに用意されます。
[0][0]の次のアドレスは[0][1]です。

char st[3][4];において

[0][3]の次のアドレスは[1][0]です。今

st[0][0]='a';
st[0][1]='b';
st[0][2]='c';
st[0][3]='d';
st[1][0]='e';
st[1][1]='\0';

で格納すると以下のように入ります。

|-[0][0]---[0][1]---[0][2]---[0][3]--|
| a | b | c | d |
|-[1][0]---[1][1]---[1][2]---[1][3]--|
| e | \0 | - | - |
|-[2][0]---[2][1]---[2][2]---[2][3]--|
| - | - | - | - |
|------------------------------------|
 
printfで示すアドレス先は特にどこでもいいのですから

printf("%s",&st[0][1]);

このように書けば「bcde」と表示されるはずです。
また、st[1]は[1]行目の1次元配列とみなせる配列の先頭アドレスですから、

printf("%s",st[1]);

こうかけば「e」が出力されます。


#include <stdio.h>

void main(){
char st[3][4];
st[0][0]='a';
st[0][1]='b';
st[0][2]='c';
st[0][3]='d';
st[1][0]='e';
st[1][1]='\0';

printf(" st[0] => %s\n",st[0]);
printf("&st[0][1] => %s\n",&st[0][1]);
printf(" st[1] => %s\n",st[1]);
}

実行結果

st[0] => abcde
&st[0][1] => bcde
st[1] => e

 
 
 
よくわからなければなんでもいいからとにかく疑問に思う表示の仕方やデータの入れ方をなんでもいいからつっこんでガンガンコンパイルしてみてください。
コンパイルした数だけ理解が深まるでしょう。


1,272ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,089ポイント)   Date: 2007/05/29(火) 17:51   No:8076     
Title: Re:無題    
管理人さん。レスありがとうございます。

なんかこう配列名は先頭要素のアドレスという言葉で
分かった気になってしまっていました。大変分かり易い
説明ありがとうございました。もっと多次元配列のコンパイル
をして理解を深めてみます。


80ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(353,375ポイント)   Date: 2007/05/29(火) 17:56   No:8077     
Title: Re:無題    
あ、あと型についてはこちらをご覧ください。
http://www.tamasoft.co.jp/lc/hlp/F029.html


31ポイント を手に入れた。

Name: Justy  ..ハッカー(106,429ポイント)   Date: 2007/05/29(火) 18:02   No:8078     
Title: Re:無題    
>const char *p = argv[1];
この1行はどういった意味なのでしょうか?

 argvの宣言は char *argv[]ですよね?
 これは char **argvと扱い的には同じになります。
 つまりポインタのポインタです。

 で、argv[1]としたとき、これ自体の型は char *となり、普通の charポインタとなります。
 でこのまま argv[1]として使い続けてもいいのですが、一端 argv[1]のポインタ値を
別の変数に入れた方が扱いやすいので、pという変数を用意して代入しています。

 どう扱いやすくなるかというと 例えば argv[1]じゃなくて、argv[2]の解析を
しようとか考えたとき、ソースのあっちこっちに argv[1]が散乱していたら
書き換えるのが面倒ですよね?

 そんなとき pに代入してあれば代入式の argv[1]を argv[2]に代えるだけで済みます。


 又、別の変数に入れる、ということはその代入元の方の変数に別の名前を付けるという意味も生まれます。
 サンプルでは pとしたので意味もへったくれもないですが、例えば

    const char *app_name = argv[0]

const char *exression_string = argv[1];

 としていたら、引数の名前の意味が
argv[0]・・・「1つ目の引数」という意味から app_name・・・「アプリケーション名」に
argv[1]・・・「2つ目の引数」という意味から exression_string・・・「式の文字列」になり

 見ただけで意味が分かりやすくなるという効果があります。


それと、よく見かけるsize_t型についてなんですが、
一体どのような場合に使われるんでしょうか?
 size_tはよく要素の数を表すのに使われます。

 例えば文字列の長さを調べる標準関数 strlen()ですが、戻り値に文字列の長さが返って来ます。
 しかし、戻り値の型は intではありません。size_tなのです。
 実際 size_tが何なのかは環境によって違いますが、大抵は unsigned intか unsigned longのようです。

 特に何もないのに積極的に size_tを使うことはありませんが、標準関数で size_t型が
指定されている場合はsize_t型を使った方がいいでしょう。

# sizeof()とかの結果の値も size_t型です。


ちなみに今現在の仕様なら、文字列を連結せずに 出来るような
気がするのですが無理ですか?
 スペースがあった場合となかった場合で、ソース(解析・計算部分)を分けると言うことですか?
 無理ではないと思いますが・・・。

 スペースはあってもなくても受け付けるということは
calc.exe 1 + 3

calc.exe 1 +3
calc.exe 1+3
calc.exe " 1 + 3"

  このどれもを受け付けなければなりません。
 もちろん、理論的には連結しなくてもできますが、ちょっとだけ面倒になります。


829ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,132ポイント)   Date: 2007/05/29(火) 18:03   No:8079     
Title: Re:無題    
早速のレスありがとうございます。typedefを使って定義されている型
とあったので、構造体が絡むんでしょうか?スミマセン。知識不足で
よく分かりませんでした。調べてみます。


43ポイント を手に入れた。

Name: Justy  ..ハッカー(106,520ポイント)   Date: 2007/05/29(火) 18:10   No:8080     
Title: Re:無題    
typedefを使って定義されている型とあったので、構造体が絡むんでしょうか
 とりあえず、size_tは要素の数を表現する型で、整数であるとだけ覚えておけば大丈夫です。


91ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,386ポイント)   Date: 2007/05/29(火) 18:29   No:8081     
Title: Re:無題    
Justyさん。レスありがとうございます。

>これは char **argvと扱い的には同じになります。
>つまりポインタのポインタです。

ポインタのポインタ。。。言葉を聞くと一瞬泣きそうになります(笑)

>もちろん、理論的には連結しなくてもできますが、ちょっとだけ面倒になります。

ですよね。回答ありがとうございました。

>例えばargv[1]じゃなくて、argv[2]の解析をしようとか考えたとき、
>ソースのあっちこっちに argv[1]が散乱していたら
>書き換えるのが面倒ですよね?

確かにあっちこっちに散乱してる場合は面倒ですね。

ちなみに、流れ的にはargv[1]〜argv[3]までを連結し、その上で
argv[]に入っている文字列を1文字ずつ解析し、数値なら式に沿って演算させる。
というふうな感じにすればいいんですよね?(こちらが質問者なのにすみません)



254ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(353,400ポイント)   Date: 2007/05/29(火) 19:57   No:8082     
Title: Re:無題    
>ポインタのポインタ。。。言葉を聞くと一瞬泣きそうになります(笑)

苦手意識をお持ちだという事が伝わってきますが、全然難しいものではないですよ。

例えば、ポインタとは目印だと思ってください。
データには目印がついていて、その目印をみればデータが取り出せると。

char **st;
で受け取ればポインタのポインタという事になりますが、
言い換えれば
目印が入った連続した箱の集まり、その集まりにさらに目印をつけたものの箱の集まり、ということです。

ポインタというのは言ってみれば配列です。

char a[]="1234";
とかいても
char *a="1234";
と書いてもいいことご存知でしょか。

上記両方ともaとかけばaのアドレスの事を示します。
2重ポインタということは、これらの配列の先頭アドレスを一つずつ格納した配列の集まりと言う事だと言い換えられます。
2重ポインタと2次元配列は同じではなく、意味は違うのですが、同じ意味も示す事が出来ます。

う〜ん、、言ってて余計にわからなくさせてしまったかな・・・。


25ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,634ポイント)   Date: 2007/05/29(火) 20:11   No:8083     
Title: Re:無題    
管理人さん。レスありがとうございます。

配列とポインタは似て非なるものと見ました。ポインタと
配列の決定的に違う部分というのは、本を見て分かったのですが
本当に理解したとは言えません(泣)

しかも本によっての解説が違うので今いちでした。


2倍のポイントを手に入れた! 248ポイント を手に入れた。

Name: Justy  ..ハッカー(106,732ポイント)   Date: 2007/05/29(火) 23:04   No:8089     
Title: Re:無題    
流れ的にはargv[1]〜argv[3]までをを連結
 argcの値によって変わりそうですが、基本的にその通りです。


><i>argv[]に入っている文字列を1文字ずつ解析し/i>
 argv[]に、というか連結して作った文字列に対して、ですね。


数値なら式に沿って演算させる
 yes.


167ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,813ポイント)   Date: 2007/05/29(火) 23:28   No:8091     
Title: Re:無題    
Justyさんレスありがとうございます。

>argcの値によってargv[1]〜argv[3]までをを連結
今回は2項演算までなので最大でもargv[3]までが引数に
なので、argcは最大で4になると思うのですが、考え方
は正しいでしょうか?

>argv[]に、というか連結して作った文字列に対してですね。
その通りですね。連結した文字列に対して1文字ずつ解析ですね。

しかし、自分のやりたいことをコードにするのは難しいですね。
この頃コンパイラに怒られてばかりです(笑)


179ポイント を手に入れた。

Name: Justy  ..ハッカー(106,899ポイント)   Date: 2007/05/29(火) 23:49   No:8092     
Title: Re:無題    
argcは最大で4になると思うのですが、考え方は正しいでしょうか?
 正しいです。


自分のやりたいことをコードにするのは難しいですね
 何かこう、プログラムの本質みたいなのが見えてくると、そのあたりはぐっと簡単になりますよ。
 その壁を越えるまでが大変ですけど・・・。



167ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,984ポイント)   Date: 2007/05/30(水) 00:01   No:8093     
Title: Re:無題    
Justyさん。レスありがとうございます。

>何かこう、プログラムの本質みたいなのが見えてくると、そのあたりはぐっと簡単になりますよ。
>その壁を越えるまでが大変ですけど・・・。

確かにそうですね。いつになれば自分で「コーディングした」っていう
感覚で仕事が出来るのか。。。。壁は高いです。。。。(( T_T)トボトボ



171ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(354,253ポイント)   Date: 2007/05/30(水) 01:02   No:8095     
Title: Re:無題    
ちょっと意欲低下してらっしゃるようなので気分転換のコメントでも^^;


@とんぷぅ〜さんはきっと現在「やらされているプログラミング」であったり、「しなければならないからやっているプログラミング」であるのではないでしょうか。そのために

なかなか思い通りに行かない・・(_ _|||)ズ〜ン

見たいな心境になってしまっているのではと思いますけど、プログラムを趣味で楽しいと思ってやっているとプログラムの見方が全然違ってきますよ。
昔ポインタが嫌いでした、構造体が嫌いでした、文字列処理が嫌いでした、自作関数がわかりませんでした。
しかしゲームをちょびちょび作っていく中でそこを嫌っていたらそれ以上の処理が出来ない事に気が付きました。
もっとよいゲームを作りたい、もっとコードを賢く書きたい、もっと効率よいコードが書いてみたい。
そんな思いで色々な単元を勉強していきました。
ちょっと勉強してはゲームを実装し、ちょっと勉強してはゲームを実装しました。
私は参考書をひたすら読んで勉強した覚えなど一度もありません。(だから基礎がなってないんだといわれたらそれまでデスガ^^;)
必要な時に調べては、コーディングするという繰り返しでした。
(そうするといつも知ってる知識内でしかプログラムコードをかかなくなってしまっていたので、意図的に他のアルゴリズムを勉強したりしたことはありましたが)

私はゲームをプログラムで作る事が楽しかったので、難しいな嫌だなと思う単元も、苦に思うことなく勉強できました。
というか趣味だったので、勉強という感じがありませんでした。
それに、きっと読むばっかりの勉強ではなく、それを勉強したらすぐにそれを使ってコーディングしたのが良かったのだと思います。
数学の教科書を1冊最初から最後まで読み通してわかった気になって、いざ教科書をひらかずに練習問題やろうとしたらさっぱりできなかったというのと同じように、
プログラムも演習によって身に付いていくものです。
また、「おもしろい!」と思えばそれに勝るものはありません。

プログラムのおもしろさを先に見つけ、プログラムの面白さを実感しながら、新しい単元を演習によって身につける道が最短コースだと思います。

((といってもシゴトとかで必要なのでしたらのんびりゲームなんて作ってる暇ないですかね^^;
もしどうしてもいやになったら、今勉強している範囲を利用して小さなゲームを作ってみたりアプリを作ってみたりして自分で学習意欲を出させる事も大事かと思います。
もし時間が出来たら色んな方向からプログラムをみつめてみてください☆

・・と偉そうな事を言ってみてもまだ私はプログラムのプの字もわかってないわけですが^^;


853ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(22,248ポイント)   Date: 2007/05/30(水) 09:33   No:8099     
Title: Re:無題    
管理人さん。レスありがとうございます。

<プログラムのおもしろさを先に見つけ、プログラムの面白さを実感しながら、
<新しい単元を演習によって身につける道が最短コースだと思います。

ですね。今は楽しむではなく、やらされている感が先行してしまいますね。
もっとこう自分で楽しく作れるようになるといいんですがw

<・・と偉そうな事を言ってみてもまだ私はプログラムのプの字もわかってない

いえいえそんなことはありません。管理人さんの説明は分かりやすいですし
私からみたら雲の上の存在です。まぁ私からすればここのサイト
にいる方が皆さんそうでしw


264ポイント を手に入れた。

Name: TT414  ..ぴよぴよ(96ポイント)   Date: 2007/05/30(水) 11:43   No:8100     
Title: Re:無題    
>どんな整数を入力しても計算結果が正しく表示されるようにする。

不可能です。無限大のメモリまたはハードディスクがなければできません。
必ず、制限があります。

問題を出題した人に正解を聞いてみましょう(どんな答えを出すか楽しみ)。


96ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,590ポイント)   Date: 2007/05/30(水) 13:58   No:8101     
Title: Re:無題    
TT414さん初めまして。

>どんな整数を入力しても計算結果が正しく表示されるようにする。

言い方が悪かったです。"どんな"というのは今まで扱ってきた値と比べて
かなり大きい値を扱うということで、今回ならば最終的に40桁まで扱える
ようにしたいがための表現が"どんな"という言葉で過大になってしまいました。

続けて質問失礼します。引数にスペース無しの場合でのコードを書いて
いたのですが、計算結果がおかしくなります。例・引数を1+1と入力すると
49 + 49 = 98などという結果が出ます。何処を直せばよいでしょうか?


#pragma warning ( disable : 4996 )

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

// パラメータエラー
void usage ( void )
{
printf ( "<< 引数を正しく入力して下さい。\n" );
printf ( "<< 1+1 or 1 + 1 の形式で入力して下さい。\n" );
exit ( 0 );
}

int main ( int argc, char *argv[] )
{
int result;
int i = 0;
char op;

// パラメータのチェック
if ( argc != 2 && argc != 4 ) {
usage ();
}

// コマンドライン引数にスペースを与えない場合
if ( argc == 2 ) {
while ( argv[1][i] != '\0' ) {
if ( argv[1][i] == '+' ) {
op = ( argv[1][1] );
if ( isdigit ( argv[1][i] ) ) {
if ( argv[1][i] >= '0' && argv[1][i] <= '9' ) {
}
}
}
i++;
}
}
switch ( op ) {
case '+':
result = argv[1][0] + argv[1][2];
break;
}

printf ( "%d %c %d = %d\n", argv[1][0], op, argv[1][2], result );


 
 

恐らくコードが意味不明な部分があると思いますが、よろしくお願いします。


658ポイント を落としてしまった。

Name: 管理人 [URL]  ..伝説のハッカー(354,706ポイント)   Date: 2007/05/30(水) 14:28   No:8102     
Title: Re:無題    
それは「文字コード」+「文字コード」をしているからです。
受け取ったものは「文字」であり、「数値」ではありません。
「1」という文字は文字コード1ではなく、「1」の文字コードはアスキーコードによると49です。
過去に文字コードについて何度か解説しています。よければちょっと探してみてください。

数値をシングルコーテーションで囲むとそれは文字コードを意味します。
例えば
1
とかけば数値1のことですが、
'1'と書けば「1」の文字コードを意味します。

printf("%d",1);
printf("%d",'1');

両者で違う数値が出ることを確認してください。
atoiで文字を数値に変換しなければならないのはこのためです。
私の書いたサンプルの中で「1+1」の各「1」をatoiで数値に変換していますよね?
また、文字の比較をするとき「'0'以上'9'以下」という書き方をコードの中でしています。
「0以上9以下」ではないのです。

ちょっと解説が手短ですが、文字と、数値、数値を表す文字コードについて調べてみてください。

数値と文字の数字は意味が違うということです。
http://e-words.jp/p/r-ascii.html
文字コードについてはこちらに書かれている表に対応します。

また、1文字の場合、わざわざatoiしなくてもいいです。
例えばいま「9」の文字を数値の「9」として取り出したいときの話です。
「0123456789」と文字コードが並んでいるので、
「9の文字コード」-「0の文字コード」
をすれば「数値の9」が取り出せます。
例えば、
0の文字コードが49だとします。9の文字コードが58ですね。
58-49=9
つまり、引き算すれば数値が取り出せます。
二桁以上になると微妙に計算がややこしくなるのですが1文字の場合単にひけばいいですよ。


342ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(21,689ポイント)   Date: 2007/05/30(水) 15:31   No:8103     
Title: Re:無題    
管理人さん。レスありがとうございます。
atoiで数値に変換したいのですがargv[1][0]等とすると
コンパイルできません。文字を解析して格納までが上手くいきません。

後、ソースでこうした方がいいということはどんどん指摘して
下さい。よろしくお願いします。


99ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(354,789ポイント)   Date: 2007/05/30(水) 15:47   No:8104     
Title: Re:無題    
関数が利用できない

自分の関数の使い方が間違っているのかな?

それなら関数の仕様を調べてみよう


こういう流れで利用できない関数は利用できるようにしていきましょう。
まず、atoiの関数の仕様を調べてみることです。
渡すべき変数の形と現在渡している変数の形がちゃんとあっていますか?

>文字を解析して格納までが上手くいきません。

文字列を解析して数値に変換すべきものは数値に変換し、中の演算子は別途格納するサンプルは既に示しました。
サンプルをじっくりみてください。


83ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(22,581ポイント)   Date: 2007/05/30(水) 16:06   No:8105     
Title: Re:無題    
>渡すべき変数の形と現在渡している変数の形がちゃんとあっていますか?

const char *stringと書いてあり型が違うので出来ないと思います。ただ
argv[1]は文字列に対するポインターの配列なのに
argv[1][n]はどうして同じではないのでしょうか?

これが分からないのは配列が分かっていなんですかね?

>文字列を解析して数値に変換すべきものは数値に変換し、
>中の演算子は別途格納するサンプルは既に示しました。

はい。参考にさせていただいて、演算子は変数char opに格納するようにしました。
ただ、演算子は一つなのでいいのですが、数字を見つけたときに、それが上書き
されてしまうんじゃないのか心配です。じゃあ格納場所を多くすればいいのか?
とも考えたんですが、実際どう組み込めばいいのか分かりませんでした。


#pragma warning ( disable : 4996 )

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

// パラメータエラー
void usage ( void )
{
printf ( "<< 引数を正しく入力して下さい。\n" );
printf ( "<< 1+1 or 1 + 1 の形式で入力して下さい。\n" );
exit ( 0 );
}

int main ( int argc, char *argv[] )
{
int result;
int i = 0;
char op;

// パラメータのチェック
if ( argc != 2 && argc != 4 ) {
usage ();
}

// コマンドライン引数にスペースを与えない場合
if ( argc == 2 ) {
while ( argv[1][i] != '\0' ) {

if ( argv[1][i] == '+' ) {
op = ( argv[1][1] );
}
else if ( argv[1][i] == '-' ) {
op = ( argv[1][1] );
}
else if ( argv[1][i] == '*' ) {
op = ( argv[1][1] );
}
else if ( argv[1][i] == '/' ) {
op = ( argv[1][1] );
}

if ( isdigit ( argv[1][i] ) ) {
if ( argv[1][i] >= '0' && argv[1][i] <= '9' ) {

}
}
i++;
}
}

switch ( op ) {
case '+':
result = argv[1][0] + argv[1][2];
break;
case '-':
result = argv[1][0] - argv[1][2];
break;
case '*':
result = argv[1][0] * argv[1][2];
break;
case '/':
result = argv[1][0] / argv[1][2];
break;
default:
exit ( 0 );
}

printf ( "%d %c %d = %d\n", argv[1][0], op, argv[1][2], result );
}

 
 
 

今の所ソースはこんな感じです。お忙しい中何度もすみません。


892ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(354,396ポイント)   Date: 2007/05/30(水) 16:54   No:8106     
Title: Re:無題    

>argv[1]は文字列に対するポインターの配列なのに
>argv[1][n]はどうして同じではないのでしょうか?

え〜と、
どうして同じではないのでしょうかということは、
argv[1][n]もアドレスが入っているとお思いでしょうか?
argv[1]は確かに[1][0]〜[1][n]が示す配列のアドレスはいっています。
しかしargv[1][0]などは特定のデータそのものを示します。

今とんぷ〜さんは

char st[10]="123";

という配列において、

なぜstと言う記述とst[1]という記述は同じではないのかとおっしゃっているのと同じです。
stというとst[0]〜st[9]までのデータの集まりの先頭のアドレスを示しますよね。
st[1]というと、stが示すアドレスの1つ先にあるアドレスの中身、データ自身を示します。

int st[10]={1,2,3,};
printf("%d\n", st);
printf("%d\n",&st[0]);
printf("%d\n",&st[1]);
printf("%d\n",&st[2]);
printf("%d\n",&st[3]);
printf("%d\n", st[0]);
printf("%d\n", st[1]);
printf("%d\n", st[2]);
printf("%d\n", st[3]);

実行結果

1245004
1245004
1245008
1245012
1245016
1
2
3
0

それと同じように、**argvにおいて、
argv[1]はargv[1][0]からargv[1][n]までのひとまとまりの1つの配列の先頭アドレスを示します。
一方で
argv[1][1]やargv[1][n]はその中の配列の特定のデータ自身を示します。
argv[1][n]はアドレスが入っているわけではありません。

疑問に思うデータの中身を色々な形で表示させてみてください。
意味が解ると思います。

 
 



393ポイント を落としてしまった。

Name: 管理人 [URL]  ..伝説のハッカー(355,068ポイント)   Date: 2007/05/30(水) 17:12   No:8107     
Title: Re:無題    
コマンドラインから指定できる形に変更しました。
このプログラムは黄色い部分はサンプルと全く同じです。
コマンドラインから受け取った文字列をstにまとめる関数addを加えただけです。
これは途中にスペースがあろうと全部引数をstにadd関数でまとめてくれますからサンプルをそのまま利用することが出来ます。

「218 + 328」

「78* 219」

「9 /2」

など、計算可能です。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>


void add(int argc, char *argv[],char st[128]){
int i=0,j=0,s=0;
while( ++i < argc ){
s=0;
while(argv[i][s]!='\0'){
st[j]=argv[i][s];
s++;
j++;
}
}
st[j]='\0';
}


int main(int argc, char *argv[]){

int i=0,x[3];
char st[128],c;


add(argc,argv,st);

while(st[i]!='\0'){
if( !(st[i]>='0' && st[i]<='9') ){
c=st[i];
st[i]='\0';
x[0]=atoi(st);
x[1]=atoi(&st[i+1]);
break;
}
i++;
}

printf("%d %c %d = ",x[0],c,x[1]);

switch(c){
case '+': x[2]=x[0]+x[1]; break;
case '-': x[2]=x[0]-x[1]; break;
case '*': x[2]=x[0]*x[1]; break;
case '/': x[2]=x[0]/x[1]; break;
}
printf("%d",x[2]);
}



672ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(355,009ポイント)   Date: 2007/05/30(水) 17:16   No:8108     
Title: Re:無題    
仕様と異なる入力のエラー処理、0割禁止処理、小数点以下計算不可能など、改良するべき箇所は沢山あるので、サンプルを元に作られる場合は、各追加すべき処理を追加してください。

59ポイント を落としてしまった。

Name: 管理人 [URL]  ..伝説のハッカー(355,053ポイント)   Date: 2007/05/30(水) 17:19   No:8109     
Title: Re:無題    
後、とんぷ〜さんの投稿されたコードは毎回私が直しているのですが、
コードを投稿するときは
<pre>と</pre>というタグで囲んでください。(「<」と「>」は半角で)
コードがこの方が綺麗に表示されますので。
プレタグを頻繁に利用するのでしたら、ユーザー辞書に追加するといいですよ。


44ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(22,668ポイント)   Date: 2007/05/30(水) 17:30   No:8110     
Title: Re:無題    
管理人さん。レスありがとうございました。

><pre>と</pre>というタグで囲んでください。
これは例えば


#include <stdio.h>
main()
{

文..............

return;
}


こういう解釈でいいのでしょうか?
ご迷惑をおかけして申し訳ありません。




87ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(22,720ポイント)   Date: 2007/05/30(水) 17:32   No:8111     
Title: Re:無題    
すみません。分かりにくいですね。

ソースの一番上を

ソースの一番下を


で括るということですよね?



52ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(355,275ポイント)   Date: 2007/05/30(水) 19:23   No:8114     
Title: Re:無題    
それであってますよ^^
タグは見えなくなるので書いてもわかりませんよw
ですからカッコを半角でかかずに<pre>と書いたんですよ。

ウェブで使うタグの表示は普通こんな記号で書くのですが
http://www.tohoho-web.com/html/char.htm
ここの掲示板の使用でこの書き方は出来ないんですよね。

私は全員の記事編集できるので、編集画面を見ることが出来るのですが、そこでどのようにタグを使っているかわかるので私にはわかりますよ。

まぁそれでなくてもプレタグで囲むとスペースのあきかたやフォントが微妙にかわるのでわかりますけどね。
普段半角スペースは2回以上かくと1つにまとめられてしまいますが、
プレタグを使うとそのまま表示されます。タブインデントもね。

ですから、配列の事を説明するときに図を書きましたけど、あれもスペースをそのまま表示したいので、プレタグ使いました。


222ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(24,203ポイント)   Date: 2007/05/31(木) 14:51   No:8161     
Title: Re:無題    
管理人さん。レスありがとうございます。

>それであってますよ^^
安心しましたww

ちょっと作成してみたんですが減算が上手くいきません。
strtol関数の部分にあるprintf ( "error : Please input the integer\n" );
のメッセージが出て終了してしまいます。何がおかしいのでしょうか?

#pragma warning ( disable : 4996 )

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>

// パラメータエラー
void usage ( void )
{
printf ( "<< 引数を正しく入力して下さい。\n" );
exit ( 0 );
}

// コマンドライン引数をst[128]にまとめる関数
void sto ( int argc, char *argv[], char st[128] )
{
int i = 0, j = 0, s = 0;

while ( ++i < argc ) {
s = 0;
while ( argv[i][s] != '\0' ) {
st[j] = ( argv[i][s] );
s++;
j++;
}
}
st[j]='\0';
}

// main関数
int main ( int argc, char *argv[] )
{
long long i = 0;
long long mod;
long long lop;
long long rop;
long long result;

char op; // 演算子
char st[128]; // コマンドライン引数を格納
char *check;

// パラメータのチェック
if ( argc <= 1 || argc >= 5 ) {
usage ();
}

// 関数呼び出し
sto ( argc, argv, st );

while ( st[i] != '\0' ) {
if ( ! ( st[i] >= '0' && st[i] <= '9' ) && ( ! ( st[i] == '-' ) ) ) {

op = st[i];
st[i] = '\0';

lop = atoi (st);
rop = atoi (&st[i+1]);

break;
}
i++;
}

lop = strtol ( st, &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' ) {
printf ( "error : Please input the integer\n" );
exit ( 0 );
}

} else {
printf ( "error : The range of the int type is exceeded\n" );
exit ( 0 );
}

rop = strtol ( &st[i+1], &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' ) {
printf ( "error : Please input the integer\n" );
exit ( 0 );
}

} else {
printf ( "error : The range of the int type is exceeded\n" );
exit ( 0 );
}


// 演算子に沿って計算
switch ( op ) {
case '+':
result = lop + rop;
break;

case '-':
result = lop - rop;
break;

case '*':
result = lop * rop;
break;

case '/':
if ( lop == 0 ) {
printf ( "error : 0 division is a prohibition\n" );
exit ( -1 );
}

// 除算のオーバーフローを考慮
if ( ( lop == INT_MIN ) && ( rop == -1 ) ) {
printf ( "error : The overflow learns by experience\n" );
exit ( 0 );
}

result = lop / rop;
mod = lop % rop;

// 割り算の結果として余りが出なかった場合
if ( mod == 0 ) {
printf ( "%lld %c %lld = %lld", lop, op, rop, result );
exit ( 0 );

// 割り算の結果として余りが出た場合
} else if ( mod != 0 ) {
printf ( "%lld %c %lld = %lld 余り %lld", lop, op, rop, result, mod );
exit ( 0 );
}

break;
default:
printf ( "error : Please input either of operator '+', '-', '*', '/'\n" );
exit ( 0 );
}

// 加、減、乗算のオーバーフローを考慮
if ( ( result > INT_MAX ) || ( result < INT_MIN ) ) {
printf ( "error : The overflow learns by experience\n" );
exit ( 0 );
}
printf ( "%lld %c %lld = %lld", lop, op, rop, result );
}


1,483ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(356,298ポイント)   Date: 2007/05/31(木) 15:20   No:8162     
Title: Re:無題    
! ( st[i] >= '0' && st[i] <= '9' ) && ( ! ( st[i] == '-' ) )

ここ、数字ではなく、マイナスではなければと書いてありますけど、
なぜマイナスの時演算子を取り込まないのですか?

! ( st[i] >= '0' && st[i] <= '9' )

このように書き直せばうまくいくと思います。


61ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(356,347ポイント)   Date: 2007/05/31(木) 15:26   No:8163     
Title: Re:無題    
後、long long型はstrtoll関数ではないでしょうか?

http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strtol.3.html

後、余りを出していますが、実数型で計算しないのでしょうか?
long double型など。
ただlong double型は処理系によっては無い可能性があるので、使わないほうがいいという考えもありますが。


49ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(24,759ポイント)   Date: 2007/05/31(木) 15:54   No:8164     
Title: Re:無題    
管理人さん。いつもお世話になっております。

>マイナスではなければと書いてありますけど、

先頭文字が'-'だった場合に、引き算と判定されてしまうので、
つけてみたんですが減算は上手くいきませんでした。

管理人さんの方でも試したのですが、今度は加算などでも
符号が違う場合などの計算が出来なくなってしまいました。

>後、long long型はstrtoll関数ではないでしょうか?

strtoll関数を使ったら以下のようなメッセージが出てコンパイル出来ませんでした。

1>c:\ct\src\projects\calc\calc\calc.c(69) : warning C4013: 関数 'strtoll' は定義されていません。int 型の値を返す外部関数と見なします。
1>リンクしています...
1>calc.obj : error LNK2019: 未解決の外部シンボル _strtoll が関数 _main で参照されました。
1>C:\CT\SRC\projects\calc\Debug\calc.exe : fatal error LNK1120: 外部参照 1 が未解決です。


2倍のポイントを手に入れた! 556ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(356,401ポイント)   Date: 2007/05/31(木) 15:58   No:8165     
Title: Re:無題    
あぁ、マイナスはそういうことですか。じゃ、数字が出てくる前にマイナスがきたら・・という風に書かないと、マイナス自体読み込まなくなってしまいますよ。

strtollについては使ったことが無いので調べて見ます。


54ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(24,799ポイント)   Date: 2007/05/31(木) 16:11   No:8166     
Title: Re:無題    
>あぁ、マイナスはそういうことですか。じゃ、数字が出てくる前にマイナスがきたら・・
>という風に書かないと、マイナス自体読み込まなくなってしまいますよ。

失礼しました。早速やってみます!!


40ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(356,531ポイント)   Date: 2007/05/31(木) 16:49   No:8167     
Title: Re:無題    
マイナスの件は今回は2つしか値を取り込まないので単純に

if ( ! ( st[i] >= '0' && st[i] <= '9' ) && i!=0 ) {

で回避できると思います。
最初にマイナスが来たときは許すと言うことは、判定を0以外の時、とすればいいのですから。

strtollの件ですが。。Visual Studio2005でもコンパイル通りません。
C99で追加された関数だと言うことはわかるのですが、VS2005の環境でもコンパイル出来ないとなると・・。
[strtoll() は C99 と POSIX.1-2001 に準拠している]と書いてあるので、
コンパイラがそれに準拠していないということではないでしょうか。

GCCはC99に準拠しているようですが、VS2005はC99に準拠していないということでしょうか。


130ポイント を手に入れた。

Name: Justy  ..ハッカー(107,262ポイント)   Date: 2007/05/31(木) 17:21   No:8168     
Title: Re:無題    
> strtoll
 MSVCなら "stdlib.h"に long longではないですけど

__int64 __cdecl _atoi64(const char *);
__int64 __cdecl _strtoi64(const char *, char **, int);


 なんてのがありますよ。


2倍のポイントを手に入れた! 154ポイント を手に入れた。

Name: @とんぷぅ〜  ..上級者(24,965ポイント)   Date: 2007/05/31(木) 17:47   No:8169     
Title: Re:無題    
管理人さん。Justyさん。レスありがとうございます。

私もvc2005なんですが、何やらstrtoll関数はvcでは使えないみたいですね。
何やら難しそうな話で私にはついていけません(笑)

ところで演算子を+/などと入れるとstrtol関数の部分で終了するため
違うエラーメッセージが出て困っています。そこで以下の文を入れたの
ですが、これですと1+-1=0等が弾かれてしまいます。何かよい方法は
ないでしょうか?

if ( strlen ( &st[i+1] ) >= 2 )


166ポイント を手に入れた。

Name: Justy  ..ハッカー(107,619ポイント)   Date: 2007/05/31(木) 23:59   No:8178     
Title: Re:無題    
> 違うエラーメッセージが出て困っています
 違うメッセージとはどういうことでしょう?
 st[i+1]が数値でなければならないところで、"/"であれば「数値を入力してほしい」というエラーで
合っていませんか?


> if ( strlen ( &st[i+1] ) >= 2 )
 これをどこに入れたのか、何を意味しているのかよくわからないです・・・。


> 1+-1
 ついに単項演算を条件に加えましたか。
 これを受け付けるようにする、ということは
 1+++++3とか 1-----4、1+-+-+-++---4も受け付けるのでしょうか?
(C言語的には ++/--演算子と混同しないように書けばOKだったりします)
 

int val1 = 1 + + + + + 3;
int val2 = 1- - - - -4;
int val3 = 1+-+-+-+-+-+-+-+-4;
printf("%d, %d, %d\n", val1, val2, val3);



# ところで@とんぷ〜さんに質問があります。

・ 最終仕様

 最終仕様の「括弧を含む演算」というのは "2 * (4 + 4)"のような複数の加減乗除を
扱う、ということでしょうか?


・ オーバーフローチェック
 今は内部の型が有限なのでチェックしているのだと思いますが、
最終的には(環境的な限界を抜きにして)無限桁になるので
今の段階でも不要なのではないでしょうか?


・ lop / rop

 whileループの中で代入して、その後 strtolでも代入しています。
 何故2回代入しているのでしょう?



357ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(25,596ポイント)   Date: 2007/06/01(金) 14:20   No:8189     
Title: Re:無題    
Justyさん。レスありがとうございました。

>違うメッセージとはどういうことでしょう?
>st[i+1]が数値でなければならないところで、"/"であれば「数値を入力してほしい」

すみません。合ってました(笑)

>if ( strlen ( &st[i+1] ) >= 2 )
>これをどこに入れたのか、何を意味しているのかよくわからないです・・・。

すみません。これは1++1などでも計算できてしまうので
それを弾きたかったんですが、見当違いですみませんでした。
ちなみに"C言語的には ++/--演算子と混同しないように書けばOKだったりします"
とJustyさんがおっしゃられていますが、それなら1++1などが計算できてもいいのでしょうか?

>最終仕様の「括弧を含む演算」というのは "2 * (4 + 4)"のような複数の加減乗除を
>扱う、ということでしょうか?

はい。恐らくなんですが、そうなると思います。

>今は内部の型が有限なのでチェックしているのだと思いますが、
>最終的には(環境的な限界を抜きにして)無限桁になるので
>今の段階でも不要なのではないでしょうか?

現段階ではまずスペース有り、無しで計算出来、負数を括弧で括る条件
で一回見せないといけないのでこうしました。

>whileループの中で代入して、その後 strtolでも代入しています。
>何故2回代入しているのでしょう?

whileループの中の何処の部分でしょうか?ちょっと分かりませんでした。

長々と失礼しました。


631ポイント を手に入れた。

Name: Justy  ..ハッカー(108,145ポイント)   Date: 2007/06/01(金) 15:09   No:8190     
Title: Re:無題    
それなら1++1などが計算できてもいいのでしょうか
 個人的には出来てもいいかと思いますが、上司の方に確認してみたほうがいいでしょう。

 C言語がOKだからといって必ずしも "1 + + 1"を受け付ける必要はないかもしれませんが、
"1 + (+1)"は数学的にもOKなので受け付ける必要があるのではないかと思います。
 一応前に作った calc_testはどちらも出来るようになっています。


はい。恐らくなんですが、そうなると思います
 なるほど。
 となると、もうそろそろ今の解析方法とかだと厳しくなりそうですね。


現段階ではまずスペース有り、無しで計算出来、負数を括弧で括る条件
で一回見せないといけないのでこうしました
 なるほどそういうことでしたか。
 失礼しました。


whileループの中の何処の部分でしょうか
 わかりにくくてすみません。説明不足でした。
 
 えーと、whileループの中で
    lop = atoi (st);

rop = atoi (&st[i+1]);

 で lop/ropに代入し、それらを一度も使うことなく、

lop = strtol ( st, &check, 10 );

rop = strtol ( &st[i+1], &check, 10 );

 と lop/ropに代入しているのでちょっと気になったのです。

 どちらかの代入が不要かと思います。


407ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(25,701ポイント)   Date: 2007/06/01(金) 17:12   No:8201     
Title: Re:無題    
>負数を括弧で括る条件
ちなみに上記条件を実行するには字句解析いう方法
が必要なのでしょうか?
調べても中々参考になるものが無いので。。。

lop/ropの代入については直しました。指摘ありがとう
ございました。


105ポイント を手に入れた。

Name: Justy  ..ハッカー(108,390ポイント)   Date: 2007/06/01(金) 18:39   No:8218     
Title: Re:無題    
ちなみに上記条件を実行するには字句解析いう方法
 どっちかというと構文解析になりますが、最終的には必要になりますね。
 これをやらないと計算順序がわからないので、正しく計算できません。
 
 今の二項演算レベルであれば、力業で解決できるとは思いますが。



148ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(25,792ポイント)   Date: 2007/06/04(月) 11:26   No:8282     
Title: Re:無題    
Justyさんおはようございます。レスありがとうございました。

<今の二項演算レベルであれば、力業で解決できるとは思いますが。
力業とはどういうことでしょうか? 



91ポイント を手に入れた。

Name: Justy  ..ハッカー(109,508ポイント)   Date: 2007/06/04(月) 13:58   No:8290     
Title: Re:無題    
>力業とはどういうことでしょうか?
 ちょっとわかりにくかったですね。
 えーと、比喩的な表現でいろいろと意味があるのですが、ここでは
思いつくまま書いていくことを指しています。

 今回のケースですと、本来であれば二項演算の「式」はどういう文字の要素で成り立ち、
どういうルールで何の文字が現れるのかを正確に仕様化してプログラムを考えるのですが、
二項演算ほどシンプルなものであれば適当に「数字 演算子 数字」とだけ分かってれば
正負の単項演算や括弧が入ってきても、シンプルであるが故に仕様に基づいた構文解析とか
しなくても適当に対処できなくはないかな、ということです。


148ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(25,988ポイント)   Date: 2007/06/04(月) 16:03   No:8293     
Title: Re:無題    
Justyさん。レスありがとうございます。

<「数字 演算子 数字」とだけ分かってれば
<正負の単項演算や括弧が入ってきても、シンプルであるが故に仕様に基づいた構文解析とか
<しなくても適当に対処できなくはないかな、ということです。

う〜んなんとなくおっしゃられていることは分かるんですが、なかなか
考えがまとまらないですね。今はopという変数に演算子を格納しているのですが
そこに括弧を格納し、switchなどで分岐させるのでしょうか?
はたまた括弧用の変数を用意した方がいいのでしょうか?

検討違いかもしれませんがよろしくお願いします。


196ポイント を手に入れた。

Name: Justy  ..ハッカー(109,789ポイント)   Date: 2007/06/04(月) 18:14   No:8298     
Title: Re:無題    
今はopという変数に演算子を格納しているのですが
 それはそれでいいと思いますよ。


そこに括弧を格納し、switchなどで分岐させるのでしょうか?
はたまた括弧用の変数を用意した方がいいのでしょうか?
 単項演算のみで考えた場合括弧は対応状態だけ
チェックして基本は無視でいいと思います。

 ちょっとサンプル作ってみました。
 括弧付きの正負の単項演算のみに対応したものです。
 つまり、"--(+(-(3)))"のようなものを解析します。

 parse_test()の中の test_expression_tbl[]の中にテスト用の
単項演算の式が複数入っています。
 この文字列を1つずつ parse()に引き渡して、正当な単項演算ができれば
1が戻り、失敗すれば 0が戻ります。

 この延長線上で考えれば二項演算も楽にできると思います。


281ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(26,436ポイント)   Date: 2007/06/04(月) 22:26   No:8302     
Title: Re:無題    
Justyさん。レスありがとうございました。

サンプルプログラム拝見しました。初めに思ったのですが、
main関数の短さに驚きました。あれだけ短いと他の関数で
何の処理をしているのかがつかみ易いですね。それだけでも
大変勉強になりました。

ただ、サンプルいろいろと動かしてみたのですが、まだ実際どのように
すれば解析出来るのか見えてきません。括弧の対応状況を調べるというのは
例えばopに'('が入っていたら')'と対応しているか調べるということですよね?

なお今現在管理人さんのサンプルを下に、opには演算子(0〜9以外の文字)
をopに格納するようにしているのですが、その条件に'(' ')'を加えればよいの
でしょうか?もし加えた場合、演算子が上書きされてしまわないでしょうか?

質問ばかりですみません。よろしくお願いします。


2倍のポイントを手に入れた! 448ポイント を手に入れた。

Name: Justy  ..ハッカー(110,407ポイント)   Date: 2007/06/04(月) 23:22   No:8304     
Title: Re:無題    
>あれだけ短いと他の関数で 何の処理をしているのかがつかみ易いですね
 私の場合、普通仕事で書く場合 main関数は数行しかないです。
 他の人を見ても、どんなに大きなプログラムでも概ね多くてmain関数は十数行程度ですね。


>まだ実際どのように すれば解析出来るのか見えてきません
 parse関数が二項演算「因子 演算子 因子」でいうところの因子の演算を
行うものであるのはわかりますよね?

 そして parse関数の第二引数はどこまで解析が終わったか(正確には未解析の文字列の先頭)を返すことが
できるように設計されています。


 この二点から、まず解析したい文字列を parse()にかけて
正常に因子の計算ができたことを確認し、解析が終わった文字列から演算子(+-*/)
を取り出します(opにでも代入しておくといいでしょう)。
 で、その次の文字からを再度 parse関数にかけてあげれば2つ目の数値が取り出せます。
 
(実際にはこのサンプルの仕様上、parse関数は未解析の文字列の先頭が NUL文字であることを
確認しているので、このチェックを外さなければなりませんが)

 従って、サンプルの parse関数を使うのであれば、もう解析の為の whileループは不要です。


>その条件に'(' ')'を加えればよいの でしょうか?
 いいえ、全て parse関数が処理しています。
 main関数が行わなければならないのは parse関数への引数と戻り値の管理と
演算子の管理、そして実際の計算だけとなります。


618ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(26,797ポイント)   Date: 2007/06/05(火) 13:49   No:8312     
Title: Re:無題    
Justyさん。レスありがとうございます。

>parse関数が二項演算「因子 演算子 因子」でいうところの因子の演算を
>行うものであるのはわかりますよね?

正直な所、因子の演算という意味がよく理解できません。

申し訳ありません。Justyさんのおっしゃられていることが理解出来ません。
大変丁寧な説明だと思うのですが、私の知識では理解出来ませんでした。

parse()にかけてというのは、引数を渡すということなのでしょうか?
parse(const char *expression, const char **end, int *pValue)となっていますが
どのようにすればいいのか分かりません。skipやfactorもどんな方に処理すればよいのかも分かりません。
 
>もう解析の為の whileループは不要です

while ( st[i] != '\0' ) {
if ( ! ( st[i] >= '0' && st[i] <= '9' ) && i != 0 ) {
op = st[i];
st[i] = '\0';
lop = atoi ( st );
rop = atoi ( &st[i+1] );
break;
}
i++;
}

この部分でしょうか?


361ポイント を手に入れた。

Name: Justy  ..ハッカー(111,636ポイント)   Date: 2007/06/05(火) 16:22   No:8316     
Title: Re:無題    
正直な所、因子の演算という意味がよく理解できません。
 二項演算というのはわかりますか?
 二つの数と演算子を元に、新たな数を導く計算のことです。
 四則演算なら例えば「1 + 1」とか「5 * 4」のように「数字 演算子 数字」の
ような形になります。

 因子というのはここでいう数字の部分に相当します。
 数字と書かなかったのは数字だけがここに来るとは限らないので、因子と書きました。
 例えば「-(+(-5)) / +++(3) 」であれば2つの因子とはそれぞれ「-(+(-5))」と「+++(3)」を指します。

 parse関数はこの 「-(+(-5))」や「+++(3)」の文字列を解析して、
int型のデータに変換する機能を持っています。


parse()にかけてというのは、引数を渡すということなのでしょうか?
 そうです。


parse(const char *expression, const char **end, int *pValue)となっていますが
どのようにすればいいのか分かりません。skipやfactorもどんな方に処理すればよいのかも分かりません。
 使うのは基本的には parse関数だけでいいのですが、ひょっとしてサンプルが何をしているのも
わからなかったのでしょうか?

 parseの第一引数は解析したい「因子」となる文字列を指定します。
 第二引数は第一引数の文字列を「因子」としての解析が終了した直後の文字列の位置を
ポインタを経由して取得できます。
 第三引数は「因子」としての解析が成功したのなら結果がポインタを経由して取得できます。

 例を挙げますと以下のようなプログラムの場合
    const char *p;

int val;
const char *expression = "-(--( 5 )) -4";
parse(expression, &p, &val);
printf("%d # %s\n", val, p);

 実行するとこのように表示されます。

-5 # hdfghdfgh
 parse関数は valに -5を、pには 第一引数で指定した文字列の中で因子としての解析が終わった位置を戻しているので、
このように表示されます。

 では、こうしたらどうでしょうか。

    const char *p;

int val1, val2;
const char *expression = "-(--( 5 )) -4";
parse(expression, &p, &val1);
parse(p, &p, &val2);
printf("%d , %d\n", val1, val2);


 表示は
-5 , -4
 になるはずです。

 1回目の parse解析で、expression内の文字列解析し、-5という値を出しています。
 そのとき、pは expression文字列の中の "-4"の部分を指しているポインタになっているので、
その pをそのまま parseにかけると2つ目の値 -4が取得しています。


 この説明でなんとなく掴めたでしょうか?


1,229ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,211ポイント)   Date: 2007/06/05(火) 17:01   No:8319     
Title: Re:無題    
Justyさん。レスありがとうございます。

説明して下さったおかげで因子については理解出来ました。

>基本的には parse関数だけでいいのですが
これはparse関数内で他の関数を呼び出しているから、parse関数を
呼び出せばいいという考え方でよいのでしょうか?

>ひょっとしてサンプルが何をしているのもわからなかったのでしょうか?

はい。すみません。実際はこんな処理をしているのかな〜ということしか分かりませんでした。
ポインタが絡んでくるともう駄目になってしまい、本を見ながら解読していたので
すが、意味を理解することが出来ませんでした。

>この説明でなんとなく掴めたでしょうか?
先ほどよりは掴めてきました。ただ、なんとなくですが。。

結局のところ、変数opに括弧と演算子を格納することが出来る
ようになるということでしょうか?結論が今いち掴めないです。
理解力不足ですみません。




414ポイント を手に入れた。

Name: バグ  ..熟練のプログラマー(44,442ポイント)   Date: 2007/06/05(火) 17:27   No:8322     
Title: Re:無題    
ポインタは決して難しいものではありませんよ。
これは私が初めてポインタを理解できたような気がした時に頭に過ぎった例えです。
参考になるか分かりませんが、良かったら読んでみて下さい。



メモリを本だと考えて下さい。

アドレスをページだと考えて下さい。

その本に書かれている文章が変数や関数だと考えて下さい。

ポインタはその書かれた場所を指し示す栞だと考えて下さい。

栞は単体では意味を成しませんよね?

書物に挟む事で初めて意味を成すものです。


int nVal;
int* pPtr;

pPtr = &nVal;


これは、nValという変数が書かれているページにpPtrという栞を挟んだと考えればどうでしょう?
pPtrは栞でありながら、nValが書かれたページでもある訳です。


*pPtr = 10;


つまり、上記のような代入を行うと、pPtrが挟まれているページの内容を10に書き換えなさいという意味になる訳です。ですから、pPtrという栞を通して、間接的にnValを書き換える事になる訳です。

参考になればよいですが…(^_^;)


274ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,461ポイント)   Date: 2007/06/05(火) 18:15   No:8324     
Title: Re:無題    
バグさん。レスありがとうございます。

<pPtrという栞を通して、間接的にnValを書き換える事になる訳です。

 確かに間接参照の考え方としては理解しやすいですね。
しかし、よく思いつきましたね。大変参考になりました!

ありがとうございました。


2倍のポイントを手に入れた! 250ポイント を手に入れた。

Name: Justy  ..ハッカー(112,194ポイント)   Date: 2007/06/05(火) 19:03   No:8325     
Title: Re:無題    
 上司の方に説明する必要があるので、中身を理解する必要があるのは
わかるのですが、今は中身の処理より、結果に注目してください。
 つまり、parse()の中身は今は無視してください。


>parse関数を呼び出せばいいという考え方でよいのでしょうか?
 単項部分に限って言えば、Y


>変数opに括弧と演算子を格納することが出来る ようになるということでしょうか?
 N
 括弧を格納する必要はありません。


 先ほどのコードに手を加えてみました。
    const char *p;

int val;
const char *expression = "-(--( 5 )) -4";
parse(expression, &p, &val);
printf("val = %d, p = %s\n", val, p);


 このコードの実行結果は
val1 = -5, p = -4
 となります。
 さて、ここで注目なのは 1つ目の parseを実行し終わったところで文字列へのポインタ pは
"-4"を指しています。
 ということとは p[0]は '-'であり、p[1]='4'である、ということです。

 では、これをふまえて、expressionの式を二項演算に代えてみました。
    const char *p;

int val;
const char *expression = "-(--( 5 )) * -4";
parse(expression, &p, &val);
printf("val = %d, p = %s\n", val, p);

 このコードだったらどうでしょう?
 この結果 pは何を指すと思いますか?


558ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,506ポイント)   Date: 2007/06/05(火) 20:08   No:8329     
Title: Re:無題    
Justyさん。レスありがとうございます。

理由はよく分かりませんが、たぶん-4を指すんだと思います。


45ポイント を手に入れた。

Name: Justy  ..ハッカー(112,284ポイント)   Date: 2007/06/06(水) 00:45   No:8337     
Title: Re:無題    
>理由はよく分かりませんが、たぶん-4を指すんだと思います。
 では実際にテストしてみて下さい。


# ところでこのままのペースで話を進めると、ある程度形になるまで
まだ相当な時間がかかりそうな気がするのですが・・・。
 先輩か上司の方に一度現状を見て貰って、状況とソースを整理してみてはどうでしょう?


90ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,631ポイント)   Date: 2007/06/06(水) 01:05   No:8338     
Title: Re:無題    
Justyさん。レスありがとうございます。

>では実際にテストしてみて下さい。

実行したら-4を指していました。

>ところでこのままのペースで話を進めると、ある程度形になるまで
>まだ相当な時間がかかりそうな気がするのですが・・・。
>先輩か上司の方に一度現状を見て貰って、状況とソースを整理してみてはどうでしょう?

はい。確かにそうですね。多桁は除いて、せめて括弧付きの計算が出来て
から確認を取りたいと思っています。う〜んプログラムは難しいですね。。(( T_T)トボトボ


125ポイント を手に入れた。

Name: Justy  ..ハッカー(112,361ポイント)   Date: 2007/06/06(水) 01:11   No:8339     
Title: Re:無題    
>実行したら-4を指していました。
 あれ? おかしいですね。
 expressionは "-(--( 5 )) * -4"になっていますか?


>括弧付きの計算が出来てから確認を取りたいと思っています。
 期限とかないんですか?


77ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,612ポイント)   Date: 2007/06/06(水) 09:38   No:8342     
Title: Re:無題    
Justyさん。レスありがとうございます。

>expressionは "-(--( 5 )) * -4"になっていますか?
はい。なっております。
実行結果va = -5, p = * -4となりました。

>期限とかないんですか?
期限はとくにないです。早く出来れば出来るだけいいんでしょうけど。


19ポイント を落としてしまった。

Name: Justy  ..ハッカー(112,471ポイント)   Date: 2007/06/06(水) 10:00   No:8343     
Title: Re:無題    
>実行結果va = -5, p = * -4となりました
 ですよね。
 ということは、この時の p[0]は '*'になるので、これをopに保存すれば、
正しく演算子を取得できるのではないでしょうか。

 で、再び、そのp[0]の次の文字p[1]からの文字列を再度 parseにかければ、
2つ目の数値が取り出せます。


110ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,739ポイント)   Date: 2007/06/06(水) 11:08   No:8344     
Title: Re:無題    
Justyさん。レスありがとうございます。

>で、再び、そのp[0]の次の文字p[1]からの文字列を再度 parseにかければ、
>2つ目の数値が取り出せます。

p++などで、n文字分進ませればいいんですよね?
そして今までのコードに組み込めばいいんでしょうか?




127ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,787ポイント)   Date: 2007/06/06(水) 11:12   No:8345     
Title: Re:無題    
間違えました。Pの要素でした。

op = p[i];
i++;

こういうことですよね?


48ポイント を手に入れた。

Name: Justy  ..ハッカー(112,543ポイント)   Date: 2007/06/06(水) 12:02   No:8346     
Title: Re:無題    
>こういうことですよね?
 ですです。
 で、後は演算子が四則演算であるかチェックして、オーバーフローチェックもどこかに入れて
実際に計算すれば(中身を理解する作業は別にして)二項演算は終了です。


72ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(27,670ポイント)   Date: 2007/06/06(水) 14:49   No:8348     
Title: Re:無題    
Justyさん。レスありがとうございます。

組み込み方が分からずなんかテンパってきました。
この場合expressionをコマンドライン引数に置き換えてやればいいんですよね?

Justyさんのサンプルでparse_test以外を今までのソースに組み合わせればいいんですよね?


117ポイント を落としてしまった。

Name: Justy  ..ハッカー(112,679ポイント)   Date: 2007/06/06(水) 15:09   No:8349     
Title: Re:無題    
>この場合expressionをコマンドライン引数に置き換えてやればいいんですよね?
 Y

>Justyさんのサンプルでparse_test以外を今までのソースに組み合わせればいいんですよね?
 Y

 parse関数に関しては、今の実装ですと終端が NUL文字であることをチェックして
1か 0か(成功したかどうか)を戻すようになっているので、その部分だけは
削った方がいいかと思います。


136ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,466ポイント)   Date: 2007/06/06(水) 15:46   No:8350     
Title: Re:無題    
Justyさん。レスありがとうございました。

一応ソースを添付しておきます。


#pragma warning ( disable : 4996 )

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <ctype.h>
#include "calc.h"

/*----------------- 関数プロトタイプ宣言 -----------------*/

// エラーメッセージ
void usage_err ( int, char *[] );
void integer_err ();
void int_over_err ();
void operator_err ();
void div_err ();
void over_flow_err ();

// 四則計算
long long add ( long long, long long );
long long sub ( long long, long long );
long long mul ( long long, long long );
long long did ( long long, long long );
long long mod ( long long, long long );


// NUL文字
#define ASCII_NUL ('\0')

// 式文字列のバッファサイズ
#define EXPRESSION_BUFF_SIZE ( 128 )

// 配列サイズ
#define ArraySize(array) (sizeof(array)/sizeof(*(array)))

/*********************************************************************/

// 構文
// factor ::= integer | ('(' factor ')') | ('+' factor) | ('-' factor)
// expression ::= factor

// 空白をスキップ
static const char *skip_parce(const char *p)
{
if(p)
{
while(isspace(*p))
++p;
}
return p;
}


// 要素解析
static int parse_factor(const char **p, int *pValue)
{
int c;

// 空白をスキップ
*p = skip_parce(*p);
c = **p;

if(isdigit(c))
{
char *end;
*pValue = (int)strtol(*p, &end, 10);
*p = end;
return 1;
}
else
if(c == '(')
{
++(*p);
if(parse_factor(p, pValue))
{
*p = skip_parce(*p);
if(**p == ')')
{
++*p;
return 1;
}
}
}
else
if(c == '-')
{
++(*p);
if(parse_factor(p, pValue))
{
*pValue = -(*pValue);
return 1;
}
}
else
if(c == '+')
{
++(*p);
if(parse_factor(p, pValue))
return 1;
}
return 0; // 異常
}

// 解析
static int parse(const char *expression, const char **end, int *pValue)
{
// NULLチェック
if(expression && pValue)
{
// 要素解析
const char *p = expression;
if(parse_factor(&p, pValue))
{
// 解析が終了した文字列の位置を記録
p = skip_parce(p);
if(end) *end = p;
}
}
return 0;
}


/*********************************************************************/

/*-------- 受け取ったコマンドライン引数を配列strまとめる --------*/

void storage ( int argc, char *argv[], char st[128] )
{
int i = 0, j = 0, s = 0;

while ( ++i < argc ) {
s = 0;
while ( argv[i][s] != '\0' ) {
st[j] = ( argv[i][s] );
s++;
j++;
}
}
st[j]='\0';
}

/*----------------- main関数 -----------------*/

int main ( int argc, char *argv[] )
{
long long lop; // 左オペランド
long long rop; // 右オペランド
long long i = 0; // 配列要素
long long n = 0;
long long surplus; // 余り
long long result; // 結果

char op; // 演算子
char st[128]; // コマンドライン引数を格納
char *check; // 変換不能な文字列へのポインタを格納

// パラメータのチェック
if ( argc <= 1 || argc >= 5 ) {
usage_err ( argc, argv );
}

storage ( argc, argv, st );

// 文字列のチェック
while ( st[i] != '\0' ) {
if ( ! ( st[i] >= '0' && st[i] <= '9' ) && i != 0 ) {
op = st[i];
st[i] = '\0';
lop = atoi ( st );
rop = atoi ( &st[i+1] );
break;
}
i++;
}

// 左オペランドのチェック
strtol ( st, &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' )
integer_err ();
} else {
int_over_err ();
}

// 右オペランドのチェック
strtol ( &st[i+1], &check, 10 );
if ( errno != ERANGE ) {
if ( *check != '\0' )
integer_err ();
} else {
int_over_err ();
}

switch ( op ) {
case '+':
result = add ( lop, rop );
break;
case '-':
result = sub ( lop, rop );
break;
case '*':
result = mul ( lop, rop );
break;
case '/':
if ( rop == 0 )
div_err ();

// 除算のオーバーフローを考慮
if ( ( lop == INT_MIN ) && ( rop == -1 ) )
over_flow_err ();

result = did ( lop, rop );
surplus = mod ( lop, rop );

if ( surplus == 0 ) {
printf ( "%lld %c %lld = %lld\n", lop, op, rop, result );
exit ( 0 );
} else if ( surplus != 0 ) {
printf ( "%lld %c %lld = %lld 余り %lld\n", lop, op, rop, result, surplus );
exit ( 0 );
}
break;
default:
operator_err ();
}

// 加、減、乗算のオーバーフローを考慮
if ( ( result > INT_MAX ) || ( result < INT_MIN ) )
over_flow_err ();

// 左オペランド、演算子、右オペランドの順に出力
printf ( "%lld %c %lld = %lld\n", lop, op, rop, result );
exit ( 0 );
}


ソース部分で//文字列のチェックという部分を削り、//右オペランドのチェック
の上の部分でparse()関数を呼び出せばいいんですよね?

>終端が NUL文字であることをチェックして
>1か 0か(成功したかどうか)を戻すようになっているので
アドバイスありがとうございました。その部分については削除しました。



1,796ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,493ポイント)   Date: 2007/06/06(水) 15:49   No:8351     
Title: Re:無題    
連レスすみません。
大変見にくいので添付ファイルにします。


27ポイント を手に入れた。

Name: Justy  ..ハッカー(112,781ポイント)   Date: 2007/06/06(水) 21:53   No:8357     
Title: Re:無題    
>ソース部分で//文字列のチェックという部分を削り、//右オペランドのチェック
>の上の部分でparse()関数を呼び出せばいいんですよね?
 そんなかんじですが、実際に呼び出したソースを見ないことにはなんとも。


102ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,573ポイント)   Date: 2007/06/07(木) 11:33   No:8393     
Title: Re:無題    
Justyさん。レスありがとうございます。

parse関数にstを渡したいのですが、型が違うため困っています。
このような場合は関数の型を変更すればよいのでしょうか?



80ポイント を手に入れた。

Name: Justy  ..ハッカー(113,316ポイント)   Date: 2007/06/07(木) 11:44   No:8394     
Title: Re:無題    
 第一引数ですよね?
 型が違うというのはstを第一引数に parse(st, ....)として渡せない、ということですか?
 何か警告かコンパイルエラーが出るのですか?



67ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,628ポイント)   Date: 2007/06/07(木) 13:50   No:8396     
Title: Re:無題    
Justyさん。レスありがとうございます。

間違いました。stは渡せました。
引数を指定してparse(st, &p, &val);
op = p[i]と代入したのですが、上手くいきません。

引数の指定が間違っているのでしょうか?


55ポイント を手に入れた。

Name: Justy  ..ハッカー(113,336ポイント)   Date: 2007/06/07(木) 14:01   No:8397     
Title: Re:無題    
 iって何でしょう?
 parseが正常に行われたのなら、演算子は p[0]に入っているはずなのですが。


20ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,833ポイント)   Date: 2007/06/07(木) 15:03   No:8398     
Title: Re:無題    
間違いました。すみませんp[0]に演算子が入っているのですが
計算自体できません。これはまだatoiで変換してないからなのですが、

例えば21 + (-5)という式があれば、valに21 pに+ (-5)がはいると思う
んですが、この時valとpをatoiで整数にするんでしょうか?

今までlopとopで表していたので、かなりごっちゃになってきました。
自分が理解出来ていないため、上手く質問することができず、ご迷惑
をおかけしますがよろしくお願いします。


205ポイント を手に入れた。

Name: Justy  ..ハッカー(113,487ポイント)   Date: 2007/06/07(木) 15:21   No:8399     
Title: Re:無題    
>これはまだatoiで変換してないからなのですが
 これは2つ目の数字の話ですか?


>この時valとpをatoiで整数にするんでしょうか?
 valとpをatoiで整数化ですか?
 ちょっと意味を掴みかねるのですが、2つ目の数字を取得したいということであれば
は pを使って再度 parseしてください。
 
2007/06/05(火) 16:22 投稿の2つ目のサンプルがどうなっていたかみればわかると思います。


151ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,869ポイント)   Date: 2007/06/07(木) 16:20   No:8400     
Title: Re:無題    
Justyさん。レスありがとうございました。

アドバイスありがとうございます。なんとか出来ました!!! 

ソースを見て頂きたいのですが、main関数内のstrtolの部分を削ると上手く
いくのですが、削らないと上手くいかないのはparse_factor関数で判定している
からなのでしょうか?

ちなみに括弧を付けた式を入力したとき (-5) + 4 と入力すると
-5 + 4 = -1となってしまい、括弧が表示されません。
これは出力する際に条件を加えなくてはならないのでしょうか?

お忙しい中何度もすみません。






36ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(29,904ポイント)   Date: 2007/06/07(木) 16:29   No:8401     
Title: Re:無題    
今テストしていたんですが、かなりバグがありました。
明らかにおかしいという部分の指摘をお願いします。


35ポイント を手に入れた。

Name: Justy  ..ハッカー(113,912ポイント)   Date: 2007/06/07(木) 16:40   No:8402     
Title: Re:無題    
>main関数内のstrtolの部分を削ると上手く いくのですが、
>削らないと上手くいかないのはparse_factor関数で判定している
 もうこのチェック方法ではだめですね。
 このチェックが int型変換時の intで扱える範囲を超えた場合に対するチェックであれば
parse_factor()内の strtol()を使っているところでチェックするといいでしょう。


>-5 + 4 = -1となってしまい、括弧が表示されません。
 それはそうでしょう。
 数値に変換したあとの lop/ropを使って printfしていますから。
 普通に文字列 stを表示すればいいのではないですか?


>今テストしていたんですが、かなりバグがありました。
>明らかにおかしいという部分の指摘をお願いします。

 parse()の戻り値をチェックしていない点でしょうか。
 因子に不正な文字が入っていてもそれを無視してしまっています。

 さらに parse()は元々成功したとき 1を返すようにしていましたが、
それがなくなっています。
(NUL文字チェックは削ってもいいのですが、1は戻すようにしてください)


425ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,074ポイント)   Date: 2007/06/07(木) 17:05   No:8403     
Title: Re:無題    
Justyさん。レスありがとうございます。

>このチェックが int型変換時の intで扱える範囲を超えた場合に対するチェックであれば
>parse_factor()内の strtol()を使っているところでチェックするといいでしょう。

了解しました。ありがとうございます。

>数値に変換したあとの lop/ropを使って printfしていますから。
>普通に文字列 stを表示すればいいのではないですか?

確かにその通りですね。固定観念はいけないですねw

>parse()の戻り値をチェックしていない点でしょうか。
>因子に不正な文字が入っていてもそれを無視してしまっています。

戻り値のチェックとはどういったことをすればよいのでしょうか?



2倍のポイントを手に入れた! 170ポイント を手に入れた。

Name: Justy  ..ハッカー(113,985ポイント)   Date: 2007/06/07(木) 17:26   No:8404     
Title: Re:無題    
>戻り値のチェックとはどういったことをすればよいのでしょうか?
 2007/06/04(月) 18:14のソースは戻り値をチェックしています。
(先にも書きましたが、parse関数は成功したら 1を返すよう修正してください)


73ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,173ポイント)   Date: 2007/06/07(木) 17:49   No:8405     
Title: Re:無題    
>先にも書きましたが、parse関数は成功したら 1を返すよう修正してください
すみませんでした。NULLチェックを省きました。

// 解析
static int parse(const char *expression, const char **end, long long *pValue)
{
// 要素解析
const char *p = expression;
if(parse_factor(&p, pValue))
{
// 解析が終了した文字列の位置を記録
p = skip_parce(p);
if(end) *end = p;

// 解析が終わってもう文字が残っていなければ成功
if(*p == ASCII_NUL)
return 1;
}
return 0;
}

こうでいいんですよね? ただ、減算、乗算、除算がうまくいきません。


99ポイント を手に入れた。

Name: Justy  ..ハッカー(113,927ポイント)   Date: 2007/06/07(木) 18:15   No:8406     
Title: Re:無題    
>NULLチェックを省きました。
 えーと、NUL文字チェックは削ってください。
 でもそこまで到達しているなら、1を返して下さい。


58ポイント を落としてしまった。

Name: @とんぷぅ〜  ..プログラマー(30,291ポイント)   Date: 2007/06/07(木) 18:34   No:8407     
Title: Re:無題    
Justyさん。レスありがとうございます。

>NUL文字チェックは削ってください。
削るというのは?上記ではおかしいのでしょうか?

>1を返して下さい。
return 1;の部分ではないのですか?

すみませんがよく理解出来ません。どういうことでしょうか?


118ポイント を手に入れた。

Name: Justy  ..ハッカー(114,050ポイント)   Date: 2007/06/07(木) 18:49   No:8408     
Title: Re:無題    
>削るというのは
 削除する、ということです。


>return 1;の部分ではないのですか?
 以前、NUL文字チェックを削ってください、と言ったとき、return 1まで削ってしまいました。
 で、return 1をしてくださいと言ったら、今度は削ったはずの NUL文字チェックが復活していました。
 なので、NUL文字チェックは削除した状態で、1を戻すようにしてください。


123ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,138ポイント)   Date: 2007/06/08(金) 00:24   No:8420     
Title: Re:無題    
Justyさん。レスありがとうございます。
すみませんでした。これでOKですよね??


// 解析
static int parse(const char *expression, const char **end, long long *pValue)
{
  // 要素解析
  const char *p = expression;
    if(parse_factor(&p, pValue))
    {
    // 解析が終了した文字列の位置を記録
    p = skip_parce(p);
      if(end) *end = p;
      return 1;
    }
    return 0;
}



153ポイント を落としてしまった。

Name: Justy  ..ハッカー(114,059ポイント)   Date: 2007/06/08(金) 01:16   No:8423     
Title: Re:無題    
>これでOKですよね
 OKです。これで終端が NUL文字じゃなくても成功として返すようになります。


9ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,217ポイント)   Date: 2007/06/08(金) 10:13   No:8429     
Title: Re:無題    
Justyさん。レスありがとうございます。

問題点がありまして、
@減算5 - 2等を行うと7という結果が出る。
A乗算1 * 1等を行うと正しく計算されず、over_flowのメッセージが出る。
B除算5 / 1等のを行うと0余り5という結果が出る。

@についてはropに演算子がくっついた状態になってしまっています。
A、Bはropに-3689348814741910324という数が入ってしまいます。
どこがおかしいのでしょうか?


79ポイント を手に入れた。

Name: Justy  ..ハッカー(114,043ポイント)   Date: 2007/06/08(金) 12:56   No:8434     
Title: Re:無題    
>どこがおかしいのでしょうか?
 戻り値をチェックした上での話ですか?

 だとすると現状の最新のソースをビルドできる形で
出して頂かないと、なんとも・・・。


16ポイント を落としてしまった。

Name: @とんぷぅ〜  ..プログラマー(30,273ポイント)   Date: 2007/06/08(金) 14:20   No:8440     
Title: Re:無題    
Justyさん。レスありがとうございます。

>だとすると現状の最新のソースをビルドできる形で
>出して頂かないと、なんとも・・・。

了解しました。かなり見ずらいですがよろしくお願いします。


56ポイント を手に入れた。

Name: Justy  ..ハッカー(114,174ポイント)   Date: 2007/06/08(金) 14:32   No:8441     
Title: Re:無題    
 ちょっと時間がないので手短に。

・ parseの戻り値をチェックしてください。
 チェックして、問題があれば(0が戻ってきている)エラーとしてください。

・ 2回目の parse(ropの方)で、第一引数に pを与えています。
 parseはあくまで因子しか解析しませんが、p[0]が演算子であり、因子でないためエラーになっています。
 因子(があるでろう)文字列を指すよう調整してください。


131ポイント を手に入れた。

Name: Comp  ..ぴよぴよ(25ポイント)   Date: 2007/06/08(金) 15:05   No:8443     
Title: Re:無題    
はじめまして、
横槍ですいません。

A、Bについてですが、

とんぷぅ〜さんはステップ実行が出来る環境でしょうか?

出来るのであれば、1+1の場合と1*1の場合で比べて見てください。

違いは+と*だけなのに片方はオーバーフローしてしまう、
じゃあ +と*の処理してる所は、どこなんでしょう?
その差は何なんでしょう?
おかしな所が浮き上がってきませんか?
ちょっとした処理の忘れ物があるだけです。

がんばってください。


25ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,105ポイント)   Date: 2007/06/08(金) 16:58   No:8445     
Title: Re:無題    
Justyさん。Compさん。レスありがとうございます。

"Justyさん"

>parseの戻り値をチェックしてください。
>チェックして、問題があれば(0が戻ってきている)エラーとしてください。

本当に申し訳ありません。具体的にどのようにすればよいのか分かりません。
if等で指定すればいいのでしょうか?

"Compさん"

>ちょっとした処理の忘れ物があるだけです。

う〜ん。分かりません。ステップさせてみたんですが、ここがこうでという
筋道を立てて理解することが出来ていないので、最終的な結果しか分からないです。
ちなみにその処理とはmain関数内ではないんですよね?


168ポイント を落としてしまった。

Name: @とんぷぅ〜  ..プログラマー(30,159ポイント)   Date: 2007/06/08(金) 17:51   No:8446     
Title: Re:無題    
すみません。解決できました。pに気を取られすぎていました。

ちなみにまだ戻り値のチェックは出来ていません(泣)


54ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,198ポイント)   Date: 2007/06/08(金) 17:53   No:8447     
Title: Re:無題    
連続レスすみません。

勘違いでした。まだ@、A、Bとも解決できていません。。。orz


39ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,258ポイント)   Date: 2007/06/08(金) 18:13   No:8450     
Title: Re:無題    
またまたすみません。無事動きました。
もう少し整理してからソースを載せたいと思いますので、
よろしくお願いします。


60ポイント を手に入れた。

Name: @とんおうぅ〜  ..ぴよぴよ(244ポイント)   Date: 2007/06/09(土) 02:30   No:8467     
Title: Re:無題    
こんばんは。

今、int型を超える場合のオーバーフローチェックをしていたのですが、

parse_factor()
*pValue = (int) strtol (*p, &end, 10);の部分の下に
if ( errno != ERANGE )
    {
if ( *end != '\0' )
// 整数以外が入力された場合   
integer_err();
}
    else
    { // int型を超えていた場合
int_over_err();
}


としたのですが、上手く動きません。何がいけないのでしょうか?


244ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,277ポイント)   Date: 2007/06/09(土) 02:30   No:8468     
Title: Re:無題    
連レスすみません。名前を間違えましたw

19ポイント を手に入れた。

Name: Justy  ..ハッカー(114,397ポイント)   Date: 2007/06/09(土) 15:11   No:8481     
Title: Re:無題    
ちなみにまだ戻り値のチェックは出来ていません
if等で指定すればいいのでしょうか
 一昨日あたりに書いたと思ったのですが、ifでチェックして下さい。


上手く動きません
 できれば何がどう旨く動かないのか書いて欲しいところですが。
 でもまぁ大体推測はつきます。

if ( *end != '\0' )

 NUL文字でなければエラーにするのは多分数式の後に余計な文字があるかどうかを
みようとしたのだと思いますが、それでは最初の parseチェックでエラーになってしまいますよ。
 2回目の parseが終わった後、チェックするようにすれば式が最後まで解析されたかどうか判ると思います。


223ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,357ポイント)   Date: 2007/06/09(土) 18:10   No:8488     
Title: Re:無題    
Justyさん。レスありがとうございます。

>2回目の parseが終わった後、チェックするようにすれば
ということはmain関数内で行えばよいのでしょうか?

う〜ん。中々難しいですね。

まだいじってないのですが、一応ソース載せておきます。


80ポイント を手に入れた。

Name: Justy  ..ハッカー(114,432ポイント)   Date: 2007/06/10(日) 02:26   No:8493     
Title: Re:無題    
>ということはmain関数内で行えばよいのでしょうか?
 Y
 これで parseの戻り値さえチェックすれば完成なのではないでしょうか。


35ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,605ポイント)   Date: 2007/06/12(火) 12:30   No:8550     
Title: Re:無題    
Justyさん。お世話になっております。
レスが遅れて申し訳ありませんでした。

戻り値のチェックですが、こんな感じでいいでしょうか?

static int Parse (const char *expression, const char **end, long long *pValue)
{
// 要素解析
const char *p = expression;
if (Parse_factor (&p, pValue))
{
// 解析が終了した文字列の位置を記録
p = Skip_parce (p);
if (end) *end = p;

return 1;
}

if (Parse == 0)
{
printf("error : return error\n");
}
return 0;
}




248ポイント を手に入れた。

Name: Justy  ..ハッカー(114,723ポイント)   Date: 2007/06/12(火) 12:59   No:8551     
Title: Re:無題    
>戻り値のチェックですが、こんな感じでいいでしょうか
 まぁ場所的にはそこでも間違いではないですが、そのチェック位置に
来たときは常にエラーです。

 つまりそこでチェックする場合、エラーチェックそのものが不要になります。


 ただ、parseの再利用性を考えるならそこでチェックせず、main側で行った方がいいでしょう。
 せっかく parse関数は成功すれば 1が、失敗すれば 0が戻ってきているのですから。



if(!parse (st, &p, &lop))
printf("error\n");



>if (Parse == 0)
 ちなみにこの if文は常に偽となります。
 意味がありません。


291ポイント を手に入れた。

Name: keichan  ..上級者(24,134ポイント)   Date: 2007/06/12(火) 14:16   No:8554     
Title: Re:無題    
>>if (Parse == 0)
> ちなみにこの if文は常に偽となります。
> 意味がありません。

ちょこっと解説をば。

なぜ "常に偽" になるかですが、関数を()なしで使用した場合
その関数のアドレスを指すことになります。
(関数ポインタを使用したことがあるならすんなり理解していただけると思いますが)

関数の"アドレス"なので 0 はあり得ません。

よって

Parse(!=0) == 0
は常に偽になります。

ご存知なネタでしたらスルーしてください。


224ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(30,826ポイント)   Date: 2007/06/12(火) 15:35   No:8557     
Title: Re:無題    
Justyさん。keichanさん。レスありがとうございました。

// 文字列stの解析
Parse (st, &p, &lop);

// opに演算子を代入
op = p[0];
p++;

// 文字列pの解析
Parse (p, &p, &rop);

if (!Parse (st, &p, &lop))
{
printf("error\n");
}


これで問題無いですよね?

>if (Parse == 0)
>ちなみにこの if文は常に偽となります。
>意味がありません。

掘り下げて論理式を調べてみました。今更ですが、
間違った考え方をしていました。指摘ありがとうございます。




221ポイント を手に入れた。

Name: Justy  ..ハッカー(114,775ポイント)   Date: 2007/06/12(火) 18:02   No:8558     
Title: Re:無題    
>これで問題無いですよね?
 戻り値のチェック方法自体は問題ないですが、
なぜ Parseが3回も呼ばれるようになってしまったのでしょうか?

 しかも1回目と2回目は一切チェックしていないですし。


52ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,264ポイント)   Date: 2007/06/12(火) 18:31   No:8559     
Title: Re:無題    
Justyさん。レスありがとうございます。

>戻り値のチェック方法自体は問題ないですが、
>なぜ Parseが3回も呼ばれるようになってしまったのでしょうか?
>しかも1回目と2回目は一切チェックしていないですし。

すみません。よく理解出来ません。こういうことなんでしょうか?


if (!Parse (st, &p, &lop))

{

printf("error\n");

}
op = p[0];
p++;
if (!Parse (p, &p, &rop))

{

printf("error\n");

}


2倍のポイントを手に入れた! 438ポイント を手に入れた。

Name: Justy  ..ハッカー(114,829ポイント)   Date: 2007/06/12(火) 19:01   No:8561     
Title: Re:無題    
>こういうことなんでしょうか?
 そうです。
 ただ、errorと表示ながらもそのまま処理を何事もなかったかのように処理を続行しているのは気になりますが。


54ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,305ポイント)   Date: 2007/06/14(木) 13:45   No:8608     
Title: Re:無題    
Justyさん。お世話になってます。レスありがとうございます。

修正してビルドしたんですが、負数の-2147483648(int型の限界)
を入力すると強制的に-2147483647となってしまいます。これは
parse関数内のstrtolの仕様なんでしょうか?

ただ"-2147483648"自体はオーバフローしていないので
ちょっとおかしいと思うのですが、何処がいけないのでしょうか?


41ポイント を手に入れた。

Name: Justy  ..ハッカー(115,144ポイント)   Date: 2007/06/14(木) 14:48   No:8609     
Title: Re:無題    
>ちょっとおかしいと思うのですが、何処がいけないのでしょうか?
 あー、なるほど。
 たしかにこのままではその値は扱えませんね。


 Parse_factor()を見るとわかると思いますが、符号があった場合
ひとまずスキップして数字文字を見つけようとします。
 で、その数字文字を整数化した後、符号に従って符号変換をします。

 つまり、-2147483648の場合、符号を無視した数字 2147483648が INT_MAXを超える為、
strtolの結果が INT_MAXである 2147483647となり、その後符号を反転するので
-2147483647になってしまいます。

 一番簡単な解決方法としては(機種依存になりますが) strtolの代わりに
_strtoi64を使って解析し、その後、lop / ropが INT_MIN〜INT_MAXの範囲内に
あることをチェックするのが一番簡単だと思います。


315ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,425ポイント)   Date: 2007/06/14(木) 15:27   No:8611     
Title: Re:無題    
Justyさん。レスありがとうございます。

無事解決出来ました。ちなみにエラーメッセージをまとめるには
もっといい方法があるんでしょうか?(例えば関数化にしても、マクロにしても)
さすがにコードが見にくいので、こうした方がいいというようなことがあればお願いします。


120ポイント を手に入れた。

Name: Justy  ..ハッカー(115,516ポイント)   Date: 2007/06/14(木) 15:56   No:8613     
Title: Re:無題    
ちなみにエラーメッセージをまとめるには もっといい方法があるんでしょうか?
 今は用途別に関数を作っているのですね。
 見たところ、exitに渡す終了コードと文字列以外には違いはないようです。

 であれば、終了コードとエラーメッセージの文字列を引数に受け取るエラー関数を
用意してみてはどうでしょうか。

int error_exit(int exit_code, const char *message);

 こんな関数を用意して、エラーを検出したら
 
error_exit(-1, "0 division is a prohibition");

 のように使うカンジで。



#余裕があったら
int error_exit(int exit_code, const char *format, ...);
の形式にチャレンジしてもいいかもしれません。


372ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,457ポイント)   Date: 2007/06/14(木) 16:36   No:8615     
Title: Re:無題    
Justyさん。レスありがとうございます。

ちょっとやってみます!!


32ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,544ポイント)   Date: 2007/06/14(木) 18:53   No:8616     
Title: Re:無題    
一応作成してみたのですが、引数の設定が分からず
妥協してしまいました。折角教えて下さったのに申し訳ありません。

一応ソース添付しますので、何かありましたらご指摘お願いします。
ヘッダと分けておいたのですが、ビルドが面倒だと思うので一緒にしておきました。
余計に読みにくいとは思いますが、よろしくお願いします。


87ポイント を手に入れた。

Name: Justy  ..ハッカー(116,426ポイント)   Date: 2007/06/15(金) 02:48   No:8630     
Title: Re:無題    
>何かありましたらご指摘お願いします

 んーと

・ exitの多用
 どのルートを経由しても必ず exitで終わらせるのは、どうなんでしょう。
 exitしなければならない状態というのはよほどの異常事態です。
 できれば exitすることなく、普通に main関数を抜けるようにした方が、
いいのではないでしょうか。


・ エラーコードが直値
 定数を直接コードの中に埋め込むのはあまり良い方法とはいえません。
 例えばバッファサイズの 128とか、エラーコードとか。
 特に後者は exit_codeが 1とか言われてもさっぱり意味がわからないので、
何かしら defineや enumなどで名前を割り振っておくといいでしょう。


・ エラーの場合、式が表示されないことある。
 式の中にエラーがあった場合でも、入力された式を表示してから
エラーとした方がいいのではないでしょうか。


・ char st[128]
 mainの引数から 128文字以上入力されると Storage()内でバッファをオーバーしてしまい
不正なプログラムになります。
 128文字以上にならないようにしましょう。


・ lop / ropの範囲チェック
 四則演算の結果が出てからチェックしていますが、する前にした方がいいのではないでしょうか。


・ 式の最後に余計な文字があった場合
 "1+1a"のように最後に余計な文字があっても解析が成功しますが、これはいいのでしょうか。


・ テスト
 コードを書いてからビルドして、その後テストをするとき、
毎回毎回式をコマンドラインでキーボードから打つか or MSVCのコマンドライン引数の設定で
記入した内容を main関数の引数に渡していると思うのですが、面倒くさくないですか?

 そういうときはデバッグ向けに式をプログラムの中に埋め込んで、
自動的にテストできるようにしてはどうでしょうか。
 ついでにテスト用の式を配列にしておいて、複数の式を順次解析、結果表示していくように
していくと、様々なケースのテストを一度に行うことができますよ。

 参考までに改良したコードを載せておきます。
(添付のコードの mainの中の #if 1を #if 0にするとこのテストモードになります)



910ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,975ポイント)   Date: 2007/06/15(金) 11:17   No:8642     
Title: Re:無題    
Justyさん。レスありがとうございます。
ソース拝見しました。さすがJustyさん。
あぁ〜やはりプロっぽいコーディングですね。

質問があるのですが、エラーコードの数とエラーメッセージ一覧の個数が
一致していないと思うのですが、それは何故なんでしょうか?

// テーブルの数とエラーコードの数が一致するかどうか検証
// 範囲外なら codeを 0に

というコメント以下はどういうふうに読めばいいのでしょうか?


// エラーコード
enum
{
ERROR_CODE_NO_ERROR,
ERROR_CODE_INVALID_EXPRESSION,
ERROR_CODE_INT_OUT_OF_RANGE,
ERROR_CODE_INVALID_OPERATOR,
ERROR_CODE_DIVIDED_ZERO,
ERROR_CODE_MULTI_OVERFLOW,
ERROR_CODE_NUMBER_OF_UNUSUAL_ARGS,
ERROR_CODE_STRING_BUFFER_OVER,
ERROR_CODE_MAX
};

// エラーメッセージ一覧
void ErrorMessage(int code)
{
static const char * const message_list[] =
{
"unknown",
"Please input a correct expression",
"The range of the int type is exceeded",
"Please input the operator correctly",
"0 division is a prohibition",
"The over_flow learns by experience",
"Please input the argument correctly",
"Buffers of character string overflowed.",
};

// テーブルの数とエラーコードの数が一致するかどうか検証
StaticAssert(ArraySize(message_list) == ERROR_CODE_MAX,
message_list_size_and_ERROR_CODE_MAX_is_not_equal);

// 範囲外なら codeを 0に
if(code < 1 && code>=ArraySize(message_list))
code = 0;
printf("error : %s\n", message_list[code]);
}


431ポイント を手に入れた。

Name: asd  ..上級者(16,343ポイント)   Date: 2007/06/15(金) 11:29   No:8643     
Title: Re:無題    
横槍失礼します。

提示されたコードだけを読む限り、エラーコードには正常終了を表すコードが含まれているように思います。
(ERROR_CODE_NO_ERROR)

また関数などのエラーコードは負の数で返ってくることが多いのと、用意したエラーコード以上値が入ってきた場合に、範囲外にならないような補正が
// 範囲外なら codeを 0に
のくだりではないでしょうか。

間違っていたらゴメンナサイ。


155ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,916ポイント)   Date: 2007/06/15(金) 11:41   No:8644     
Title: Re:無題    
asdさん。素早いレスありがとうございます。

ではERROR_CODE_MAXがエラーコード以上の値が入った場合の処理
ということでよいのでしょうか?

マクロを忘れてました。
// 静的アサート(コンパイル時)
#define StaticAssert(eval, tag) typedef char StaticAssert_##tag_[1][(eval)]

アサートって引数が1つだと思ったのですが、これは自作ということですよね?


59ポイント を落としてしまった。

Name: Justy  ..ハッカー(117,428ポイント)   Date: 2007/06/15(金) 11:53   No:8645     
Title: Re:無題    
質問があるのですが、エラーコードの数とエラーメッセージ一覧の個数が
一致していないと思うのですが、それは何故なんでしょうか?

 一致していないように見えるだけだと思います。
 エラーメッセージ message_listの配列要素数は見ての通り8個あります。
 で、エラーコードは



ERROR_CODE_NO_ERROR, // 0・・・エラーではない
ERROR_CODE_INVALID_EXPRESSION, // 1・・・何かのエラー
ERROR_CODE_INT_OUT_OF_RANGE, // 2・・・何かのエラー
ERROR_CODE_INVALID_OPERATOR, // 3・・・何かのエラー
ERROR_CODE_DIVIDED_ZERO, // 4・・・何かのエラー
ERROR_CODE_MULTI_OVERFLOW, // 5・・・何かのエラー
ERROR_CODE_NUMBER_OF_UNUSUAL_ARGS, // 6・・・何かのエラー
ERROR_CODE_STRING_BUFFER_OVER, // 7・・・何かのエラー
ERROR_CODE_MAX // 8・・・エラーコードの数


 で、実際にエラーとして使われるのはERROR_CODE_NO_ERROR(1)〜ERROR_CODE_STRING_BUFFER_OVER(7)の
計7個ですが、enumにはエラーではないことを示すERROR_CODE_NO_ERRORもあるので
計8個となり、message_listの要素数と同じだけあります。

 ERROR_CODE_MAXは、特殊な使い方をするもので、エラーコード
としては使いません。
 実はエラーコードの数を表すのに使われます。


というコメント以下はどういうふうに読めばいいのでしょうか?
 asdさんの書かれている通りです。
 このErrorMessage関数から見ると codeに何が入ってくるかは予想できないので、
配列に対して不正なアクセスをしないようにしています。

 例えば codeが 100とか -100とかの状態で message_list[code]にアクセスしたら
まずいですよね?


 ちなみに StaticAssertは enumのエラーコード数と message_listの配列要素数を
比較していますが、これは片方に何か追加したのにもう片方の追加を
忘れたりしないようにする為の予防策です。

 双方の数が一致しないとコンパイル時にエラーがでるので、
実行時にエラーを出すより、気づきやすくなります。


アサートって引数が1つだと思ったのですが、これは自作ということですよね?
 自作ですね。
 そのソースのどこかにマクロが定義してあります。


1,002ポイント を手に入れた。

Name: @とんぷぅ〜  ..プログラマー(31,985ポイント)   Date: 2007/06/25(月) 09:47   No:8903 解決!     
Title: Re:無題    
遅くなりましたが皆様レス本当にありがとうございました。

管理人さん始め、Justyさん。その他大勢の方に回答をいただけ
大変助かりました。まだまだ未熟者ですがよろしくお願いします。



69ポイント を手に入れた。

Name: 管理人 [URL]  ..伝説のハッカー(377,674ポイント)   Date: 2007/06/25(月) 13:09   No:8904     
Title: Re:無題    
完成されました?! お疲れ様でした!
あまりお力になれず申し訳ないです^^;
これから大変でしょうけど、頑張ってください!


42ポイント を手に入れた。




 
[ 1 , ... ]
 
 
管理者画面   RSS   + Powered By 21style +