A問題(50点)
配列のアドレスの確認を行う。
1. まず、ハンドアウトLec05-3 (p103)のサンプルプログラム lec05-1int.c を自分のディレクトリにコピーしてコンパイル・実行し、ハンドアウトと似た出力が得られることを確認せよ。 (出力されるアドレスは実行例と異なるが、 一回ループするごとに出力されるアドレスの差(増分)は同じである。)
2. 上のサンプルプログラムをコピーして prog01.c というファイルを作成し、
そこに以下の配列宣言を追加しなさい。なお、宣言の中の「 ________
」には、文字または文字列の宣言を適切に補うこと。
float f_array[] = {0.1,0.2,0.3,0.4}; double d_array[] = {1e+4, 2e+3, 3e+2, 4e+1}; ______ c_array[] = {'A','B','C','D'}; ______ c_2d_array[][9] = {"ab","c","defg","hij"}; ______ str_array[] = {"ab","c","defg","hij"};
3.さらに、 array[]
の場合と同様に、
追加された配列それぞれについての各要素のアドレスを出力する記述を追加しなさい。
4. 最後に以下の記述を追加して、 sizeof()によって各型のサイズを表示するようにせよ。
printf("Size of each type\n"); printf(" int: %ld, float: %ld, double: %ld, char: %ld\n", sizeof(int), sizeof(float), sizeof(double), sizeof(char)); printf(" int*: %ld, float*: %ld, double*: %ld, char*: %ld\n", sizeof(int *), sizeof(float *), sizeof(double *), sizeof(char *));
5. このプログラムを実行し、2.で追加したそれぞれの配列について、
一回ループするごとに出力されるアドレスの増え方を答えよ。
テキストファイル prog01.txt を作成して回答を書き込みなさい。
6. アドレスの増え方が上で求めたようになる理由を、4.で追加したsizeof演算子の結果や、
Lec05-4 (p103)、Lec05-11 (p105)などを参照しながら考察して
prog01.txt 中に書き込み、提出しなさい。
double d_array[] : アドレスは xx ずつ増える。 理由は、. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . であるため。
以下は、 "Computer Science and Engineering, University of Aizu"
という内容を持つ文字列変数 str1
があるとき、キーボードから入力された二つの整数値
(start_pos
と end_pos
)を用いて、
文字列の start_pos
文字目から end_pos
文字目までを出力するプログラムである。
例えば、 start_pos
に 22 、 end_pos
に 32 が与えられたとき、22文字目から32文字目までの11文字
"Engineering" が出力されるようになっている。
このような処理を実現する方法として、以下のような3通りのやり方が考えられる。
なお、この文字列の文字数は52文字である。
また、上の説明では最初の文字を1文字目と数えていて、配列の添字と数え方が違うことに注意すること。
下記プログラムで使用されているstrlen関数は、文字列の長さ(ヌル文字含まず)を返す関数である(ハンドアウトLec04-18 (p102))。
#include <stdio.h> #include <string.h> int main() { int i, len; int start_pos, end_pos; char str1[] = "Computer Science and Engineering, University of Aizu"; char *p, *q; len = strlen(str1); printf("Input start and end positions (1 - %d): ", len); scanf("%d%d", &start_pos, &end_pos); /* 通常の配列添字を使い、配列の要素を順次参照する方法 */ for(i = ________; ________; i++) { printf("%c", str1[i]); } printf("\n"); /* 参照するアドレスをポインタ演算で計算する方法。pは固定。 */ p = ________; for(i = ________; ________; i++) { printf("%c", ________(p ________)); } printf("\n"); /* ポインタ変数に格納されているアドレスそのものを変えていく方法 */ for(________; ________; ________) { printf("%c", *q); } printf("\n"); return 0; }実行例
% ./a.out Input start and end positions (1 - 52): 22 32 Engineering Engineering Engineering % ./a.out Input start and end positions (1 - 52): 49 52 Aizu Aizu Aizu %
B問題(50点)
newstr
という文字型1次元配列とする。newstr
を作るが、
そのとき単語と単語の間にスペース一つを入れる。
ただし、終端(最後の単語の後)にはヌル文字を入れること。newstr
を丸ごと printf で出力する。
この時 printf を複数繰り返したり、printf内でスペースの挿入を行ってはならない。newstr
の文字数(スペース含む)を表示して終了(実行例参照)。#include <stdio.h> #include .......... #define NWORD 7 int main() { char str2[NWORD][20]; /* 入力用の文字配列 */ char newstr[120]; /* 出力用の文字配列 */ int i; /* ここにその他の変数宣言 */ printf( "Input %d words: \n", NWORD ); for( i = 0; i < NWORD; i++ ){ /* ここに入力された単語をstr2に読み込む処理を書く */ } /* 入力されたstr2をもとに、newstrを作成する処理を書く */ /* 単語の間にスペースを入れながら、各単語をつないだ一つの文字列にする */ printf("%s\n", newstr); /* 新しい文字列全体を表示 */ /* ここで、newstrの文字数を表示 */ return 0; }実行例
% ./a.out Input 7 words: Computer Science and Engineering, University of Aizu Computer Science and Engineering, University of Aizu Total: 52 characters %
#include <stdio.h> #define N 6 int main() { int data[N]; /* 配列の宣言 */ int tmp; int min_idx; int i, j; printf("Please input %d numbers\n", N); for(i = 0; i < N; i++) scanf("%d", &data[i]); for(i = 0; i < N - 1; i++){ min_idx = i; for(j = i + 1; j < N; j++){ if(data[j] < data[min_idx]) min_idx = j; } tmp = data[i]; data[i] = data[min_idx]; data[min_idx] = tmp; } printf("Sorted data\n"); for(i = 0; i < N; i++) { printf("%d ", data[i]); } printf("\n"); return 0; }実行例1
% ./a.out Please input 6 numbers 5 3 -2 24 1 -7 Sorted data -7 -2 1 3 5 24 %それでは、上記のプログラムの宣言部(行番号7-10) を以下のように変更し、演習問題2の3つめの方法のように、配列要素を参照するためにint型変数を使用するのではなく、 ポインタ変数を使用する方法で、同様な動作をするプログラムを作成し、また、入力された整数型データを大きい順に並び換えて表示させてください(実行例2を参照)。
int data[N]; /* 配列の宣言 */ int tmp; int *p,*q,*max_ptr;実行例2
% ./a.out Please input 6 numbers 5 3 -2 24 1 -7 Sorted data from highest to lowest 24 5 3 1 -2 -7 %
Extra問題
ネットワークに接続された一つ一つの計算機には、固有の ホスト名 と固有の
IPアドレス というものが割り当てられている。
IPアドレスは 163.143.43.50
のように、0~255の範囲の整数4つをドットで仕切って表す決まりである。
ファイル hostlist.txt に、IPアドレス・ホスト名のリストがある (IPアドレスは架空のものである)。リスト4-1にその最初の部分を示す。 このリストには、1行の中にIPアドレス(15文字以下)、半角空白1文字、 ホスト名(255文字以下)が続けて与えられ、それらが複数行ならんでいる。
このファイルをまず読み込んでおき、標準入力から検索したいホスト名(std1dc1等)
を与えると、該当するホストが存在すれば
「ホスト名 :
IPアドレス」のように表示し、
存在しない場合には、
「ホスト名 : not found!
」
(実行例参照)のように表示するプログラムを作成せよ。
検索時に入力する文字列は255文字以内とし、EOFが入力された場合はプログラムを終了させる。なお、EOFは、キーボードで Ctrl-D を押すか、リダイレクトで入力したファイルの終端に達すると、プログラムへ入力される。 (ハンドアウトLec02-10 (p89)参照)
実行例はリスト4-2である。
本課題では第2回講義で学習したリニアサーチを用いること。また、
hostlist.txt
はプログラムを実行するディレクトリに前もってダウンロードして置いておくものとする。
解答の際には、リスト4-3を読み、ホスト名のファイルを読み込むコードを理解すること。
その上で、このコードを修正してプログラムを完成させること。
文字列の比較(一致するかどうかのチェック)には strcmp
関数を使うこと。
(ハンドアウトLec04-18 (p102)参照。string.hのインクルードも必要である。)
リスト4-1 (全リスト hostlist.txt)
192.0.2.31 std1dc1 192.0.2.32 std1dc2 192.0.2.33 std1dc3 ...
リスト4-2
実行例1: % ./a.out std5dc1 std5dc1 : 203.0.113.31 std6tc60 std6tc60 : not found! Ctrl-D % 実行例2: %./a.out < testdata.txt(ファイルは こちら ) std1dc9 : 192.0.2.39 std2cd14 : not found! std3tc1 : not found! std3dc12 : 198.51.100.42 hdw3dc2 : not found! std5dc32 : 203.0.113.62 std6dc55 : not found! %
リスト4-3 (以下のソースファイル)
#include .... #include .... #include .... /* * MAXDATA:最大データ数 * LENIP :IPアドレスの最長文字数+1 * LENHOST:最長文字数+1 */ #define MAXDATA 1024 #define LENIP 16 #define LENHOST 256 int main(){ int i; int ndata; FILE *fp; char ip[MAXDATA][LENIP]; char hostname[MAXDATA][LENHOST]; char query[LENHOST]; /* その他必要な変数を定義して良い */ ..... /*** データの読み出し処理 ***/ /* ファイルのオープン */ fp = .........; if (fp == NULL) { printf("Cannot open file!\n"); exit(1); } /* データの読み出し */ for( i=0; i<MAXDATA; i++ ){ /* 2項目読めなければループを抜ける */ if (fscanf( fp, "%s %s", ip[i], hostname[i] ) != 2) break; } ndata=i; fclose(fp); /*** 問合せの処理 ***/ while(...){ ...... /* 文字列の配列の使用方法に注意 * * hostname[xxx]でxxx番目の文字列を示す */ ....strcmp( hostname[xxx], query ).... ...... } return 0; }
ポインタの働きの確認を行う。
以下のプログラムは、int型の配列変数 a, b
とポインタ ptr
を用いて、同じ値を2種類の方法で参照して printf
で表示するプログラムである。一つ目の参照方法は既に書いてあり、
二つ目の方法が空欄になっている。
プログラム中のコメントにしたがいながら、下線部の空欄を埋めて、printf
で各行に同じ値が2回表示されるようにしなさい。
例えば (1) では、 *ptr
と同じ事を配列 a
を用いて
書けばよいので、空欄には a[0]
が入る。
(2) 以降を自分で考えて空欄を埋めればよい。
もちろん、空欄に左と同じものを入れる答えは不可である。ハンドアウト Lec05-6,7,9,10 を参考にするとよい。
※余力のある者は、実行する前にどのような値が表示されるか予想してメモしておき、
実際その通りになるか確かめなさい。
ポインタの表記についてのコメント
#include <stdio.h> int main(){ int a[] = {1, 2, 4, 8, 16, 32}; int b[2][3] = {{1, 3, 9}, {-1, -3, -9}}; int *ptr; ptr = a; printf("(1) *ptr = %d \t= %d\n", *ptr, ______); /* aを用いて配列風に */ printf("(2) &a[2] = %p \t= %p\n", &a[2], ______); /* ptrでポインタ演算 */ printf("(3) *(ptr+3) = %d\t= %d\n", *(ptr+3), ______); /* aを用いて配列風に */ ptr = &a[2]; printf("(4) ptr[2] = %d \t= %d\n", ptr[2], ______); /* aを用いて配列風に */ printf("(5) *ptr-- = %d \t= %d\n", *ptr--, ______); /* aを用いて配列風に */ printf("(6) *ptr = %d \t= %d\n", *ptr, ______); /* aを用いて配列風に */ ptr = b[0]; printf("(7) *++ptr = %d \t= %d\n", *++ptr, ______); /* bを用いて配列風に */ printf("(8) *(ptr+3) = %d\t= %d\n", *(ptr+3), ______); /* bを用いて配列風に */ return 0; }実行結果の表示例を最初の1行のみ示す。 = の右に同じ値が表示されるように空欄を埋めること。
% ./a.out (1) *ptr = 1 = 1 .....