初めまして。一難民と申します。
私は今、配列の文字列を参照してローマ数字をアラビア数字に変換するプログラムを、
emac(Finderバージョン10.3.3)付属のXcode(バージョン1.5)を用いて作っています。
大体の面においてはうまくいくのですが、一カ所'L'についての配列でおかしな症状がでています。
1,本来+5されるべき場所がなぜか+10される
2,四桁目以降何もない場合なぜかそこでもう一度+10される
という症状がでています。
皆さんからみれば簡単なことと思いますが、どうかよろしくお願いします。
コード
#include <stdio.h>
int main (int argc, const char * argv[/url]) {
int o,t,h,th,m;
char r[100];
o=0;
t=0;
h=0;
th=0;
printf("入力してください ");
scanf("%99s",&r);
for(m=0;m<100;m++){
if(r[m-1]=='C' && r[m]=='M'){
h=h+9;
}
if(r[m-1]!='C' && r[m]=='M'){
th=th+1;
}
if(r[m-1]=='C' && r[m]=='D'){
h=h+4;
}
if(r[m-1]!='C' && r[m]=='D'){
h=h+5;
}
if(r[m-1]=='X' && r[m]=='C'){
t=t+9;
}
if(r[m]=='C' && r[m+1]=='D'){
}
if(r[m-1]!='X' && r[m+1]!='M' && r[m]=='C' && r[m+1]!='D'){
h=h+1;
}
if(r[m-1]=='X' && r[m]=='L'){
t=t+4;
}
if(r[m-1]!='X' && r[m]=='L'){
t=t+5;
}
if(r[m]=='X' && r[m+1]=='C'){
}
if(r[m]=='X' && r[m+1]=='L'){
}
if(r[m-1]=='I' && r[m]=='X'){
o=o+9;
}
if(r[m+1]!='C' && r[m+1]!='L' && r[m-1]!='I' && r[m]=='X'){
t=t+1;
}
if(r[m-1]=='I' && r[m]=='V'){
o=o+4;
}
if(r[m-1]!='X' && r[m]=='L'){
t=t+5;
}
if(r[m]=='I' && r[m+1]=='X'){
}
if(r[m]=='I' && r[m+1]=='V'){
}
if(r[m+1]!='V' && r[m+1]!='X' && r[m]=='I'){
o=o+1;
}
if(r[m]=0){
m=m+1000;
}
printf("%d%d%d%d\n",th,h,t,o);
}
printf("%d%d%d%d",th,h,t,o);
return 0;
}
文字列の参照について
Re:文字列の参照について
内容の理解まではできませんが
m=0 のとき
if(r[m-1]!='C'
でアクセス違反起こしてます
また m=99 のとき
if(r[m]=='X' && r[m+1]=='C'){
m+1 = 100
r[100] にアクセスしてます
これもアクセス違反ですね
あと
気になったので
m=0 のとき
if(r[m-1]!='C'
でアクセス違反起こしてます
また m=99 のとき
if(r[m]=='X' && r[m+1]=='C'){
m+1 = 100
r[100] にアクセスしてます
これもアクセス違反ですね
あと
if(r[m-1]=='X' && r[m]=='L'){ t=t+4; } if(r[m-1]!='X' && r[m]=='L'){ t=t+5; } ... if(r[m-1]!='X' && r[m]=='L'){ t=t+5; }同じif分が3つありますが
気になったので
Re:文字列の参照について
> 大体の面においてはうまくいくのですが、一カ所'L'についての配列でおかしな症状がでています。
> 1,本来+5されるべき場所がなぜか+10される
> 2,四桁目以降何もない場合なぜかそこでもう一度+10される
そのように、思った動きをしないプログラムを
仕様どおりに持っていく工程を「デバッギング」といいます。
そういう重要な工程を人任せにして、
質問者さんのC言語に関する実力が本当に付くといえるのでしょうか。
「C言語の実力なんかどうでもいい。課題の答えさえ得られればよい」とか
いうのであれば、まあそれでもいいですけれどね。
なお、プログラムにおいて「なぜかそうなる」ということは
事実上ないといってよく、「書いたとおりに動いている」というのがホントのところです。
> 1,本来+5されるべき場所がなぜか+10される
> 2,四桁目以降何もない場合なぜかそこでもう一度+10される
そのように、思った動きをしないプログラムを
仕様どおりに持っていく工程を「デバッギング」といいます。
そういう重要な工程を人任せにして、
質問者さんのC言語に関する実力が本当に付くといえるのでしょうか。
「C言語の実力なんかどうでもいい。課題の答えさえ得られればよい」とか
いうのであれば、まあそれでもいいですけれどね。
なお、プログラムにおいて「なぜかそうなる」ということは
事実上ないといってよく、「書いたとおりに動いている」というのがホントのところです。

Re:文字列の参照について
1.についてはdicさんが指摘しているところが原因だと思います。
ただ、if文の条件が全く同じなのはdicさんが挙げた3つのうち後ろの2つです。
2.について調べるとき、
数字の表示を
printf( "%d %d %d %d\n ",th,h,t,o);
にした方が良いような気がします。
ただ、if文の条件が全く同じなのはdicさんが挙げた3つのうち後ろの2つです。
2.について調べるとき、
数字の表示を
printf( "%d %d %d %d\n ",th,h,t,o);
にした方が良いような気がします。
Re:文字列の参照について
2.について
scanfで取得した後の文字列を調べてみたら、
入力した文字列の後ろに0(終端文字'\0')が来て、
その後ろででたらめに文字が入っているようです。
この文字によって変数が+されるのではないでしょうか。
これが原因だとしたら
'\0'が出たところで判定をやめれば、
何もないと思っているところで変数が変わることはなくなるでしょう。
scanfで取得した後の文字列を調べてみたら、
入力した文字列の後ろに0(終端文字'\0')が来て、
その後ろででたらめに文字が入っているようです。
この文字によって変数が+されるのではないでしょうか。
これが原因だとしたら
'\0'が出たところで判定をやめれば、
何もないと思っているところで変数が変わることはなくなるでしょう。
Re:文字列の参照について
質問者が答えだけほしかったのかそれともヒントがほしかったのかを
書き込みをみて判断してから書きこみたかったのですが、
過去ログに落ちたのでプログラムを考えたときのメモと
ソースコード(cpp)を載せます。
ローマ数字について
I:1
V:5
X:10
L:50
C:100
D:500
M:1000
基本は大きな数字を左に書き、全ての数字の和がその数を表す。
しかし、4,9などは減算則が用いられる。
小さい数を大きい数の左側に置くと右の数から左の数を減じたものが示す数字となるというもの。
この減算則は右の数が左の数のちょうど5倍または10倍で左の数がI,X,Cのときに使われる。
EXCELのROMAN()関数は0~3999までをローマ数字に変換することができる。
プログラム
ローマ数字をアラビア数字にする
まずは文字列をキーボードから取得し表示するという基本のおさらい
scanf(const char *_Format,...)で取得し、
printf(const char *_Format,...)で出力することができる。
さて、プログラムを考える。
ローマ数字は文字列として扱い、アラビア数字はint型の変数一つで表したい。
というわけで文字列をinput[64],アラビア数字をoutputとする。
まずは文字列の取得
これはscanf("%s",input)でできる。
ただし、入力は常に正確なものであると仮定する。
次に左から文字を見ていく。
基本的にはそれぞれの文字が表わす数字を足していけばよいのだが
時々減算則が混ざっていることがある。これに注意しなければならない。
これに関する処理はI,X,Cの次にそれぞれ(V,X),(L,C),(D,M)があるかどうかを見て、
もしあった場合は対応した数字を足し、次の判定をとばすというようにする。
終わりになっていたらループから抜ける。
以上より書いたcppファイルがこちら。
なお、以下を実行してみたところ、
ウィキペディアの表にのっている3999までの数字については
期待通りの値が出た。
#include <stdio.h>
int main(){
char input[64];
int output=0;
int i=0;
scanf("%s",input);
while(input!='\0' && i<63 ){
switch(input){
case 'I':
switch(input[i+1]){
case 'V':
output+=4;
i++;
break;
case 'X':
output+=9;
i++;
break;
default:
output+=1;
break;
}
break;
case 'V':
output+=5;
break;
case 'X':
switch(input[i+1]){
case 'L':
output+=40;
i++;
break;
case 'C':
output+=90;
i++;
break;
default:
output+=10;
break;
}
break;
case 'L':
output+=50;
break;
case 'C':
switch(input[i+1]){
case 'D':
output+=400;
i++;
break;
case 'M':
output+=900;
i++;
break;
default:
output+=100;
break;
}
break;
case 'D':
output+=500;
break;
case 'M':
output+=1000;
break;
}
i++;
}
printf("%d\n",output);
return 0;
}
書き込みをみて判断してから書きこみたかったのですが、
過去ログに落ちたのでプログラムを考えたときのメモと
ソースコード(cpp)を載せます。
ローマ数字について
I:1
V:5
X:10
L:50
C:100
D:500
M:1000
基本は大きな数字を左に書き、全ての数字の和がその数を表す。
しかし、4,9などは減算則が用いられる。
小さい数を大きい数の左側に置くと右の数から左の数を減じたものが示す数字となるというもの。
この減算則は右の数が左の数のちょうど5倍または10倍で左の数がI,X,Cのときに使われる。
EXCELのROMAN()関数は0~3999までをローマ数字に変換することができる。
プログラム
ローマ数字をアラビア数字にする
まずは文字列をキーボードから取得し表示するという基本のおさらい
scanf(const char *_Format,...)で取得し、
printf(const char *_Format,...)で出力することができる。
さて、プログラムを考える。
ローマ数字は文字列として扱い、アラビア数字はint型の変数一つで表したい。
というわけで文字列をinput[64],アラビア数字をoutputとする。
まずは文字列の取得
これはscanf("%s",input)でできる。
ただし、入力は常に正確なものであると仮定する。
次に左から文字を見ていく。
基本的にはそれぞれの文字が表わす数字を足していけばよいのだが
時々減算則が混ざっていることがある。これに注意しなければならない。
これに関する処理はI,X,Cの次にそれぞれ(V,X),(L,C),(D,M)があるかどうかを見て、
もしあった場合は対応した数字を足し、次の判定をとばすというようにする。
終わりになっていたらループから抜ける。
以上より書いたcppファイルがこちら。
なお、以下を実行してみたところ、
ウィキペディアの表にのっている3999までの数字については
期待通りの値が出た。
#include <stdio.h>
int main(){
char input[64];
int output=0;
int i=0;
scanf("%s",input);
while(input!='\0' && i<63 ){
switch(input){
case 'I':
switch(input[i+1]){
case 'V':
output+=4;
i++;
break;
case 'X':
output+=9;
i++;
break;
default:
output+=1;
break;
}
break;
case 'V':
output+=5;
break;
case 'X':
switch(input[i+1]){
case 'L':
output+=40;
i++;
break;
case 'C':
output+=90;
i++;
break;
default:
output+=10;
break;
}
break;
case 'L':
output+=50;
break;
case 'C':
switch(input[i+1]){
case 'D':
output+=400;
i++;
break;
case 'M':
output+=900;
i++;
break;
default:
output+=100;
break;
}
break;
case 'D':
output+=500;
break;
case 'M':
output+=1000;
break;
}
i++;
}
printf("%d\n",output);
return 0;
}