ここから本文です

解決済みの質問

知恵コレに追加する

C言語について

f_animal_nameさん

C言語について

==============================================
void itoa(char *y, int x)
{
int i, j, k, l, m, n, o = x;
char a[80];

if (x < 0) {
x = x * -1;
}

for (l = 1, m = 1, i = 0, n = x; n != 0; i++) {
n = n / 10;
l = l * 10;
j = x - n * l;
k = j / m;
m = m * 10;

if (k == 0) {
a[i] = '0';
}
else if (k == 1) {
a[i] = '1';
}
else if (k == 2) {
a[i] = '2';
}
else if (k == 3) {
a[i] = '3';
}
else if (k == 4) {
a[i] = '4';
}
else if (k == 5) {
a[i] = '5';
}
else if (k == 6) {
a[i] = '6';
}
else if (k == 7) {
a[i] = '7';
}
else if (k == 8) {
a[i] = '8';
}
else if (k == 9) {
a[i] = '9';
}
}
if (o >= 0) {
a[i] = '\0';
}
else if (o < 0) {
a[i] = '-';
a[i+1] = '\0';
i++;
}
while (i >= 0) {
*y = a[i - 1];
y++;
i--;
}
*y = '\0';
}
==============================================


for (l = 1, m = 1, i = 0, n = x; n != 0; i++)
内を綺麗に書き直したいのですが、うまく書き直せません・・・

ご指導お願いします!

ちなみに、itoa関数を作っています。

違反報告

ベストアンサーに選ばれた回答

quickbrwnfoxjumpsoverthelazydogさん

比較の羅列は皆さんご指摘の通り。

でも、それ以外の変数の使い方もよろしくない。
まず、変数の名前。名は体を現すべきで、lmno...ってのはなんだかわからん。ijkあたりは慣習的にカウンタとして使いますけれど。

それから、剰余の演算(わり算の余りを求める)は知っておくべき。
n = n / 10;
l = l * 10;
j = x - n * l;
k = j / m;
m = m * 10;
で、求めたいのはkなんだろうけど、これは
digit=n%10; /* kじゃなくてきちんと名を付けよう。一桁だからdigit。nは後でなくすつもりなので放置 */
n/=10;
で書けてしまう。つまりj,l,mは無駄な変数。

また、符号の判別用にoをとってxを代入しておき、xは絶対値をとって計算用にnに代入し、その後xは変化していない。保存すべき変数とつぶしていい変数を整理すれば、
if(x>=0) {
sgn=1; /* oじゃなくて意味のある名前 */
}else {
sgn=-1;
}
x=x*sgn; /* xを絶対値に */
以降xが変化しても困らないのでnは不要。

もひとつ。forは、どちらかというと規定回数回すようなループに使う。回数以外の何かがループの継続条件ならwhile / do - whileを使った方がいいと思う。

作業用のバッファを80バイトもとっているのは...まぁいいか。64bit intでもそんなに要らないのは明らかだと思うけど、安全な方向だし害はほとんどないし。

あと、引数xに0が渡されたときにもおかしなことにならないように対策が必要でしょう。

追記。もう一つ気がついた。
while (i >= 0) {
*y = a[i - 1];
これって、i=0の時もループ継続だけど、a[-1]にアクセスするので不可。

結果、関数の中身としてはこんな感じでどぉ?
sgn=1; i=0;
if(x==0){
buf[i++]='0';
}else if(x<0){
sgn=-1;
}
x*=sgn;
while(x!=0){
digit=x % 10;
x /= 10;
buf[i++]= digit + '0';
}
if(sgn<0){
buf[i++]='-';
}
while(i>0){
*y++=buf[--i];
}
*y=0;

  • 違反報告
  • 編集日時:2010/12/7 13:36:29
  • 回答日時:2010/12/7 09:10:06

質問した人からのコメント

  • ほぉ~
    勉強になりました!

    回答してくださった皆様、本当にありがとうございました!
  • コメント日時:2010/12/7 20:33:46

グレード

この質問・回答は役に立ちましたか?
役に立った!

お役立ち度:お役立ち度 1点(5点満点中)1人が役に立つと評価しています。

ベストアンサー以外の回答

(4件中1〜4件)

並べ替え:回答日時の
新しい順
古い順

 

biwyfiさん

まずは、数値→文字変換を一個にまとめる。
#define itoc(c) ((c)+'0')
で取り合えず代用。
ちなみに、ASCIIコードでない限り、数字の文字が連続している保証は無い。
例えば、「壱弐参...」は不連続だから、個別変換は全くの間違いではない。
(でも、その場合は変換表を使うのが普通)

で、無駄に大量の作業変数を使用しているのは、先の指摘通りなのだが、それ自体は、当人が分かり易ければ問題は無い。
が、同一変化は一つにまとめないといけない。
lとmが共に10倍され、nが1/10になるんだから、本質的に全部一つになる筈。
あと、作業用変数も、実作業直前で宣言するのが妥当。これを行うと、
int n = x/ (10*m);
int l = m*10;
int j = x - n*l;
int k = j / m;
m*=10;
とループ変数がm一個にまとまり、括弧を使って、作業変数を除去すると
int k =(x-(x/(m*10))*10*m)/m;
m*=10;
になる。

で、“m*10”が大量に出るのは、「何か」がおかしいから。
それから、ループ内で変更する変数は、for文で明記するべき。
あと、現状では、数値0が表示出来ない。

正しくまとめると、こうなる。
int base = 10;
for (i=0, m=base; ; i++, m*=base) {
int k = (x - (x/m)*m)/(m/base);
a[i] = itoc(k);
if (x<m) break;
}
数値の0を表示させるので、初期条件を省略した。
そのままでは、当然無限ループになるので、breakで脱出する。
あと、数値が剥き出しなのは気持ち悪いので、変数を一個追加した。
(これで、itocを工夫すれば、16進変換も対応してしまう)

do-while文を好む人も居るが、個人的には、ループ変数が明記されるfor文が好み。
breakでの脱出を嫌う人も居るが、初期条件で省略してあるのだから、何処かでbreakして居るのが自明なので問題は無い。
尤も、この記述では、mがINT_MAXを超えると異常動作する。

元の記述を重視して敢えて奇妙な記述を使ったが、余りを‘x%base’で求めて、‘x/=base’とするのが、本来の姿。
でも、ここは、練習を兼ねて、記述しない事にする。

それから、引数xを保存しながら、作業用途で代用破壊するのは好ましくない。
作業変数に格納保存するなら、作業変数の方を変更するのが筋。

それ以前に、符号は文字は、出力の先頭に付くのだから、最初に処理してしまえば、何の保存も不要。
if (x<0) *y++ = '-';
をxの絶対値化前に追加すれば済む話。

最後のwhile文も、記述が致命的に間違って居るのは、先の回答者の指摘通り。
で、iをループにするのだから、ここも、for文が自然。
for (; i>=0; i--) *y++ = a[i];
*y='\0';
で、完成かな?
「あれっ」と思うかも知れないが、実は先の修正でbreakで脱出する仕様に変更したので、iの初期値が、実は1減っているのだ。

pyon_naniwa2001さん

念のため、
数字0~9の文字コードがこの順で連続しているのは、Cの規格で保証されている。

とりあえず、

>if (k == 0) {
>a[i] = '0';
>}
>...
>else if (k == 9) {
>a[i] = '9';
>}
a[i] = '0' + k;

  • 違反報告
  • 編集日時:2010/12/7 17:27:36
  • 回答日時:2010/12/7 00:22:40

umiushi711さん

void itoa(char *y, int x)
{
__sprintf(y, "%d", x);
}

k032yfさん

f_animal_nameさん


if (k == 0) {
a[i] = '0';
}
else if (k == 1) {
a[i] = '1';
}
else if (k == 2) {
a[i] = '2';
}
else if (k == 3) {
a[i] = '3';
}
else if (k == 4) {
a[i] = '4';
}
else if (k == 5) {
a[i] = '5';
}
else if (k == 6) {
a[i] = '6';
}
else if (k == 7) {
a[i] = '7';
}
else if (k == 8) {
a[i] = '8';
}
else if (k == 9) {
a[i] = '9';
}

これをまとめると
if(k >= 0 && k < 10)
a[i] = k +'0';

この質問に付けられたタグ

タグとは

あなたにおすすめの解決済みの質問

c言語分かる方。 #include <stdio.h> #include <ctype.h> int main() { for(;) { char p[1024]; char * result; int i; int size[1024]; result = gets(p); if(result == NULL) break; i=0; for(;){ if (i >=1024) break; if(p[i...
C言語で、独自のitoa関数を作りたいのですが・・・ 初めて質問させて頂きます。 初歩的な質問かとは思いますが、どなたか分かる方、ご教授頂ければと思います。 【実装仕様】 char *myitoa(int value, char *buff, int radix); 第1...
C言語 エラーをみつけてください 何度コンパイルしてもエラーが改善されません warning 25行目 void function way not return a value function isempty →return(1) warning 29行目 void function way not return a value...

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。

お客様自身の責任と判断で、ご利用ください。

話題のキーワード

[カテゴリ:C言語関連]

ただいまの回答者

21時48分現在

4474
人が回答!!

1時間以内に8,982件の回答が寄せられています。

>>回答ひろばに行く