みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

上手く表示できない。(C言語)

お世話になります。capeofdragonと申します。

Visual Studio 2008 ProでC言語を書いたのですが、
上手く表示されません。
やりたいことは、
256と言う、int型の値を、十分の一倍し、
25.6
と言う、文字列に置き換えて、
文字列として表示させることです。
以下にソースを添付します。

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *ftoa(int num)
{
char Num[10];
char rNum[10];
char decimal1[1];
char integer[2];
_itoa_s(num, Num, 10);
integer[0] = Num[0];
integer[1] = Num[1];
decimal1[0] = Num[2];
if(integer[0] == '0')
{
rNum[0] = integer[1];
rNum[1] = '.';
rNum[2] = decimal1[0];
return rNum;
}
else
{
rNum[0] = integer[0];
rNum[1] = integer[1];
rNum[2] = '.';
rNum[3] = decimal1[0];
return rNum;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char *pWk;
int a = 256;
pWk = ftoa(a);
printf("pWk = %s\n",pWk);
return 0;
}

コンパイルすると、
pWk =
と表示され、
pWk = 25.6
と表示されません。

また、sprintfを使いたいのですが、
高速化のために、キャラクター操作とかけ算、シフトレジスタなどだけで
シンプルに作成したいと考えています。
お手数をお掛け致しますが、
ご教授宜しくお願い致します。

投稿日時 - 2012-04-13 11:59:03

QNo.7418625

困ってます

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(9)

ANo.9

>終端文字'\0'分の領域まで確保していないと、理解しています。

それだけじゃないですが。
それがわかってないからまた同じ事してるし(他の方も指摘されてますが)
まともにプログラムが組めないレベルで高速化などを考えたところでろくな事はありません(実は遅速化だったりまともに動かなかったり)。

前にもいいましたが勉強をしっかりやり直した方がいいです。

どうでもいいですが一番高速な方法書いておきましょうか

// valは0~1000限定
const char *ftoa(int val)
{
static const char *numtbl[] = {
"0.0",
"0.1",
"0.2",

"99.9",
"100.0",
}
return numtbl[val];
}

投稿日時 - 2012-04-14 10:33:38

ANo.8

itoaは使っていいけどsprintfは使っちゃダメって、なんかチグハグな気がするのは私だけ?

実数を使わないっていう制約なら
int _tmain(int argc, _TCHAR* argv[])
{
int a = 256;
char pWk[10];
sprintf(buffer, "%d.%d", a/10, a%10);
printf("pWk = %s\n",pWk);
return 0;
}
でもいいでしょうね。

関数化するなら、グローバル変数にするんじゃなくて、作成した文字列を格納する領域を呼び出し元から渡すようにするのが良いでしょう。

void my_func(int num, char* buffer)
{
if (0 <= num && num < 1000)
{
sprintf(buffer, "%d.%d", a/10, a%10);
} else
{
*buffer = 0;
}
}
nt _tmain(int argc, _TCHAR* argv[])
{
int a = 256;
char pWk[10];
my_func(a, buffer);
printf("pWk = %s\n",pWk);
return 0;
}

投稿日時 - 2012-04-13 17:21:51

ANo.7

Wr5

>0の時は、何も表示されませんでした。
>if分を用いて、0の時は、
>0.0
>を表示させるようにして、エラーを回避しました。

でしたら、1の時は?
2の時は?
3の時は?
 :
9の時は?
10の時は?

という確認はしましたか?

投稿日時 - 2012-04-13 15:29:34

ANo.6

> 実際、計測されるのは、
> 300以下から0以上となります。

では、試しに0の時にあなたの考えた方法で問題が出ないか検証してみましょう。

投稿日時 - 2012-04-13 15:06:55

補足

ご回答有難うございます。
0の時は、何も表示されませんでした。
if分を用いて、0の時は、
0.0
を表示させるようにして、エラーを回避しました。
ご指摘有難うございます(^^)。

投稿日時 - 2012-04-13 15:17:09

ANo.5

引数は 100以上 (1000未満) に限定してるんだっけ?

投稿日時 - 2012-04-13 13:29:12

補足

1000未満を想定しています。
実際、計測されるのは、
300以下から0以上となります。

これを例えば、
300なら30.0に、
196なら19.6に、
25なら、25.0に、
表示したい、
と考えています。

投稿日時 - 2012-04-13 14:00:49

ANo.4

Wr5

>最後の「また」以降が何を意味するのかさっぱり分からん.

sprintf()相当(低機能版?)の、いわゆる「車輪の再発明」かと…。
# strchr()相当の…ってのならやったことはありますけどねぇ。
# ShiftJISでの問題回避の為。とはいえ、いまのCランタイムで対応しているとは思いますけどね。(ロケールの設定とか必要かもしれませんが)

下手に「高速化だ~」とか「シンプル版だ~」とかやって無意味にバグを盛り込むリスクを負うよりは、
既存のライブラリ使った方がマシでしょう。
# 先の通り、再発明することもたまにありますけどね……。


本来の問題点については既に指摘回答ついていますのであえて回答はしませんが。
>char decimal1[1];
とか
>decimal1[0] = Num[2];
とか、ちょっと……。
# 言語仕様的にはありなんでしょうけど。

投稿日時 - 2012-04-13 12:57:06

ANo.3

文字列終端の\0を入れる処理も抜けてますから、変数をグローバルにすれば解決というわけにはいかないでしょう。

ちゃんと勉強しなおすことをお勧めします。

投稿日時 - 2012-04-13 12:43:37

ANo.2

プログラムを実行すると、

> int _tmain(int argc, _TCHAR* argv[])
> {
> char *pWk;

pWkという変数名で、char型のポインタ変数が確保されます。

> int a = 256;
> pWk = ftoa(a);

256の値を引数として、ftoa関数が呼び出されます。
ftoa関数の中では、

> char *ftoa(int num)
> {
> char Num[10];
> char rNum[10];

~様々な処理をした結果~

> return rNum;

で、関数内のローカル変数のアドレスを返しています。
この際、関数内のローカル変数の内容やアドレスは、関数から抜けた際に保証が無くなります。
そのため、かつては関数内のローカル変数の値を指していたが、mainに戻った後はなんだか分からないアドレスを、

> printf("pWk = %s\n",pWk);

として表示しようとした結果、(運良くセグメンテーション違反なんかにならずに)何も表示されないって状態になっているって事だと思います。

--
取りあえず動作すればって対処法だと、

char rNum[10];

を関数の中から出して、ソースの先頭に持って来てグローバル変数にしてしまえば、動作するハズ。
(対処の方策としては、最悪の部類ですが…。)

--
C言語の最大の難関、ポインタの所で説明や理解は難しいところですが、
デバッグの方法としては、

char rNum[10];

の直後に、

printf("rNum[10]のアドレスは%x\n", rNum)
printf("rNum[0]の内容は%c\n", rNum[0])

などとして、ポインタ変数=アドレスを入れる変数って事で、何番地のアドレスが入っていて、そのアドレスに格納されている値は?とかを意識するってのが、自分の場合は分かりやすかったです。

投稿日時 - 2012-04-13 12:24:07

お礼

ご回答有難うございます。

グローバル変数を用いるのは不本意でしたが、
ご回答を参考にして、作った所、
本意の表示が出来ました。

short型を受け取って、
小数点第一までの実数表記の文字列配列を、
表示させる関数に、文字列配列の変数を入れて、
表示させたかったと言う、背景があります。

extern void _kPutTextXY(short ACol,short ARow,short AColor,short char *AStr)
{
textcolor(AColor);
gotoxy(ACol+1.ARow+1);
cprintf("%s",AStr);
}
と言う、関数がありまして、
_kPutTextXY(pCol,Row,pColor,pWk)
のpWkの場所に、グローバル変数のrNumを入れることで、
動作しました。
本来なら、sprintfなどで、pWkに実数の文字列を、入れれば良いのですが、
実数は用いない仕様になっており、
sprintf(pWk,"%.1f A",stChnl[pCnt].mMesCurrent);
とすると、エラーになります。
stChnl[pCnt].mMesCurrentはshort型の値。

丁寧なご対応有難うございました。
自分なりに、もう一度良い方法ないか確かめてみます。
また、何かありましたら、宜しくお願い致します。

投稿日時 - 2012-04-13 15:34:22

ANo.1

最後の「また」以降が何を意味するのかさっぱり分からん.

とりあえず
http://okwave.jp/qa/q7416900.html
の #4 で何を言われたか, 理解できていますか?

投稿日時 - 2012-04-13 12:22:08

補足

回答有難うございます。
終端文字'\0'分の領域まで確保していないと、
理解しています。

投稿日時 - 2012-04-13 15:07:44

あなたにオススメの質問