A問題(50点)
printf
を使って、ポインタの動作の確認を行う。
#include <stdio.h> int main(){ int data = 312; int *p; p = &data; printf("(1) ___\n", &data); printf("(2) ___\n", data); printf("(3) ___\n", *data); printf("(4) ___\n", &p); printf("(5) ___\n", p); printf("(6) ___\n", *p); printf("(7) ___\n", &(*p)); return 0; }
上記プログラムについて、(1)-(7) の printf
の下線部に
適切な書式を答えなさい。
また、printfの変数部分(第2引数)が実質的に何を表しているか、以下のA-Eから適切なものを選択せよ。
これらの答えは解答例のような形で、prog01.txtに記入し、提出すること。
なお、コンパイル時にエラーになるものについては
Eを選択し、その原因(理由)を記入すること。
解答例:
(1) B: %f
(2) E: 変数が宣言されていない
(3) C: %lf
:
下記のプログラムは、標準入力から入力される2つの変数 a, b の値とそれらのアドレス、
さらにそれらの値の積と商を表示するプログラムである。
ポインタ変数p, qの代入部分以外では、変数a,bを使わずに
同じ出力になるように書き換えよ。
ただし、printfの書式部分は変更しないこと。
#include <stdio.h> int main(){ double a, b; double *p, *q; /* * ここでポインタ変数p, qに適切な代入を行った後、 * それ以降は変数 a, b を使わない形に書き換える * (以下のa,bの代入文もa,bを使わないように書き換えること) */ printf("aの値を入力\n"); scanf("%lf",&a); printf("bの値を入力\n"); scanf("%lf",&b); printf("aの値: %.1f, aのアドレス: %p\n", a, &a); printf("bの値: %.1f, bのアドレス: %p\n", b, &b); printf("積: %.1f\n", a * b); printf("商: %.1f\n", a / b); return 0; }実行例: (アドレスの値が違うことがある)
% ./a.out aの値を入力 3.2 bの値を入力 6.7 aの値: 3.2, aのアドレス: 0x7ffe6a3cd938 bの値: 6.7, bのアドレス: 0x7ffe6a3cd930 積: 21.4 商: 0.5
補足: アドレスの表示は16 進数での表示であることに注意せよ。 また、状況(計算機・コンパイラ・実行環境等)によって変数のアドレスの割り当ては変化し得るので、 表示されるアドレスがいつも同じとは限らないことに注意すること。
B問題(50点)
標準入力から文字型配列 str1
に読み込まれた文字列を
別の文字型配列str2
にコピーするプログラムを作成する。
str2
にコピーする際、カギ括弧[]でその文字列を囲むと共に
母音(aiueoAIUEO)を除外する。
実行例を参考に、以下のプログラムを雛型として、完成させよ。
(ヒント)引数の文字が母音だったときに1を返し、それ以外は
0を返すような関数を作成し、利用すると良い。
#include <stdio.h> #define N 100 /* 適宜プロトタイプ宣言を追加 */ int main(){ char str1[N], str2[N]; /* 適宜変数を追加すること */ printf("Input string: "); scanf("%s", str1); /* 文字列を標準入力から入力 */ /* * 最初の開括弧 [ を代入し * 入力した文字列を1文字ずつチェックし, * 母音ではなかった場合str2に追加する。 * さらに,最後の閉括弧 ] を代入し, * str2 の末尾の処理(ヌル文字追加)を行う */ printf("str1 : %s\n", str1); printf("str2 : %s\n", str2); return 0; } /* 適宜関数を追加 */ただし、
str2
のサイズを越えるような入力は無いものとする。
'\0'
)を用いること。
str2
の終端にも忘れずにヌル文字を加えること。
% ./a.out input string: Aizuwakamatsu str1: Aizuwakamatsu str2: [zwkmts] %
世界の空港には国際空港運送協会(IATA)により3文字の空港コードが
定められている。
今、日本にある空港のコードとその名称がファイルIATA-jp.txtに
格納されているものとして、
標準入力から入力された空港コードに対して、該当する空港があれば空港名を
表示し、なければ無い旨を表示するプログラムを作成したい。
ただし、空港コードの入力は英字3文字(大文字)であり、
control+dでプログラムは終了するものとする。
なお、ファイルは途中(あるいは最後)まで
読み込むとそれ以前のデータにはアクセスできないので、
一度クローズして再度オープンするか、またはrewind()関数を
使ってデータの読み込み位置をファイルの先頭に戻す処理が
必要になる(rewind()関数を使って見たい人は自分で調べてみて下さい)。
以下はfopen(), fclose()を繰り返すタイプのプログラムである。
不足部分を補って完成させなさい。変更部分が多くなるがrewind()を
使うタイプに変更しても構わない。
また、文字列の比較には文字列用ライブラリ関数を使って良い。
/home/course/prog1/public_html/2024/ex/ex04/
より、 IATA-jp.txt
をコピーしておくこと。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char code[4], airport[30]; /* 空港コードと空港名用文字配列 */ char buf[4]; /* キーボード入力用文字配列 */ int status; /* fscanfの戻り値用 */ /* 適宜変数は追加して良い */ while(1) { printf("Input IATA code: "); if (scanf("%s",buf)==EOF) break; /* ファイルオープン */ if ((fp=fopen("IATA-jp.txt","r"))==NULL) { printf("Code file open error!!\n"); exit(2); } /* ここに、空港コードを読み込みながら、一致する ものがあるかをチェックする処理と、結果を表示する 処理を追加する */ fclose(fp); } printf("\n"); return 0; }実行例:
% ./a.out Input IATA code: HND HND is TOKYO(Haneda) Airport. Input IATA code: FKS FKS is FUKUSHIMA Airport. Input IATA code: MIE MIE is not found. Input IATA code: ITM ITM is OSAKA(Itami) Airport. Input IATA code: control+d %
Extra問題
文字列のn文字目の後ろに、標準入力から入力した単語を挿入するプログラムを作成せよ。プログラムの動作は以下のようにすること。
256要素
とする。文字列には末尾にヌル文字が付加されるため、
保持できる文字数は最大255文字である。ただし、挿入された { } も文字数としてカウントする。また以下のようなエラーがあった場合には、エラーを表示して次の入力を受け付けること。
255文字
を越える場合実行例:
% ./a.out
Current string: [Wakamatsu]
input-> 0 Aizu
Current string: {Aizu}[Wakamatsu]
input-> 17 City
Current string: {Aizu}[Wakamatsu]{City}
input-> 11 abcde
Current string: {Aizu}[Waka{abcde}matsu]{City}
input-> 23 apple
Current string: {Aizu}[Waka{abcde}matsu{apple}]{City}
input-> 150 end
Error in position
Current string: {Aizu}[Waka{abcde}matsu{apple}]{City}
input-> 0 zzz.....合計250文字の「z」.....zzz <= (注)全体の文字数が255文字を越えるようなデータ(文字列)を与える。
Error in length
Current string: {Aizu}[Waka{abcde}matsu{apple}]{City}
input-> Ctrl-D
%
テキストファイル myedit_in.txt を開き、そのファイルの編集を行って、結果を myedit_out.txt に保存するプログラムを作成する。
このプログラムはリスト6-1と、演習問題5を参考にして作成する。ファイルの編集は表に挙げたコマンドを与えることで行うが、 編集するテキストファイルの大きさは改行文字を含めて1023文字以下とする。コマンドを認識できなかったり、 実行した結果がバッファのサイズを超えてしまう場合はERROR と表示して、プログラムを終了する。 実装するコマンドを以下の表に挙げる。このプログラムの実行例はリスト6-2であり、コマンドを入力することでテキストを編集する。
コマンド | パラメータ | 意味 | 備考 |
なし | バッファの内容を表示する | ||
insert num str | num: 整数 str: 文字列 | バッファの num 文字目に、 文字列 str を挿入する。 |
num が負の数だった場合は、 バッファの後端に文字列 str を挿入する。 |
cut num1 num2 | num1: 整数 num2: 整数 | num1 文字目から num2 文字を削除する。 |
|
space num | num: 整数 | バッファの num 文字目に空白を挿入する。 | num が負の数だった場合、 バッファの後端に空白を挿入する。 |
enter num | num: 整数 | バッファの num 文字目に改行を挿入する。 | num が負の数だった場合、 バッファの後端に行を挿入する。 |
undo | なし | バッファを直前の編集前に戻す。 | 遡ることができる履歴は、 1 つ前まででよい。 |
quit | なし | 実行結果を myedit_out.txt に保存し、 プログラムを終了する。 |
まず上記のコマンドを認識するプログラムを、リスト6-1を参考にして作成する。 下記の手順に従い、プログラムの確認と拡張を行うこと。
strcmp( )
を利用することにより、文字列がコマンドと一致するか判定することができる。scanf( )
関数で読み込む。printf( )
関数で表示して確認する。printf( )
関数をプログラムから削除しておく。リスト6-1: エディタプログラムのスケルトン(skeleton_prog06.c)
#include ..... #include ..... #include ..... #define MAXLEN 1024 int main(){ int i; char c; FILE *fp; char buffer[MAXLEN]; char query[MAXLEN]; char buffer_prev[MAXLEN]; int status; int arg1, arg2; int in_len, buf_len; /* ファイルのオープン */ fp = ........; if(fp == NULL){ printf("Cannot open input file.\n"); exit(1); } /* データの読み出し(最後に'\0'を忘れないこと) */ buf_len = 0; while(1){ c = fgetc(fp); if(c == EOF){ buffer[buf_len++] = '\0'; break; } else{ buffer[buf_len++] = c; } } fclose(fp); /* コマンド入力のためのループ */ while(1){ status = scanf("%s", query); if(status != 1) break; /* 現在のテキストの長さを取得する */ buf_len = strlen(buffer); /* それぞれのコマンドのチェック */ if(strcmp("print", query) == 0){ /* printコマンド */ /* printコマンドの処理を以下に書く */ continue; } else if(strcmp("insert", query) == 0){ /* insertコマンド */ if(scanf("%d %s", &arg1, query) == 2){ /* insertコマンドの処理を以下に書く */ continue; } } /* 以下同様に,他のコマンドをプログラムを書く */ /* 該当するコマンドが見付からないとき */ printf("ERROR\n"); exit(1); } return 0; }
コマンドを識別する部分が完成したら、次にコマンドの実行部を作成する。
printf( )
関数で出力することで実現する。printf( )
関数や exit( )
関数を用いてもよい。printf( )
関数や exit( )
関数を用いてもよい。printf( )
関数や exit( )
関数を用いてもよい。strcpy( )
関数を用いて現在のバッファをundo用バッファにコピーする。strcpy( )
関数を用いて
現在のバッファにコピーする。
動作の例をリスト6-2に示す。
scanf( )
の使い方によっては、 ERROR の表示が複数出現するが、
バッファが正しく操作できて、結果を保存できていればプログラムが正しいと評価する。
リスト6-2:実行例
% cat > myedit_in.txt (改行を入力) Ctrl-D # (この処理を行うことで,一行分の空行のみを内容とするテキストファイル myedit_in.txt が作成される) % ./a.out print insert 0 #include<stdio.h> print #include<stdio.h> insert -1 main(){printf("HelloWorld\n");return space -1 insert -1 0;} enter -1 print #include<stdio.h> main(){printf("HelloWorld\n");return 0;} space 18 insert 18 int print #include<stdio.h> int main(){printf("HelloWorld\n");return 0;} enter 29 enter 53 enter 63 print #include<stdio.h> int main(){ printf("HelloWorld\n"); return 0; } cut 30 24 print #include<stdio.h> int main(){ return 0; } undo print #include<stdio.h> int main(){ printf("HelloWorld\n"); return 0; } quit % cat myedit_out.txt #include<stdio.h> int main(){ printf("HelloWorld\n"); return 0; } %./a.out c 1 1 ERROR %./a.out cut abc 1 ERROR %./a.out cut 2 1 ERROR %