CSVファイルを読み込んで構造体に格納し、格納したデータを標準出力、女性のデータだけを標準出力、その後データのナンバーを昇順にソートし標準出力しようとしていますが、下2つが上手く出力できません・・・
どなたか、間違いを指摘してもらえませんか?

CSVファイルの内容
*****************************************************************
022023,金沢聖悟,M,012-345-6789
022011,鈴木信也,M,123-456-7890
022025,佐々木小太郎,M,901-234-5678
032002,加田宮千代子,F,890-123-4567
032011,ラスコーニ・イワンチャコフ,M,789-012-3456
032020,渡辺真,M,678-901-2345
032050,加藤江美,F,567-890-1234
042007,萩原雄一,M,456-789-0123
042010,井上麻衣,F,345-678-9012
042014,カイ・ハンセン,M,234-567-8901
042035,近松門左衛門,M,111-222-3333
042044,セルビア・モンテネグロ,F,555-555-5555
**************************************************************

プログラム
***************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NUMBER_LENGTH 30
#define MAX_NAME_LENGTH 20
#define MAX_SEX_LENGTH 2
#define MAX_TEL_LENGTH 20
#define MBF 256

struct NameCard{
char number[MAX_NUMBER_LENGTH]; // 番号
char name[MAX_NAME_LENGTH]; // 名前
char sex[MAX_SEX_LENGTH]; // 性別
char tel[MAX_TEL_LENGTH]; // 電話番号

};


void swap(struct NameCard * ,struct NameCard *);
void sort(struct NameCard [], int );



int main(void)
{
FILE* fp; /* ファイルポインタ用 */
char *ret; /* ファイル名用 */
char *c,ch[MBF]; /* 文字入力用 */
int i = 0;
int n,k;



struct NameCard ncd[20];





if((fp = fopen("meibo.csv", "r")) == NULL)
printf("ファイルをオープンできません\n");
//exit(1);/* 強制終了 */

else{
printf("読み込んだファイルを表示します\n");
while ( fgets(ch,MBF,fp) != NULL){
//printf("test\n");
strcpy(ncd[i].number,strtok(ch,","));
strcpy(ncd[i].name,strtok(NULL,","));
strcpy(ncd[i].sex,strtok(NULL,","));
strcpy(ncd[i].tel,strtok(NULL,","));

atoi(ncd[i].number);

printf("%s,%s,%s,%s",ncd[i].number,ncd[i].name,ncd[i].sex,ncd[i].tel);
i++;




}
//printf("%s\n",ncd[0].sex);
//printf("%s\n",ncd[1].sex);
//printf("%s\n",ncd[2].sex);
//printf("%s\n",ncd[3].sex);

printf("女性のリスト\n");
for(n=0;n<i;n++)
{
//printf("test\n");
if(ncd[n].sex==c){
//printf("test\n");
printf("%s,%s,%s,%s",ncd[n].number,ncd[n].name,ncd[n].sex,ncd[n].tel);
}else;


}

}





sort(ncd, i);


printf("ソート後\n");
for(k=0;k < i;k++)
{
printf("%s,%s,%s,%s",ncd[k].number,ncd[k].name,ncd[k].sex,ncd[k].tel);
}



fclose(fp); /* ファイルクローズ */






return(0);
}



void swap(struct NameCard *x,struct NameCard *y)
{
struct NameCard temp = *x;
*x = *y;
*y = temp;
}

void sort(struct NameCard data[], int n)
{
int k = n - 1;
while(k >= 0){
int i,j;
for(i = 1,j = -1; i <= k; i++)
if(data[i-1].number > data[i].number){
j = i - 1;
swap(&data[i],&data[j]);
}
k = j;
}

}

A 回答 (2件)

変数cは、宣言だけされていて初期化されていないんじゃないですか?


また、

>if(ncd[n].sex==c){
>if(data[i-1].number > data[i].number){

これらの式は、ポインタの値を比較していて、文字列を比較しているのではありません。

動作に影響はありませんが、

>atoi(ncd[i].number);

整数に変換した結果がそのまま捨てられていますね。
    • good
    • 0

起動はコマンドプロンプトから



./a.out meibo.csv

のように、CSVファイル名を引数として指定してください。
また、CSVファイルの読み取りは

while(fscanf(fp, "%[^,],%[^,],%[^,],%s",ncd[i].number,ncd[i].name,ncd[i].sex,ncd[i].tel) != EOF) {
http://simd.jugem.jp/?eid=49

を使いたかったのですが、当方の Gccコンパイラと相性が良くありませんのでしたので、質問の回答に合わせてあります。



/* An answer by Gcc on Mac OSX
* file name: matsuo.c
* compile: gcc matso.c
* execution: ./a.out <CSVファイル>
*/

#include <stdio.h>
#include <stdlib.h>//exit()
#include <string.h>
#define MAX_NUMBER_LENGTH 30
#define MAX_NAME_LENGTH 20
#define MAX_SEX_LENGTH 2
#define MAX_TEL_LENGTH 20
#define MBF 256
#define SIZE 20

struct NameCard{
char number[MAX_NUMBER_LENGTH]; // 番号
char name[MAX_NAME_LENGTH]; // 名前
char sex[MAX_SEX_LENGTH]; // 性別
char tel[MAX_TEL_LENGTH]; // 電話番号
};

/* プロトタイプ宣言 */
int number_comp(const void *, const void *);

int main(int argc, char *argv[]) {
FILE* fp; // ファイルポインタ用
char ch[MBF]; // 文字入力用
int n, i = 0;
struct NameCard ncd[SIZE];

if(argc != 2 || (fp = fopen(argv[--argc], "r")) == NULL) {
printf("ファイルをオープンできません?n");
exit(1);/* 強制終了 */
}
while(fgets(ch,MBF,fp) != NULL) {
strcpy(ncd[i].number,strtok(ch,","));
strcpy(ncd[i].name,strtok(NULL,","));
strcpy(ncd[i].sex,strtok(NULL,","));
strcpy(ncd[i].tel,strtok(NULL,","));
i++;
}
fclose(fp); /* ファイルクローズ */
printf("読み込んだファイルを表示します?n");
for (n = 0; n < i; n++)
printf("%s,%s,%s,%s",ncd[n].number,ncd[n].name,ncd[n].sex,ncd[n].tel);

printf("女性のリスト?n");
for(n=0;n<i;n++) {
if(*ncd[n].sex=='F') {
printf("%s,%s,%s,%s",ncd[n].number,ncd[n].name,ncd[n].sex,ncd[n].tel);
}
}

/* ソーティング */
qsort(ncd, i, sizeof(struct NameCard), number_comp);
printf("ソート後?n");
for(n=0;n < i;n++) {
printf("%s,%s,%s,%s",ncd[n].number,ncd[n].name,ncd[n].sex,ncd[n].tel);
}

return(0);
}


/* NumberCard.number[] の比較 */
int number_comp(const void *_p0, const void *_p1) {
struct NameCard *p0 = (struct NameCard *)_p0;
struct NameCard *p1 = (struct NameCard *)_p1;

return strcmp(p0->number, p1->number);
}
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

Qstruct tanka_kosuu kosuu[10];の[10]て何

#include <stdio.h>
struct tanka_kosuu {
int tanka;
int kosuu;
int kingaku;
};
int main()
{
         struct tanka_kosuu kosuu[10];
       構造体宣言 構造体名  変数名
struct tanka_kosuu kari_nyuuryoku = {-1, 0, 0};
int nyuuryoku_kosuu = 0;
while(kari_nyuuryoku.tanka != 0){
scanf("%d %d", &kari_nyuuryoku.tanka,
&kari_nyuuryoku.kosuu);
kosuu[nyuuryoku_kosuu] = kari_nyuuryoku;
nyuuryoku_kosuu++;
}
return 0;
}
以上ですが、
 struct tanka_kosuu {
int tanka;
int kosuu;
int kingaku;
以上と
struct tanka_kosuu kosuu[10];は
 以下
int tanka;
int kosuu[10];
int kingaku;
 と同じ意味ですか?
 それとも
  int tanka[10];
int kosuu[10];
int kingaku[10]; 
 と同じ意味ですか?
int tanka[10];と
 int kingaku[10];の
 合計に[10]は必要ないですよね
以上すべて私の考え方が間違っていたならごめんなさい。
 以上よろしくお願いいたします。

#include <stdio.h>
struct tanka_kosuu {
int tanka;
int kosuu;
int kingaku;
};
int main()
{
         struct tanka_kosuu kosuu[10];
       構造体宣言 構造体名  変数名
struct tanka_kosuu kari_nyuuryoku = {-1, 0, 0};
int nyuuryoku_kosuu = 0;
while(kari_nyuuryoku.tanka != 0){
scanf("%d %d", &kari_nyuuryoku.tanka,
&kari_nyuuryoku.kosuu);
kosuu[nyuuryoku_kosuu] = kari_nyuuryoku;
nyuuryoku_kosuu++;
}
return 0;
}
以上です...続きを読む

Aベストアンサー

#1です。

>struct tanka_ data { ・・・・(1)
>  int tanka;
>  int kosuu;
>  int kingaku;
>};
・・・途中省略
>} これでいいでしょうか

(1)のところは、変えてはいけません。
struct tanka_kosuu { 
のままにして下さい。
他は、問題ありません。

Qchar AA[]{"全角文字"};から"全"という一字を取り出したい

 今晩は、Cの初心者です、宜しくお願いします。
 全角文字の入ったchar AA[]{"全角文字"};から"全"という文字一字を取り出す時にAA[0]とかくとエラーになります。
 どのようにしたら取り出せるのでしょう。
 ポインタを使う方法と使わない方法を教えて下さい。
 宜しくお願いします。

Aベストアンサー

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出す必要があります。

>char AA[]={'全','角'};

char AA[]="全角";
とし
>printf("%s%s\n" , AA[0],AA[1] ) ;

printf("%c%c\n" , AA[0],AA[1] ) ;
とすれば、「全」だけを表示する事が可能と思われます。

日本語を文字列で表示する為の文字コードについては
Shift-JISだけでなく、UnicodeやUTF・EUC・JISなどがあります。

もう少し詳しく記載してあるホームページはないか探してみましたが、ちょっと無理でした。

参考URL:http://marupeke296.com/CPP_charUnicodeWideChar.html

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出...続きを読む

Qint kosuu; とstruct tanka_kosuu kosuu[10]; の関係は

同プログラムの内容で現在3個の質問をしておりますが!
 その質問を解決する上で4つ目の質問をさせていただきます。
 悪しからず・・・
 さて
以下のサイトのプログラムで 些細な疑問がございます。
https://oshiete.goo.ne.jp/qa/9062058.html
 で
 struct tanka_kosuu {
int tanka; 
int kosuu; 
int kingaku; /
以上の中にあるkosuuと
 struct tanka_kosuu kosuu[10];のkosuu[10]とは直接関係がありますか?
 馬鹿な質問ばかりで申し訳ございませんがよろしくお願いいたします。

Aベストアンサー

#No.1です。

>kosuu[10];をakb[10];変えたところ 以下の errorでてコンパイルできません!?
> example10.c(15) : error C2065: 'kosuu' : 定義されていない識別子です。


宣言している変数名を変更したら、その変数を利用している場所(エラーメッセージで15行目と書かれています)の変数名も変更する必要があると思いませんか?

下の例で、1行目も変数をaからbに変えたら、2行目,3行目のaも、bに変える必要があのはご理解いただけますよね?
01: int a;
02: a = 10;
03: printf("a=%d\n", a);

Qfp = fopen(argy[1], "r");の[1]の意味は

https://oshiete.goo.ne.jp/qa/8940272.html
 の11行目に
fp = fopen(argv[1], "r");の[1]の意味が分かりません。
試したいのですが、ソフトがうまく動きません
 よろしくお願いいたします。

Aベストアンサー

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから入力し実行すると、

argc = 5
argv[0] = "test"
argv[1] = "test1"
argv[2] = "test2"
argv[3] = "3"
argv[4] = "4"

と文字列が入ってきます。

以下はサンプル。

void main( int argc , char *argv[])
{
if( argc < 2 )
{
// パラメータ指定がなかった場合の表示
printf( "test に続けて4つまでパラメータを入力できます\n");
exit(0);
}
if( argc > 5 )
{
 // パラメータが5つ以上あった場合の表示
printf( "5つ以上のパラメータは受け付けません\n");
exit(-1);
}

// 正常ルート
printf( "パラメータの数は%d個ですね?ニヤッ\n", argc-1);
printf( "最初のパラメータは%sでしょ?\n", argv[1]);
printf( "残りはargv[2]以降ですが、面倒なので表示しません\n");
}

と言う具合に、引数を活用できます。argv[0]には、実行ファイル名が入ります。
argc は実行ファイルの名前も含めてカウントされます。

プログラムによっては必要な引数の数が変わりますし、
ユーザーのコマンドラインからの入力ミスなどでパラメータがなかったり、
必要なパラメータが不足していたりしますので、
argcとargvを使って最初にシンタックスエラーチェックをするのが常道です。

実行ファイル名の指定がなく、プログラムが実行されることはないと思われます
から、argcは1以上の値になります。

argc, argvの活用は、
実行コマンドを手打ちで打ち込むコンソール形式でよく用いられる基本的な
アプリケーションの開発手法です。

ご質問の箇所は、
第一パラメータにプログラム内で読み込むファイルのファイル名を指定してるの
でしょう。(よくあります)

しかし、Windowsなどのウィンドウを使用するアプリケーションは、
これとは違っておりますので注意が必要です。
(C言語とは別に、Windowsに特化した開発ノウハウの勉強が必要です)

Windows系で上記の様な基本的なプログラムを作成する場合は、
プロジェクトの作成時に(VisualStudioなどで)コンソールアプリケーション
を選んで作成します。実行時にコンソールが開きます。

Linuxの場合は、コンソールがデフォルトになっているでしょうから、
(特殊な設定がなければ)そのまま作成できます。

テキストエディタでソースを記述し、gcc などでコンパイルします。
実行形式ファイルが出来ていれば、想定どおりの動作をするでしょう。

ファイルの読み込みが出来るようになったら、
ファイルの内容を書き換えて保存したり、
ファイル名を変えたり、
ディレクトリ内のファイルを全て表示したり、
ファイル内に含まれる文字列を検索し、該当するファイルをリストしたりなど、

有用なサンプルプログラムを沢山作って練習します。

ファイルを読み込む先は、char型の配列でバイトサイズのメモリーとして確保
します。メモリーと変数の関係を充分に理解することをお勧めします。
殆どのプログラムは、このメモリーの確保やメモリーサイズの計算と格闘する
場合が多くなるからです。

バイナリー形式のファイル(すべてはバイナリー形式として良いのですが)に
ついて理解が深まった後は、
bmpの画像ファイル、wavなどの音声ファイルをあけて、
これの中身を書き換えて遊びます。

特にwavファイルは、音量の変更や周波数フィルタなども掛けれますので、
メモリ、配列、ファイルの関係を(焦らずに)ゆっくり理解するだけで、
今の知識レベルでも面白いことが沢山出来ます。

以上、ご参考に成れば。

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから...続きを読む

Qchar *(*)[3];について

#include <iostream.h>
main(){
char *(*pp)[3];
printf("%lu", sizeof(char*));
printf(" pp%lu", pp);
printf(", ++pp%lu", ++pp);
}

これを実行して
4 pp6660000, ++pp???????
のように表示されたときに、???????の部分が何になるか考えました。
ppはchar[3]を指すポインタのポインタだから、ppをインクリメントすれば、「char[3]を指すポインタ」の大きさだけ大きくなるはずだから、「char[3]を指すポインタ」の大きさである4バイト大きくなるはずだから
4 pp6660000, ++pp6660004
になると思いました。
どこを勘違いしていてどう考え直せばよいか教えて下さい。

Aベストアンサー

pp は、3コのポインタの配列へのポインタです。
ポインタのサイズが4バイトの時、
pp をインクリメントすると12バイト増えることになります。

例えば、次の様に書くとわかりやすいと思います。
#include <cstdio>

using namespace std;
// CHAR3 は、3のサイズを持つchar の配列
typedef char CHAR3[3];

int main(){
CHAR3 *pc3;//pc3 は、char[3]を指すポインタ
char test[3];
pc3=&test;
printf("%p\n",pc3);
pc3++;
printf("%p\n",pc3);//+3(サイズ分)される

CHAR3 **ppc3;//ppc3 は、char[3]を指すポインタのポインタ
ppc3=&pc3;
printf("%p\n",ppc3);
ppc3++;
printf("%p\n",ppc3);//+4(ポインタサイズ分)される

return 0;
}

pp は、3コのポインタの配列へのポインタです。
ポインタのサイズが4バイトの時、
pp をインクリメントすると12バイト増えることになります。

例えば、次の様に書くとわかりやすいと思います。
#include <cstdio>

using namespace std;
// CHAR3 は、3のサイズを持つchar の配列
typedef char CHAR3[3];

int main(){
CHAR3 *pc3;//pc3 は、char[3]を指すポインタ
char test[3];
pc3=&test;
printf("%p\n",pc3);
pc3++;
printf("%p\n",pc3);//+3(サイズ分)される

CHAR3 **ppc3;//p...続きを読む


人気Q&Aランキング

おすすめ情報