演習中に配ったものよりも、while 文の終了条件がうまくできています。
/* prac0401.c */
#include <stdio.h>
int split_number_name( char *line, int *dn, char *name, int len )
{
int n, i, pos;
n = 0;
for( i = 0; i < 2; i += 1 ){
if( (line[i] < '0') || ('9' < line[i]) )
return 0;
n = n * 10 + line[i] - '0';
}
*dn = n;
if( line[i] != '_' )
return 0;
i += 1;
pos = 0;
while( line[i] != '.' ){
if( len <= pos )
return 0;
switch( line[i] ){
case '\0':
return 0;
case '_':
name[pos] = ' ';
break;
default:
name[pos] = line[i];
}
pos += 1;
i += 1;
}
name[pos] = '\0';
return 1;
}
int main()
{
int dn;
char line[100], name[100];
while( fgets(line,100,stdin) != NULL ){
if( split_number_name(line, &dn, name, 100) )
printf("%d\t%s\n", dn, name);
}
return 0;
}
|
nc_get の終了の仕方は、仕様が悪い。nc_get には返り値を持たせ、フォー マット通りの場合は 1 を返し、フォーマットと異なる場合は 0 を返し、入力 無しの場合は 2 を返すなどの工夫が必要である。
/* namecard.c */
// 第4回目のために拡張
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "namecard.h"
// ==================================================================
// アクセサ(構造体の変数を読み書きするための関数)
// ------------------------------------------------------------------
// 変数 name の操作
// 指定位置の文字の読み書き
void nc_put_name_at(NameCard *nc, char c, int pos)
{
nc->name[pos] = c;
}
char nc_get_name_at(NameCard *nc, int pos)
{
return nc->name[pos];
}
// 名前の読み書き
char *nc_get_name(NameCard *nc)
{
return nc->name;
}
void nc_put_name(NameCard *nc, char *str)
{
strncpy(nc->name, str, NAME_LEN);
}
// 名前の消去
void nc_clear_name(NameCard *nc)
{
nc_put_name_at(nc,'\0',0);
}
// ------------------------------------------------------------------
// 変数 age の操作
void nc_put_age(NameCard *nc, int n)
{
nc->age = n;
}
int nc_get_age(NameCard *nc)
{
return nc->age;
}
// ------------------------------------------------------------------
// ドライバーナンバーの操作
void nc_put_driver_number(NameCard *nc, int dn)
{
nc->number = dn;
}
int nc_get_driver_number(NameCard *nc)
{
return nc->number;
}
// ==================================================================
// 構造体の確保と解放
NameCard *nc_open()
{
NameCard *ans;
ans = (NameCard *)malloc(sizeof(NameCard));
if( ans == NULL ){
fprintf(stderr,"nc_open: malloc failed\n");
exit(1);
}
nc_put_age(ans, 0);
nc_put_driver_number(ans, 0);
nc_clear_name(ans);
return ans;
}
void nc_close(NameCard *nc)
{
free(nc);
}
// ==================================================================
// フォーマット通りの読み書き
// 末尾の改行コードをカットする
// ※ ここのファイル namecard.c の中だけで使う関数なので
// static としている。
static void cut_return_code( char * line )
{
int l;
l = strlen( line );
if( line[l-1] == '\n')
line[l-1] = '\0';
}
// 1行のデータを分割
// ※ ここのファイル namecard.c の中だけで使う関数なので
// static としている。
static int split_number_name_age(char *line, int *dn, char *name, int len, int *age)
{
int n, i, pos;
i = 0; // i は、入力文字列 line の参照位置
// 数字を表す文字列を参照し、整数 int に変換
n = 0;
while( line[i] != '\t' ) { // タブが正しい境界文字
if( (line[i] < '0') || ('9' < line[i]) )
return 0;
n = n * 10 + line[i] - '0';
i += 1;
}
*dn = n;
i += 1; // タブを読み飛ばす
// 名前を表す文字列を参照
// 「(年齢)」が現れるまで、または「\0」までを参照
pos = 0;
while( line[i] != '(' ){
if( len <= pos )
return 0;
if( (line[i] == '\0') ){ // 「\0」のとき終了
name[pos] = '\0';
*age = 0;
return 1;
}
name[pos] = line[i];
pos += 1;
i += 1;
}
name[pos] = '\0';
i += 1;
// 「年齢)」のうち年齢を抽出
n = 0;
while( line[i] != ')' ) {
if( (line[i] < '0') || ('9' < line[i]) )
return 0; // 「閉じ括弧で終了しなければスキャン失敗」
n = n * 10 + line[i] - '0';
i += 1;
}
*age = n;
return 1;
}
// 1行データをファイルから入力する
void nc_get(NameCard *dst, FILE *fin)
{
int dn, age;
char line[NAME_LEN + 32];
char name[NAME_LEN];
if( fgets(line, NAME_LEN + 32, fin) == NULL )
exit(0); // 正常終了、仕様がよくない。。。
cut_return_code( line ); // 改行コードをカットする。
if( split_number_name_age(line, &dn, name, NAME_LEN, &age) ){
nc_put_driver_number(dst, dn);
nc_put_name(dst, name);
nc_put_age(dst, age);
} else
exit(1); // 異常終了、仕様が良くない。。。
}
// 1行データをファイルに出力する
void nc_put(NameCard *src, FILE *fout)
{
fprintf(fout,"%d\t%s(%d)\n",
nc_get_driver_number(src),
nc_get_name(src),
nc_get_age(src));
}
|