専門学校96日目/10月18日(金)

1時限~3時限
C言語基礎 やさしいC 第5版

前回の授業の最後に関数をヘッダファイル内で宣言し、main関数のあるファイルとは別のファイルに関数を記述して、それを呼び出すという練習問題5の課題をやりました。

3つのファイルを作ると書いてあったが、どこに作るかということは書かれていない。
Visual Studioの環境では、ユーザー\ユーザ名の直下にあるsource\repos\functionの直下に分割して作ったファイルを置く。
ここで私はfunctionというプロジェクト名にしたのでそのようになっています。分割したファイルはメモ帳などで作って適切な位置に配置してもよい。その場合、ファイル名はpower.cやpower.hなどとする。

Visual Studioのソリューションエクスプローラーのソースファイルで右クリックして「追加→既存の項目」を選択し、置いたファイルを選択すると分割して作ったファイルを開くことができ、同様にヘッダファイルも同じように開くことができる。こうして自分で定義した関数を使いまわせる。

中間テストは11月の22日の週になる。3時限でなく2時限くらいでテストする形になります。

今日からは教科書9章のポインタを学びます。
C言語にはメモリの位置をあらわすポインタという機能がある。アドレスはメモリ上の住所のことで16進数などであらわすことが多い。
変数の値が格納されているメモリのアドレスはアドレス演算子の&を使って知ることができる。
教科書の例はアドレスを表す16進数は桁数も少ないが、実際は10数桁の16進数で表示された。

ポインタの仕組み
アドレスを格納する特殊な変数をポインタという。ポインタの使い方は原則としてこれまでの変数と同じ。ポインタを表す変数には必ず*を付けて宣言する。
int *pA
というように記述する。*はポインタの宣言であることをあらわす記号。

ポインタから逆にたどって元の変数の値を知ることができる。*という演算子を使う。間接参照演算子という。ポインタを使って利用価値が高まるというのは後ほど説明します。ポインタには何らかの変数のアドレスを代入する必要がある。

1.ポインタ変数の宣言はを付けてpAなどとする。
2.ポインタ変数は宣言時以外はpAというようには付けない。
3.アドレスの格納されたポインタ変数にを付けると、ポインタのさしている変数の値がわかる。

aは変数a
&aは変数aのアドレス
pAは変数aのアドレスを格納したポインタ
*pAは変数aを格納するポインタがさしている変数

キーボード入力でポインタに入力値を渡すときは&がいらない。これは通常の変数だと変数のさしているメモリ領域に格納するために&でアドレスを渡す必要があった。ポインタ変数はすでにアドレスを保持しているので&はいらない。ポインタがさすメモリに直接値を格納できるため。

これまでに何度もやった三角形の面積を求める問題をポインタを使って計算するプログラムを作りました。

#include <stdio.h>

int main(void) {
/**
int a;
a = 5;

printf("変数aの値は%dです。\n", a);
printf("変数aのアドレスは%pです。\n", &a);
//*/
//通常の変数の代わりにポインタを使って面積を計算
/**/
int iteihen;
int itakasa;
int *teihen = &iteihen; //ポインタの初期化
int *takasa = &itakasa;	

printf("三角形の面積を求めます。\n");
printf("底辺の長さを入力してください。\n");
scanf_s("%d", teihen);
printf("高さを入力してください。\n");
scanf_s("%d", takasa);

printf("三角形の面積は%.2fです。\n", *teihen * *takasa / 2.0);
//*/
return 0;
}

ポインタ変数に入力して最後に間接参照演算子を使い、計算している。

教科書にあるコードをそのまま写してポインタを使用して関数で実引数の入れ替えができるか実行してみました。
ポイントは関数内で定義する仮引数をポインタとして定義しておくこと。関数内でもポインタとして変数を扱うことで、関数に値渡しした元の実引数の操作ができる。値渡しは実引数の値を仮引数にコピーして関数内で使用しているだけで、関節参照演算子を使って関数内での変更を実引数の変更にしてやる必要がある。

#include <stdio.h>

/* swap関数の宣言 */void swap(int *pX, int *pY);

int main(void) {//ポインタを使って関数で値のスワップを実現するint num1 = 5;int num2 = 10;
printf("変数num1の値は%dです。\n", num1);
printf("変数num2の値は%dです。\n", num2);
printf("変数num1とnum2の値を交換します。\n");

swap(&num1, &num2);

printf("変数num1の値は%dです。\n", num1);
printf("変数num2の値は%dです。\n", num2);

return 0;
}

/* swapの定義 */void swap(int *pX, int *pY) {
int tmp;
tmp = *pX;
*pX = *pY;
*pY = tmp;
}


課題として3つの数値を入力して小さい順に変数a,b,cを並べ替える関数を作りました。

#include <stdio.h>

/* sort関数の宣言 /
void sort3(int pA, int* pB, int* pC);

int main(void) {
int a, b, c;
//a,b,cの値の入力
printf("aの値を入力してください。\n");
scanf_s("%d", &a);
printf("bの値を入力してください。\n");
scanf_s("%d", &b);
printf("cの値を入力してください。\n");
scanf_s("%d", &c);
sort3(&a, &b, &c); //&を使いアドレスを渡して関数を呼び出す

printf("小さい順に並べると%d、%d、%dです。\n", a, b, c);

return 0;
}

/* sort3関数の定義 /
void sort3(int pA, int* pB, int* pC)
{
int tmp; //a,b,cを入れ替えるための一時的な変数

if (*pA > *pB) { // aとbの比較、a<=bならそのまま
	tmp = *pB;
	*pB = *pA;
	*pA = tmp;
}
if (*pA > *pC) { //aとcの比較、a<=cならそのまま
	tmp = *pA;
	*pA = *pC;
	*pC = tmp;
}
if (*pB > *pC) { //bとcの比較、b<=cならそのまま
	tmp = *pB;
	*pB = *pC;
	*pC = tmp;
}

}

練習問題を解いておく宿題が課されました。次週は解説から始めます。

練習問題
1-①変数のアドレスを表示させる変換仕様%pとアドレス演算子&を使っているので、そのコンピュータ上のアドレスが表示される。よってコンピュータが違えば結果も違ってくる。だから×

1-②ポインタには別なアドレスを代入できる。よって答えは〇

1-③int*型のポインタはあくまでもメモリアドレスを保持するもので、変数にアドレス演算子&をつけてあらわしたアドレスだけ格納できる。よって×

問題2
①はポインタpA。宣言時はが必要だが、それ以外ではは必要ない。
②は%p。アドレスを表示させる変換仕様は%pとするから。
③はpA。直前に②の%pがあるので、アドレスを表示させるものです。pA=&aでアドレスを代入したので、pAが正解。

問題3

#include <stdio.h>

/* 点数を加算する関数の宣言 /
add2(int numX, int* numY, int z);

void int main(void) {
//宿題の練習問題3
/**/
int num1, num2, add;
printf("2科目の点数を入力してください。\n");
scanf_s("%d", &num1);
scanf_s("%d", &num2);
printf("加算する点数を入力してください。\n");
scanf_s("%d", &add);

add2(&num1, &num2, add);

printf("%d点加算したので\n", add);
printf("科目1は%d点となりました。\n", num1);
printf("科目2は%d点となりました。\n", num2);
//*/
return 0;
}

/* add2関数の定義 /
void add2(int numX, int* numY, int z)
{
*numX += z;
*numY += z;
}



4時限~6時限
webDBシステム開発 スッキリわかるSQL入門第3版ドリル256問付き

今日も教科書から学びます。前回飛ばしたp.151-
関数の中で別な関数を使う入れ子構造のSQL文。lengthは文字数を返す。trimは空白を取り除く。
この2つを入れ子にしてlength(trin('SQL '))とすればまず中のtrimから処理し、その後、lengthが処理される。

p.157-
ROUND関数、実務でよく使う。Excelでも同じ関数があります。

select 出金額, round(出金額, -2) as 百円単位の出金額
from 家計簿
 
select 出金額, round(出金額, -3) as 千円単位の出金額
from 家計簿

この2つは百円単位と千円単位の表示になる。関数をselect文に入れることができる。

select 出金額, trunc(出金額, -2) as 百円単位の出金額
from 家計簿

select 出金額, trunc(出金額, -3) as 千円単位の出金額
from 家計簿

truncは指定した桁で切り捨てのSQL文。

power関数はあまり使わないが、面白い使い方ができる。後日紹介する。

日付に関する関数はよく使います。項目の最後に更新日付と更新者、更新IDなどを入れることで、だれがいつ操作したのかわかるようにできる。current_timestampなどに()は付けない。

insert into 家計簿
values (current_date, '食費', 'ドーナツを買った', 0, 260)

日付は2024-10-18といった表示形式で出力されます。

p.160
cast関数
出金額 + '円'としたいとき、データ型は不一致。型の異なる値は||演算子で連結することはできない。そこでcast関数で
cast(出金額 as varchar(20)) + '円'のように文字型に変換して連結することができる。数値でない文字を数値型には変換できない。

coalesce関数

select coalesce('A', 'B', 'C');
select coalesce(null, 'B', 'C');
select coalesce(null, 'B', null);
select coalesce(null, null, 'C');

select coalesce(出金額, 0)
from 家計簿

この関数はnullがあるときに使うと便利である。nullがどの箇所にあるかも見つけやすくなる。

第5章のまとめ

select 日付, 費目, メモ, 入金額, 出金額,入金額 - 出金額 as 入出金額差
from 家計簿

select 日付, 費目,
    case when length(メモ) >= 8 then substring(メモ,1,8) || '…'
    else メモ
    end as メモ, 入金額, 出金額
from 家計簿

select 日付, trunc(入金額/140.0, 0) as 入金ドル, 
trunc(出金額/140.0, 0) as 出金ドル
from 家計簿

select *
from 家計簿
where 日付 > current_date

select 日付, coalesce(メモ, 費目, '不明') as 備考
from 家計簿

以上がまとめのSQL文です。select内で入金額 - 出金額 as 入出金額差のように計算できます。
case when length(メモ) >= 8 then substring(メモ,1,8) || '…'
else メモ
end as メモ, 入金額, 出金額ではメモが8文字以上なら最後に…をつけて表示させます。||で連結しています。
truncでは0桁目で切り捨てて、ドルに直した金額を表示します。

current_dateでの比較は未来の日付で登録した行を探しています。
最後のは引数のメモ、費目のうち、nullでない最初の文字列を返します。どちらもnullなら不明と表示する。

2時限目からは課題に取り組みました。

create table 車種マスタ (
    ID integer,
    車種 varchar(10),
    メーカー varchar(6),
    価格(最低グレード) integer,
    価格(最高グレード) integer
    )

insert into 車種マスタ
values (1, 'カルディラ', 'トコタ', 1698000, 2908000)

insert into 車種マスタ
values (2, 'レナシー', 'スベル', 1740000, 3013000)

insert into 車種マスタ
values (3, 'アワード・ワゴン', 'ホソダ', 2148000, 2548000)

insert into 車種マスタ
values (4, 'アバニール', '目産', 1657000, 2623000)

insert into 車種マスタ
values (5, 'レグメム', '二菱', 1923000, 3144000)

insert into 車種マスタ
values (6, 'マークワゴン', 'トコタ', 2400000, 3370000)

insert into 車種マスタ
values (7, 'ブリメーラ', '目産', 1767000, 2448000)

insert into 車種マスタ
values (8, 'インプルッサ', 'スベル', 1298000, 2899000)

insert into 車種マスタ
values (9, 'カベラ・ワゴン', 'マシダ', 1705000, 2525000)

insert into 車種マスタ
values (10, 'カルーラ・ワゴン', 'トコタ', 1423000, 1998000)

insert into 車種マスタ
values (11, 'B5アバント', 'アウブー', 5090000, 5990000)

insert into 車種マスタ
values (12, 'カルブ', 'トコタ', 1327000, 2089000)

insert into 車種マスタ
values (13, 'オルティナ', 'ホソダ', 1668000, 2183000)

insert into 車種マスタ
values (14, 'U7O', 'ブルボ', 4100000, 5800000)

insert into 車種マスタ
values (15, 'テニオ', 'マシダ', 964000, 1554000)

insert into 車種マスタ
values (16, 'リベロ', '二菱', 1437000, 2424000)

insert into 車種マスタ
values (17, '5OO', 'BWM', 5990000, 6450000)

insert into 車種マスタ
values (18, 'カルクス', 'ススキ', 1230000, 1823000)

insert into 車種マスタ
values (19, 'ステージラ', '目産', 2320000, 3464000)

insert into 車種マスタ
values (20, 'Zクラス・ワゴン', 'ベンス', 5900000, 8000000)

続いてテーブルの操作です。

select 車種, メーカー, 価格(最低グレード) as 若い世代へのサービス価格,
case when 価格(最低グレード)< 1000000 then '絶対おススメ!'
     when 価格(最低グレード)< 1500000 then '家計に優しい'
     else 'おしゃれな夫婦に'
     end as 人気の秘密
from 車種マスタ
where 価格(最低グレード)< 2000000

select 車種, メーカー, 価格(最高グレード) - 200000 as ハイグレード車種が今だけこの価格!
from 車種マスタ
where 価格(最高グレード)>= 3000000

update 車種マスタ
set 価格(最低グレード) = 価格(最低グレード) + 200000,
set 価格(最高グレード) = 価格(最高グレード) + 300000

select メーカー, 車種, trunc(価格(最低グレード), -5) as FROM(価格),
 trunc(価格(最高グレード), -5) as TO(価格)
from 車種マスタ


この記事が気に入ったらサポートをしてみませんか?