見出し画像

(答案提出) C言語教室 第14回 - 変数型のサイズ

最近、諸事情でバタバタしていましたので、答案提出する余裕がありませんでしたが、前回の「C言語教室 第13回 - 文字コードと符号の取り扱い 」では課題がお休みでしたので助かりました。

気合を入れ直して、「第14回」の課題に取り組んでいきたいと思います。

課題

long 型配列に格納されているランダムな数値を short 型配列にコピーしなさい。short に格納できない値が含まれているときには、short で表現できる最大値または最小値にすること。

https://note.com/kazushinakamura/n/n168cc8ff6e31

答案作成上のポイント整理

  • long型とshort型の配列を作成するとき、符号の扱いをどうする?
    →「short で表現できる最大値または最小値にすること」とわざわざ記載してあるので、符号付きが意図されているものと推定。(そうでなければ、最小値は常にzeroとなってしまう)

  • ランダムな数値を、long型整数で格納可能な範囲で生成する
    →上記で作成したランダムなlong型整数の配列には、short型整数で格納できない値を含む必要がある

  • 「short で表現できる最大値または最小値」をどこから入手する?
    実装環境によってこれらの数値が変わる可能性があるという趣旨だと思われるので、実行時にこれらの値を入手する必要がある

  • 取り敢えず、私の実装環境について調査する

gccで、実装環境について調査

#include <stdio.h>
#include <limits.h>

int main(int argc, char *argv[]) {
  printf("size of short integer=%lu\n", sizeof(short));
  printf("minimum number of short integer=%d\n", SHRT_MIN);
  printf("maximum number of short integer=%d\n", SHRT_MAX);
 
  printf("size of long integer =%lu\n", sizeof(long));
  printf("minimum number of long integer=%ld\n", LONG_MIN);
  printf("maximum number of long integer=%ld\n", LONG_MAX);
}
jm3nrhMBP-EN:c akio$ gcc test13.c
jm3nrhMBP-EN:c akio$ ./a.out
size of short integer=2
minimum number of short integer=-32768
maximum number of short integer=32767
size of long integer =8
minimum number of long integer=-9223372036854775808
maximum number of long integer=9223372036854775807
jm3nrhMBP-EN:c akio$ 

ブラウザ環境で、実装環境について調査

ブラウザ環境ではlimits.hがincludeできないので、gccで上記コードを動かしてみて、その結果を見ながら試行錯誤で下記のブラウザ版コードを準備。

#include <stdio.h>
#define SHRT_MIN -32768
#define LONG_MIN -2147483648

void main() {
  printf("size of short integer=%lu\n", sizeof(short));
  printf("minimum number of short integer=%d\n", SHRT_MIN);
  printf("maximum number of short integer=%d\n", SHRT_MAX);
 
  printf("size of long integer =%lu\n", sizeof(long));
  printf("minimum number of long integer=%ld\n", LONG_MIN);
  printf("maximum number of long integer=%ld\n", LONG_MAX);
}
size of short integer=2
minimum number of short integer=-32768
maximum number of short integer=32767
size of long integer =4
minimum number of long integer=-2147483648
maximum number of long integer=2147483647

実装環境によって、いろいろと差異がありますね。

答案 - 課題

乱数の範囲を、-80,000〜80,000にしてみました。

大小比較について、私が期待した通りに動かすのにひと苦労。
最小値についてはすんなり処理できるのに、最大値については絶対値が65536となるあたりで、実行結果が怪しくなるのに苦慮しました。

前回の講習(第13回)を読み返して、ヒントを探ります。

#include  <stdio.h>
#include  <stdlib.h>
//#include <limits.h>
#define SHRT_MIN -32768
#define SAMPLE 10
#define MIN_VALUE (-80000L)
#define MAX_VALUE (80000L)

void long_clear_tbl(long* x, int y) {
  for (int i = 0; i < y; i++) {
     *x++ = 0L;
  }
}
void short_clear_tbl(short* x, int y) {
  for (int i = 0; i < y; i++) {
     *x++ = 0;
  }
}

void long_set_tbl(long *x, int y) {
  for (int i = 0; i < y; i++) {
    *x++ = (long) rand() % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE;;
  }
}

void copy_tbl(long *x, short *y, int z) {
  for (int i = 0; i < z; i++) {
    if (*x < 0){
      *y = *x < SHRT_MIN ? SHRT_MIN : (short) *x;
    } else {
      *y = *x > SHRT_MAX ? SHRT_MAX : (short) *x;
    }

    *x++; *y++;
  }
}

void print_tbl(long *x, short *y, int z) {
  for (int i = 0; i < z; i++) {
    printf("(%d) %-ld / %-d\n", i, *x++, *y++);
  }
}

void main() { 
  int s = SAMPLE;
  long *long_tbl;
  short *shrt_tbl;
  
  long_tbl = (long*)malloc(sizeof(long) * s); //long整数配列を作成します
  if (long_tbl == NULL) exit(-1);

  shrt_tbl = (short*)malloc(sizeof(short) * s); //short整数配列を作成します
  if (shrt_tbl == NULL) exit(-1);

  long_clear_tbl(long_tbl, s); //long整数配列の要素を全てゼロにします

  short_clear_tbl(shrt_tbl, s); //long整数配列の要素を全てゼロにします

  long_set_tbl(long_tbl, s); //long整数配列に乱数を割り付けます
  
  copy_tbl(long_tbl, shrt_tbl, s); //short整数配列にlong整数配列をコピーします
  
  print_tbl(long_tbl, shrt_tbl, s); //整数配列の内容を表示します

  free(long_tbl);
  free(shrt_tbl);
  
}


実行結果 - 課題

私の実装環境では、short型整数の範囲を下回る場合は-32768、上回る場合は32767が表示されます。

(0) -80000 / -32768
(1) -1664 / -1664
(2) 20593 / 20593
(3) -40725 / -32768
(4) 67155 / 32767
(5) 12311 / 12311
(6) 16025 / 16025
(7) 8598 / 8598
(8) 39426 / 32767
(9) -18541 / -18541


演習

short、unsigned short、long、unsigned long 型の数値を printf で出力する時に使う書式指定子を調べなさい。

https://note.com/kazushinakamura/n/n168cc8ff6e31?magazine_key=m07bb4da8df3e

答案 - 演習

shortの数値を printf で出力する時に使う書式指定子、、、d
unsigned shortの数値を printf で出力する時に使う書式指定子、、、u
longの数値を printf で出力する時に使う書式指定子、、、ld
unsigned long 型の数値を printf で出力する時に使う書式指定子、、、lu

#include  <stdio.h>

void main() { 
  short val_short = -12345;
  unsigned short val_unsigned_short = 65123;
  long val_long = -70123;
  unsigned long val_unsigned_long = 3000000000;

  printf("short %d\n", val_short);
  printf("unsigned short %u\n", val_unsigned_short);
  printf("long %ld\n", val_long);
  printf("unsigned long %lu\n", val_unsigned_long); 
}

実行結果 - 演習

short -12345
unsigned short 65123
long -70123
unsigned long 3000000000

いかがでしょうか?

後記

今回の課題の趣旨ではありませんが、数値を3桁ごとにカンマ編集する方法が分からず終いでした。
どうもsetlocaleを使うらしく、locale.hをincludeしないといけないみたいなのですが、ブラウザ環境では読み込めません。
gccでもやってみたのですが、setlocaleの指定方法がよくないのか、うまくいきません。
ネットでは、自分で関数を作ってカンマ編集している方も居られるようで、いろんな実装環境で機能を実現しようとするならこの方が手っ取り早かったりして。

追記(2023.02.22)

long integerをカンマ編集する関数を作ってみました。

#include <stdio.h>
#include <string.h>
#define SHRT_MIN -32768
#define LONG_MIN -2147483648

char * char_edit_comma(long x) {
  char tmp[11]; // 文字列化した入力数値
  char rst[14]; // 編集した文字列
  int  ptr_tmp = 0; // tmp[]のポインタ
  int  ptr_rst = 0; // rst[]のポインタ
  int  len; // 入力した数値の桁数
  int  dgt; // 一度に処理する桁数

  sprintf(tmp, "%d", x);

  len = strlen(tmp);
  dgt = len % 3;
  if (dgt == 0) dgt = 3; // 3で割り切れる桁数の場合は、一度に3桁処理する
  if ((dgt == 1) && (x < 0)) dgt = 4; // マイナス符号の直後は、カンマ編集しない

  while (len > 0) {
    for (int i = 0; i < dgt; i++) {
        rst[ptr_rst++] = tmp[ptr_tmp++];
        len--;
    }

    if (len > 0) {
      rst[ptr_rst++] = ','; // 残りの桁が3桁以上あるので、カンマを追加する
      dgt = 3; // 次回以降は3桁ごとに、処理する
    }
  }

  rst[ptr_rst++] = NULL; // 文字配列の最後にNULLを追加する
  return rst;
}

void main() {
  short s_min = SHRT_MIN;
  short s_max = SHRT_MAX;
  long l_min = LONG_MIN;
  long l_max = LONG_MAX;

  printf("size of short integer=%lu\n", sizeof(short));
  printf("minimum number of short integer=%s\n", char_edit_comma( (int) s_min));
  printf("maximum number of short integer=%s\n", char_edit_comma( (int) s_max));
 
  printf("size of long integer  = %lu\n", sizeof(long));
  printf("minimum number of long integer=%s\n", char_edit_comma(l_min));
  printf("maximum number of long integer=%s\n", char_edit_comma(l_max));

}

この関数は、long integerの範囲を超えると動作が保証されません。
また、小数点以下の実数の場合は処理対象外です。

size of short integer=2
minimum number of short integer=-32,768
maximum number of short integer=32,767
size of long integer =4
minimum number of long integer=-2,147,483,648
maximum number of long integer=2,147,483,647

ここまで読んでいただき、有難うございました。

これまでの収益は全て、それを必要としておられる方々へ、支援機関を通して寄付させていただきました。この活動は今後も継続したいと思っています。引き続きよろしくお願いいたします。