質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
char

charは文字データ型を指します。一文字分の文字コードの格納を想定としている型です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

7回答

2303閲覧

C言語で10進数をn進数に変換するプログラムの動作

misaki_saki

総合スコア10

char

charは文字データ型を指します。一文字分の文字コードの格納を想定としている型です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

0グッド

2クリップ

投稿2019/08/05 08:08

前提・実現したいこと

初学者ですが、大学院入試のためにC言語を勉強しています.
コードの内容について分からない箇所があり,教えていただきたいです.

下に載せたF(n,b)という関数について,

(1)この関数はどのような値を返すか (2)この関数が正常に動作するbの最大値を求めよ (3)printf("%s\n",F(428,16))とprintf("%s\n",F(226,4))はそれぞれどのような値を返すか

という問題がありました.

試したこと

問題を解いているときには気づけなかったのですが...
実際に記述して試してみたところ「10進数のnをb進数に置換する」プログラムのようだとわかりました
また文字列のoutbの中身がlまでなのでbの最大値は22(22進数まで変換できる)ともわかりました
(3)についても答えはプログラムを実行することで得られました.

わからないこと

関数Fの中身について次のことが分からず,教えていただきたいです.

  • 最初のstaticも含めてiが何を表しているのか
    符号つきの2進数のように符号を表しているのかと思いましたが,それらは表示されないのでしょうか?

 また,66を最上位だと思うと,i=65がどうなっているのか疑問です


  • outb[i]の右辺がどうなっているのか

 "0123456789abcdefghijkl"[n%b]という箇所はどのような動作をするのでしょうか.
また教本には同様の例が載っておらず,このようにクォーテーションで囲まれた配列に名前があれば教えていただけるとありがたいです


  • なぜ最後にreturnするのが&out[i+1]なのか

 コードから実際に&をとるとエラーが出てしまいますが,ポインタでは文字列のアドレスが表示されてしまうのではないでしょうか?
文字列もポインタ?のような感じがするのでポインタのポインタのような印象を受けてしまい,困惑しています.

お手数ですが上の3点について教えていただけるとありがたいです.お願いします.

該当のソースコード

C

1#include<stdio.h> 2 3char* F(int n,int b){ 4 static char outb[66] = {0}; 5 int i = 64; 6 for(; n>0 && i>0 ; --i,n /= b) outb[i] = "0123456789abcdefghijkl"[n%b]; 7 return &outb[i+1]; 8} 9 10int main(){ 11 printf("%s\n",F(428,16)); 12 printf("%s\n",F(226,4)); 13 return 0; 14}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答7

0

目的は、このプログラムを自分で読めるようになることですよね?
質問が、かなりとんちんかんなレベルなので、まずはCをちゃんと勉強するところから始めないとどうしようも無いかと思います。

投稿2019/08/05 08:28

otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2019/08/05 08:36

特に、「Cに於ける文字列とは、具体的に何を意味するのか?」のあたりを理解するようにして下さい。
退会済みユーザー

退会済みユーザー

2019/08/05 11:49

c言語の規約又は参考書は有りますか?
guest

0

最初のstaticも含めてiが何を表しているのか

static を付けることで変数はこの関数を抜けても存在することになります。
これをしないと、関数を抜けると消滅してしまいますんで、outbは返り値にできません
変数宣言時の初期化によりoutb[65]は0が入ってます

"0123456789abcdefghijkl"

文字列、つまりは文字の配列です。
配列であれば、後ろに[]をつけてその要素にアクセスできます

なぜ最後にreturnするのが&out[i+1]なのか

これはこの関数の動作を追っていきましょう。
i+1でないとここではダメです

投稿2019/08/05 08:28

y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

次のコードを研究してみてください。

c

1#include <stdio.h> 2#include <string.h> 3 4const char * NUMS = "0123456789abcdefghijkl"; 5 6char* func(int n, int base) { 7 static char outb[66]; 8 int i = 64; 9 10 for(; n > 0 && i > 0 ; --i, n /= base) { 11 outb[i] = NUMS[n % base]; 12 } 13 return &outb[i + 1]; 14} 15 16char* func_x(int n, int base) { 17 static char outb[5]; 18 strcpy(outb, "____"); 19 int i = 4; 20 for(; n > 0 && i > 0 ; --i, n /= base) { 21 outb[i] = NUMS[n % base]; 22 printf("%s ", outb); 23 } 24 return &outb[i + 1]; 25} 26 27int main() { 28 for (int i = 0; i < 32; i++) { 29 printf("%s ", func(i, 16)); 30 } 31 printf("\n"); 32 33 for (int i = 0; i < 32; i++) { 34 printf("%s ", func(i, 4)); 35 } 36 printf("\n"); 37 38 for (int i = 0; i < 32; i++) { 39 printf(" -> %s\n", func_x(i, 4)); 40 } 41 printf("\n"); 42}

実行例
イメージ説明

投稿2019/08/05 13:05

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

実際に記述して試してみたところ「10進数のnをb進数に置換する」プログラムのようだとわかりました

いいえ、違います。

int の n のうち、正の数を b進数文字列に変換したものを返します。
0 および負の数の場合、""(長さ 0 の文字列)を返します。

また、int の値は、プログラム内部では 10進数ではありません。
内部表現は 2進数ですが、2進数文字列ではありません。
F(0xFF, 10) は "255" を返しますが、16進数を 10進数に変換したのではありません。
0xFF を内部2進表現に変換するのはコンパイラです。

b に 2 を指定したときの返却値は 2進数文字列です。
正確にいうと、2進数文字列の先頭文字へのポインタを返します。

質問だけでなく回答にもいくつか間違いがあります。

文字列の終端の '\0' は NULL とは意味が異なります。
C では NULL はポインタとして扱います。

static char outb[66] = { 0 }; という初期化では、
outb[0] だけでなく、outb[0]~outb[65] のすべてが 0 に、
すなわち '\0' に初期化されます。= { 0 } がなくても、
この場合、static があるので、すべて 0 に初期化されます。

投稿2019/08/05 12:03

編集2019/08/05 12:04
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

最初のstaticも含めてiが何を表しているのか

変換した文字を入れるためのインデックスですね。
n進数に変換する場合、1の位から求めていくことになります。初期値としてi=64としているのはout[65]にはNULLを入れる必要があるためです。(C言語の文字列は必ずNULLで終わる必要がある)

outb[i]の右辺がどうなっているのか

"0123456789abcdefghijkl"[n%b]という箇所はどのような動作をするのでしょうか.

これは、変換文字列を直接宣言しているのでわかりにくいかもしれませんが、"0123456789abcdefghijkl"の部分は文字列ですが実際にはchar型の配列になります。その配列を[n%b]でどの文字を取ってくるのかを決めているわけです。

c

1static char[] str = "0123456789abcdefghijkl"; 2outb[i] = str[n%b];

と分けて書いたほうがわかりやすいかもしれませんね。

なぜ最後にreturnするのが&out[i+1]なのか

out配列には1桁目から順に入っていくことになります。つまりout[64]から順にout[63], [62], ・・・ということです。
求めたn進数の文字列が必ず65桁になるわけではありません。F(15, 2)だと4桁
(1111)ですよね。なので、必要な桁分だけ返すために&out[i+1]となっているのです。
動作を1つ1つ追っかけていけばわかると思いますよ。

ちなみに、"0123456789abcdefghijkl"なので、22進数まで変換可能ということですね。(おっと、(2)の答えを書いてしまった。まあいいか)

投稿2019/08/05 09:03

編集2019/08/05 09:04
PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

outb[i]の右辺がどうなっているのか

"0123456789abcdefghijkl"[n%b]という箇所はどのような動作をするのでしょうか.

実際に数値を与えて考えると分かるはずです。
とりあえず、問題の最初の例:n=428、b=16でいくと、
n%bは12
それを添字に入れて考えると
"0123456789abcdefghijkl"[12] は
文字列の「c」のところのアドレス(ポインタ)ですね。

なぜ最後にreturnするのが&out[i+1]なのか

outbという配列は最初にヌルで初期化されています。
これは、結果を文字列として取り出すのに都合よく考えられています。
例えば、「a3c」という結果を出したいときには
outb[0]=0
outb[1]=0

outb[58]=0
outb[59]=0
outb[60]='a'
outb[61]='3'
outb[62]='c'
outb[63]=0

という配列の添字60のところのアドレス(ポインタ)を返せばいいというわけです。
※for文のところでiを1つ余分に減らしたので元に戻すため1を足していることに留意

投稿2019/08/05 08:34

satocha

総合スコア336

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

static char outb[66] = {0};

outb という名前の char 配列を用意し、その要素数を 66 と定めて outb[0] を 0 に初期化しています。ここはおそらくバグ入りで、outb[65] を 0 にしたかったんだと思います。

static がつかない場合、関数を呼び出すたびにローカル変数の領域が確保されますが、static を付けた場合には領域は実行時に確保されます。こうすると、関数から戻っても領域が破棄されないので、その領域を main で使うことができます。

i は outb 中のインデクスを表します。i = 0 の時、outb[i] は outb[0] を指します。これを 64 から~~(正確には --i なので事実上 63 から)~~カウントダウンさせることにより、outb の内容を後ろから書き換えています。

"0123456789abcdefghijkl" は文字列ですが、C 言語ではこれは char 配列です。つまり、"0123456789abcdefghijkl"[n%b] とした場合、n%b が 0 であれば "0123456789abcdefghijkl"[n%b] == '0' となり、n%b が 10 であれば "0123456789abcdefghijkl"[n%b] == 'a' となります。

戻り値は、outb 内のアドレスです。たとえば outb[6364] のみを書き換えた場合、outb[6364] のアドレスが、outb[63] と outb[6264] を書き換えた場合、outb[6263] のアドレスが戻ります。

outb は char 配列なので、文字列として扱うことができます。たとえば outb[6263] == '1', outb[6364] == '2', outb[6465] == '\0' であった場合、&outb[6263] は文字列 "12" のアドレスになります。これを printf に渡すことにより、文字列を表示しています。

投稿2019/08/05 08:32

編集2019/08/05 14:22
Zuishin

総合スコア28656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SHOMI

2019/08/05 14:03

>outb[0] を 0 に初期化しています。ここはおそらくバグ入りで、outb[65] を 0 にしたかったんだと思います。 static char outb[66] = {0};で全要素0初期化されますよ。
Zuishin

2019/08/05 14:16

そうですか? #include <stdio.h> #include <stdlib.h> int main(void) { char buf[3] = {1}; for (int i = 0; i < 3; i++) { printf("%d\n", buf[i]); } return 0; } この結果が、Visual Studio でも gcc でも 1 0 0 になりましたけど。
Zuishin

2019/08/05 14:20

失礼しました。よく調べると、残りは 0 で初期化されると書いてありました。私の勘違いです。
SHOMI

2019/08/05 14:24

値の指定を省略した要素の初期値が0になります。={0}は1要素目に0を指定しているので全要素0です。 あなたが例に上げたコードは1要素目のみ1を指定しているので1,0,0となり正しい動作ですよ。
Zuishin

2019/08/05 14:25

そう書きました。
SHOMI

2019/08/05 14:29

すみませんリロードせずに書いたため入れ違いになったようです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問