今回は前回のプログラムの機能をさらに拡張します。
市のデータ(cities.txt)を対象として、以下の各機能を持ったプログラム
1. 情報の登録と一覧表示
2. 情報の削除
3. cities.txt からの情報の読み込み
4. citiesDB.txtへのリスト内容の書き出し
5. 人口でソート
に対して、以下の点を拡張します。
- 人口、面積、人口密度、設立年月日について、それぞれ昇順および降順でソート
- 関数ポインタを使用すること
それで、自分なりにサンプルプログラムなどを使って作ってみましたが、わからない点が数点あります。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRLEN 32
#define BUF_LEN 128
#define CITYDB_R_FILE "cities.txt" // 読み込み用ファイル
#define CITYDB_W_FILE "citiesDB.txt" // 書き出し用ファイル
struct cities{
char pref[STRLEN];
char city[STRLEN];
int popl;
float area;
float dens;
char founded[STRLEN];
struct cities *next;
};
struct cities *root=NULL; // rootへのポインタは大域変数として定義
void *mymalloc(size_t sz){
void *p = (void *)malloc(sz);
if(p == NULL){
fprintf(stderr,"ERR: Can't malloc memory %d bytes.",(int)sz);
exit(1);
}
memset(p,0,sz);
return p;
}
void showCity(struct cities *c, FILE *fp){
fprintf(fp,"%s\t%s\t%d\t%.2f\t%.2f\t%s\n",
c->pref, c->city, c->popl, c->area, c->dens, c->founded);
}
struct cities *genNewCityCell(char *pref, char *city, int popl, float area, float dens, char *founded ){
struct cities *c;
c = mymalloc(sizeof(struct cities));
strcpy(c->pref,pref);
strcpy(c->city,city);
c->popl = popl;
c->area = area;
c->dens = dens;
strcpy(c->founded,founded);
return c;
}
void showList(FILE *fp){
struct cities *cur= root;
while(cur != NULL){
showCity(cur,fp);
cur = cur->next;
}
}
void saveList(){
FILE *fp;
if((fp=fopen(CITYDB_W_FILE,"w"))==NULL){
printf("cannot open!\n");
exit(1);
}
showList(fp);
fclose(fp);
printf("File saved to %s\n",CITYDB_W_FILE);
}
struct cities *line2City(char *buf){
struct cities *c=NULL;
int popl;
char pref[STRLEN], city[STRLEN], founded[STRLEN];
float area, dens;
sscanf(buf, "%s %s %d %f %f %s", pref, city, &popl, &area, &dens, founded);
c = genNewCityCell(pref,city,popl,area,dens,founded);
return c;
}
void addCity(struct cities *c){
struct cities **cur = &root;
while(*cur!=NULL){
cur = &(*cur)->next;
}
*cur = c;
c->next = NULL;
}
void inputStr(char *buf,int len){
fgets(buf,len,stdin);
buf[strlen(buf)-1]='\0';
}
void addNewCity(){
char buf[BUF_LEN] = "";
struct cities *c;
while(strlen(buf)<=0){
printf("Input one line:\n");
inputStr(buf, BUF_LEN);
}
if(strncmp(buf, "Prefecture", 10) == 0) return;
c = line2City(buf);
addCity(c);
}
void deleteCityFromList(char *delcity){
struct cities **cur = &root;
while(*cur && strcmp(delcity,(*cur)->city)){
cur = &(*cur)->next;
}
if(*cur){
struct cities *p = *cur;
*cur = p->next;
free(p);
}
}
void deleteCity(){
char buf[STRLEN];
showList(stdout);
printf("Select Delete City Name:");
inputStr(buf, STRLEN);
deleteCityFromList(buf);
}
void readListFILE(FILE *fp){
char buf[BUF_LEN];
struct cities *c;
while( fgets(buf,BUF_LEN,fp) != NULL){
if(strncmp(buf, "Prefecture", 10) == 0) continue;
c = line2City(buf);
if(c != NULL) addCity(c);
}
}
void readList(){
FILE *fp;
if((fp=fopen(CITYDB_R_FILE,"r"))==NULL){
printf("cannot open!\n");
exit(1);
}
readListFILE(fp);
fclose(fp);
printf("File loaded\n");
}
int poplAscend(struct cities *p,struct cities *q){
return p->popl - q->popl;
}
int poplDescend(struct cities *p,struct cities *q){
return q->popl - p->popl;
}
int areaAscend(struct cities *p,struct cities *q){
return p->area - q->area;
}
int areaDescend(struct cities *p,struct cities *q){
return q->area - p->area;
}
int densAscend(struct cities *p,struct cities *q){
return p->dens - q->dens;
}
int densDescend(struct cities *p,struct cities *q){
return q->dens - p->dens;
}
int foundedAscend(struct cities *p,struct cities *q){
return p->popl - q->popl;
}
int foundedDescend(struct cities *p,struct cities *q){
return q->popl - p->popl;
}
void insertCityWithComp(struct cities *sc, int(*comp)(struct cities*,struct cities*)){
struct cities **cur= &root;
while(*cur != NULL){
if(comp(*cur,sc)>0)
break;
cur = &((*cur)->next);
}
sc->next = *cur;
*cur = sc;
}
void sortCityWithComp(int(*comp)(struct cities*,struct cities*)){
struct cities *cur,*fr;
cur = root;
root = NULL;
while(cur != NULL){
insertCityWithComp(genNewCityCell(cur->pref, cur->city, cur->popl, cur->area, cur->dens, cur->founded),comp);
fr = cur;
cur = cur->next;
free(fr);
}
showList(stdout);
}
void sortList(){
char buf[BUF_LEN];
printf("sort by?(xy)\n");
printf("x=[p:population,a:area,d:dens,f:founded]\n");
printf("y=[a:ascending,d:descending]\n");
fgets(buf,BUF_LEN,stdin);
if(strncmp(buf,"pa",2)==0){
sortCityWithComp(poplAscend);
}
else if(strncmp(buf,"pd",2)==0){
sortCityWithComp(poplDescend);
}
else if(strncmp(buf,"aa",2)==0){
sortCityWithComp(areaAscend);
}
else if(strncmp(buf,"ad",2)==0){ //少しずれが生じる 例.55.30>55.50
sortCityWithComp(areaDescend);
}
else if(strncmp(buf,"da",2)==0){
sortCityWithComp(densAscend);
}
else if(strncmp(buf,"dd",2)==0){//上と同様
sortCityWithComp(densDescend);
}
else if(strncmp(buf,"fa",2)==0){//文字列なのに昇順?
sortCityWithComp(foundedAscend);
}
else if(strncmp(buf,"fd",2)==0){
sortCityWithComp(foundedDescend);
}
else{
printf("Not practice!\n");
}
}
int main(int argc, char *argv[]){
char buf[BUF_LEN];
while(1){
printf("Menu(a:add, d:delete, l:list, s:sort, w:write file, r:read file q:quit):\n");
fgets(buf,BUF_LEN,stdin);
switch(buf[0]){
case 'a':
addNewCity();
break;
case 'd':
deleteCity();
break;
case 'l':
showList(stdout);
break;
case 's':
sortList();
break;
case 'w':
saveList();
break;
case 'r':
readList();
break;
case 'q':
exit(0);
break;
}
}
}
たとえば、areaで大きい順にソートしたら
Aichi Iwakura 48042 10.49 4580.00 1971-12-01
Osaka Takaishi 60077 11.35 5293.00 1966-11-01
Tokyo Koganei 115116 11.33 10160.00 1958-10-01
Tokyo Kokubunji 118801 11.48 10349.00 1964-11-03
Tokyo Fussa 60413 10.24 5900.00 1970-07-01
Tokyo Kiyose 73518 10.19 7215.00 1970-10-01
Saitama Wako 78575 11.04 7117.00 1970-10-31
Tokyo Hamura 56984 9.91 5750.00 1991-11-01
Tokyo Musashino 138516 10.73 12909.00 1947-11-03
のような結果になります。
このずれはどうすれば治りますか?
・foundedは文字列として構造体に格納されていますが、これはどうやって比較するのでしょうか?
よろしくお願いします。