• ベストアンサー

switchとメモリ取得位置

#include <stdlib.h> #include <string.h> #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE -1 char* get(char **p_str); char *get_line(char buf[]); int comp_rtn(const void *p1, const void *p2); typedef struct { int number; char class_type[10]; char name[15]; char subject[10]; int ten; } my; my *data; void myswap(my *p, my *q); int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufFormat; char *bufG; bufG = (char *)malloc(1000); if(bufG == NULL){ printf("メモリ不足"); free(bufG); } int line2 = 0; if((fp=fopen("jjj.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); if((fp=fopen("jjj.txt","r"))==NULL){   printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); if(data == NULL){ printf("メモリ不足"); free(data); } while(fgets(buf,1000,fp) != NULL){ bufFormat =(char *)malloc(strlen(buf) + 1); if(bufFormat == NULL){ printf("メモリ不足"); free(data); } bufFormat = get_line(buf); str = bufFormat; while(*str != '\0'){ bufG = get(&str); switch(field){      case 0: data[line].number = atoi(bufG); break case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; case 4: data[line].ten = atoi(bufG); break; } str++; field++; } line++; field = 0; } fclose(fp); qsort(data,line,sizeof(my),comp_rtn); for(int m = 0; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject); printf("%d\n", data[m].ten); printf("\n"); } free(data); return 0; } void myswap(my *p, my *q) { my temp; temp = *p; *p = *q; *q = temp; } char *get(char **p_str) { int i; char *str; str = *p_str; static char bufG[1000]; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else if(*str == '\\'){ str++; if(*str == 'c'){ bufG[i] = ','; } else if(*str == '"'){ bufG[i] = '"'; } } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; *p_str = str; return bufG; } char *get_line(char buf[]) { int in_quotation = FALSE, i = 0; char* str = buf; static char bufG[1000]; while(*str != '\0'){ if(*str=='"'){ if(in_quotation == TRUE){ str++; if(*str == '"'){ bufG[i] = '\\'; i++; bufG[i] = '"'; i++; } else{ in_quotation = FALSE; bufG[i] = *str; i++; } } else{ in_quotation = TRUE; } } else{ switch(*str){ case '\n': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'n'; i++; } else{ bufG[i] = *str; i++; } break; case ',': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'c'; i++; } else{ bufG[i] = *str; i++; } break; default: bufG[i] = *str; i++; } } str++; } bufG[i] = '\0'; return bufG; } 構造体メンバをポインタで宣言する方法はもうできていて 配列の方も組んでいるのですが 比較関数など所々省いてますがこのプログラムに対し以下のことをいわれました 1,switch文のfieldの値を数字じゃなく分かりやすいのに変えよ 2,mainのすぐしたの bufG = (char * )malloc(1000)が なかなか使用されないのにここでメモリを取るのはおかしい 3,これを使うまでの間にエラーが発生したときのfreeがない と言われました。 1ですが確かCではswitch文のcase式は整数型定数でなければならない とあるので無理な気もするのですが、方法ありますか? 2に関してはよくわかりません。効率がよくないのでしょうか? どの場所がいいのでしょうか 3に関してはどういうことなのかもわかりません。 この3点について教えて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8512/19352)
回答No.5

1. enum { number_col, class_type_col, name_col, subject_col, ten_col }; (略) case number_col: data[line].number = atoi(bufG); break case class_type_col: strcpy(data[line].class_type, bufG); break; case name_col: strcpy(data[line].name, bufG); break; case subject_col: strcpy(data[line].subject, bufG); break; case ten_col: data[line].ten = atoi(bufG); 2. get関数、get_line関数で static char bufG[1000]; と定義して、静的なメモリのアドレスを return bufG; で返している。 で、mainは bufG = get(&str); と、静的なメモリのアドレスをbufGに受け取っている。 つまり「mallocしたメモリのアドレスをbufGに入れてあるのをすっかり忘れて、bufGを変更しちゃってるので、mallocしたメモリを2度とfree出来なくなっている」と言う状態になっている。 「効率が良くない」とかの問題じゃなく ・mallocしたメモリがfreeできず、メモリがリークしている ・そもそも、静的なメモリを使用しているのだから、mallocそのものが不要 同様の事が、bufFormatでも起きている。 bufFormat =(char *)malloc(strlen(buf) + 1); (中略) bufFormat = get_line(buf); ここでも「mallocしたメモリのアドレスをbufFormatに入れてあるのをすっかり忘れて、bufFormatを変更しちゃってるので、mallocしたメモリを2度とfree出来なくなっている」と言う状態になっている。 3. 「mallocしたすべてのメモリは、freeするまで、保持しつづけなければならない」「mallocしたすべてのメモリは、プログラムが終了する前までに、プログラマが責任を持ってすべてfreeしなければならない」と言う事が理解できていません。 しかも、質問者さんは「エラー判定がまったく出来ていない」です。 質問者さんがやってるのは「エラー判定のフリ」だけで、何もしてないのと同じです。 エラー判定とは「エラーのため、必要な物を確保、設定出来なかった時に<<<<それ以上、処理を継続しないため>>>>の処理」です。 「<<<<」と「>>>>」で囲った部分を100回読んで下さい。 100回読んでから if(bufG == NULL){ printf("メモリ不足"); free(bufG); } とか if((fp=fopen("jjj.txt","r"))==NULL){ printf("ファイルが開けません"); } とか if(data == NULL){ printf("メモリ不足"); free(data); } とかの部分を良く見てください。 これらのエラー処理は「エラーだ、と報告しているだけで、平気で処理を継続してしまっていて、必要な変数が設定されてないまま、必要なファイルが開けてないまま、プログラムを中断してない」です。 通常、エラー処理というのは、以下のようにします。 p1 = malloc(~~~); if (p1 == NULL) { printf("メモリ不足\n"); return 0;//これ以上処理できないので呼び出し元に帰る } p2 = malloc(~~~); if (p2 == NULL) { free(p1);//p1はmalloc出来てるので、freeして後始末する printf("メモリ不足\n"); return 0;//これ以上処理できないので呼び出し元に帰る } p3 = malloc(~~~); if (p3 == NULL) { free(p1);//p1はmalloc出来てるので、freeして後始末する free(p2);//p2はmalloc出来てるので、freeして後始末する printf("メモリ不足\n"); return 0;//これ以上処理できないので呼び出し元に帰る } fp=fopen(~~~); if (fp == NULL) { free(p1);//p1はmalloc出来てるので、freeして後始末する free(p2);//p2はmalloc出来てるので、freeして後始末する free(p3);//p3はmalloc出来てるので、freeして後始末する printf("ファイルが開けません\n"); return 0;//これ以上処理できないので呼び出し元に帰る } p4 = malloc(~~~); if (p4 == NULL) { free(p1);//p1はmalloc出来てるので、freeして後始末する free(p2);//p2はmalloc出来てるので、freeして後始末する free(p3);//p3はmalloc出来てるので、freeして後始末する fclose(fp);//fpはfopen出来てるので、fcloseして後始末する printf("メモリ不足\n"); return 0;//これ以上処理できないので呼び出し元に帰る } //全てのメモリ、ファイルが準備出来たので、ここで処理開始 (中略) //すべての処理が終ったら、すべてfreeし、すべてfcloseする free(p4); fclose(fp); free(p3); free(p2); free(p1); //すべてfreeし、すべてfcloseしているのでreturnして、プログラムを終了しても良い return 0; 質問者さんのプログラムは、こういう「後始末」がまったく出来てないので「どうにかしろ」と言われたのです。 以下蛇足。 「表」の漢字でバグが起きるのが直ってませんね。 http://okwave.jp/qa5122320.html '\\'を'_'に変えたとしても「表」でバグる代わりに「廟」でバグるようになるだけで、何の問題解決にもなってません。 ちゃんと「漢字は漢字として処理して、漢字の第2バイトの'\\'は、'\\'として特殊処理しないでスキップする」と言う処理をしましょう。 もし「漢字の判定が出来ない」と言うなら、漢字の第2バイトに来ない文字だけを特殊文字に使用しましょう。 漢字の第2バイトには !"#$%&'()*+,-./0123456789:;<=>? の文字は来ないので、この文字を特別扱いするなら、漢字の判定は不要です。 エラー処理の件もそうですが「対処療法的に目に見える事象やバグにだけ対処し、根本的な原因や理由を理解、解決しようとしない姿勢」は、質問者さんの悪い癖です。 こういう姿勢が身についてしまっているので >3に関してはどういうことなのかもわかりません。 と言うように「何が悪いのか、理解できない」と言う状況に陥るのです。

rooding
質問者

お礼

そんな姿勢になってる感はありますね。 わかりやすい解説ありがとうございました。 わかったこと ・静的なメモリについての理解ができていなかった ・エラー処理に関しては本文ではreturn 0は入ってますが それ以外は不足していました。 ・漢字の2バイト free(bufFormat)ってすると落とされててあれ・・って なってたんですが、この説明でわかりました。 皆様貴重な意見ありがとうございました。

その他の回答 (4)

回答No.4

このコードなら、1.については、 列挙体(enum)を使った方が良いと思います。 switch(field) で、分岐して、しかも、 field++; で処理を切り替えています から、#define による定義だと、 #define isNumber 0 #define isClass 1 #define isName 3 #define isSubject 3 なんてなっていて、正体不明のバグに 引っかかるかもしれません。 enum FieldType {isNumber, isClass, ...} だと、 enum FiledType field; で、 filed = isNumber; とかできますし、 filed++; で、定義した順序で、抜けなく処理できる ことがわかりますから。 あと、C++なら、型チェックも効きます。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.3

1. 例えば case -1: よりも case FALSE: のほうがわかりやすいという意味でしょう 2.3. bufG = get(&str); で別のポインタを代入してるようなので bufG = (char *)malloc(1000); if(bufG == NULL){ printf("メモリ不足"); free(bufG); } の部分は削除しても問題ないと思いますよ

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.2

1は#defineでも使って整数の代わりにマクロ名を使う。 2はbufGの使い方を見るとmallocした領域を使っていないように見える。そもそもmallocが必要ないのでは? 3は実際は途中のエラーのあるなしに関わらず2でmallocした領域を正しくfreeしていない。 bufGはfreeする前に他のアドレスで上書きされてしまっている。 なお、メモリ不足でmallocがNULLを返した場合にその変数をfreeすることには意味がない。むしろfreeすべきなのは他の既に獲得した領域を保持する変数だし、また必要な領域が確保できていないのに異常終了させずに先に進んでは不味いだろう。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

1. #defineかconstを使えって事です。 2. 主にデバッグ効率の問題です。大抵の場合は使う直前のところ、このコードならwhileループの直前で確保するように書きます。 3. fopen()などでエラーが発生したときにbufGを解放してないということです。 あと、bufG==NULLの時のfree(bufG)は不要というか無意味です。あっても問題ありませんが、もともと確保できてないからNULLが返っているので。

関連するQ&A

  • CArray

    #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE -1 char* get(char **p_str); char *get_line(char buf[]); int comp_rtn(const void *p1, const void *p2); typedef struct { int number; char class_type[10]; char name[15]; char subject[10]; int ten; } my; my *data; void myswap(my *p, my *q); int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufFormat; char *bufG; int line2 = 0; if((fp=fopen("jjj.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); if((fp=fopen("jjj.txt","r"))==NULL){   printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); while(fgets(buf,1000,fp) != NULL){ bufFormat = get_line(buf); str = bufFormat; while(*str != '\0'){ bufG = get(&str); switch(field){      case 0: data[line].number = atoi(bufG); break case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; case 4: data[line].ten = atoi(bufG); break; } str++; field++; } line++; field = 0; } fclose(fp); qsort(data,line,sizeof(my),comp_rtn); for(int m = 0; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject); printf("%d\n", data[m].ten); printf("\n"); } free(data); return 0; } void myswap(my *p, my *q) { my temp; temp = *p; *p = *q; *q = temp; } char *get(char **p_str) { int i; char *str; str = *p_str; static char bufG[1000]; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else if(*str == '\\'){ str++; if(*str == 'c'){ bufG[i] = ','; } else if(*str == '"'){ bufG[i] = '"'; } } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; *p_str = str; return bufG; } char *get_line(char buf[]) { int in_quotation = FALSE, i = 0; char* str = buf; static char bufG[1000]; while(*str != '\0'){ if(*str=='"'){ if(in_quotation == TRUE){ str++; if(*str == '"'){ bufG[i] = '\\'; i++; bufG[i] = '"'; i++; } else{ in_quotation = FALSE; bufG[i] = *str; i++; } } else{ in_quotation = TRUE; } } else{ switch(*str){ case '\n': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'n'; i++; } else{ bufG[i] = *str; i++; } break; case ',': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'c'; i++; } else{ bufG[i] = *str; i++; } break; default: bufG[i] = *str; i++; } } str++; } bufG[i] = '\0'; return bufG; } 以前上記のソースになるプログラムの質問をいくつかしました。 これはCで組んでますがC++で組みなおすに当たり 今mallocを使っていますがCArrayを使用するように薦められました どういう感じになるのかさっぱりわかりません。

  • メモリ

    #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> int check(int a[100], int n); typedef struct { char number[6]; char class_type[20]; char name[8]; char subject[5]; } my; my data[100]; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: strcpy(data[line].number, bufG); break; case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; } field++; } else{ str++; } } line++; field = 0; } int p, q; int a[100]; int u = 0; for(p = 0; p < line; p++){ for(q = 0; q < line; q++){ if(strcmp(data[p].class_type, data[q].class_type) == 0 && strcmp(data[p].subject, data[q].subject) == 0 && p != q ){ //処理 } } } } fclose(fp); return 0; } 先日文字列入れ替えについてご質問したものですが メモリの取り方についてご質問します。 先日このプログラムにおいて my data[100]と固定してるのはいけないという意見をもらったので メモリを取得しようと思ってるのですが できればdata[i].○○の形でアクセスしたいのでこのままの形は あまりかえたくないです。この場合 while(fgets(buf,1000,fp) !=NULL){ str=buf;     int len = strlen(buf); my *o; o = (my *)calloc( len + 1, sizeof(my *)) while(*str != '\0'){ としてみたのですがこれは実際どうなのでしょうか? NULLは帰ってきてないみたいなので割り当ては出来てるとは思うんですが この一行の文字列の大きさにぴったり合うメモリを割り当てたいのですが ちゃんとなっているか調べる方法を教えて下さい。

  • 配列

    数回に渡り質問させてもらってますが 構造体のメンバをポインタで宣言してるのが不評で 配列の方でも組んでみました。 #include <stdlib.h> #include <string.h> #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE -1 char* get(char **p_str); char *get_line(char buf[]); int comp_rtn(const void *p1, const void *p2); typedef struct { int number; char class_type[10]; char name[15]; char subject[10]; int ten; } my; my *data; void myswap(my *p, my *q); int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufFormat; char *bufG; bufFormat =(char *)malloc(1000); bufG = (char *)malloc(1000); int line2 = 0; if((fp=fopen("jjj.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); if((fp=fopen("jjj.txt","r"))==NULL){   printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); while(fgets(buf,1000,fp) != NULL){ bufFormat = get_line(buf); str = bufFormat; while(*str != '\0'){ bufG = get(&str); switch(field){      case 0: data[line].number = atoi(bufG); break case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; case 4: data[line].ten = atoi(bufG); break; } str++; field++; } line++; field = 0; } fclose(fp); qsort(data,line,sizeof(my),comp_rtn); for(int m = 0; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject); printf("%d\n", data[m].ten); printf("\n"); } free(data); return 0; } void myswap(my *p, my *q) { my temp; temp = *p; *p = *q; *q = temp; } char *get(char **p_str) { int i; char *str; str = *p_str; static char bufG[1000]; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else if(*str == '\\'){ str++; if(*str == 'c'){ bufG[i] = ','; } else if(*str == '"'){ bufG[i] = '"'; } } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; *p_str = str; return bufG; } char *get_line(char buf[]) { int in_quotation = FALSE, i = 0; char* str = buf; static char bufG[1000]; while(*str != '\0'){ if(*str=='"'){ if(in_quotation == TRUE){ str++; if(*str == '"'){ bufG[i] = '\\'; i++; bufG[i] = '"'; i++; } else{ in_quotation = FALSE; bufG[i] = *str; i++; } } else{ in_quotation = TRUE; } } else{ switch(*str){ case '\n': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'n'; i++; } else{ bufG[i] = *str; i++; } break; case ',': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'c'; i++; } else{ bufG[i] = *str; i++; } break; default: bufG[i] = *str; i++; } } str++; } bufG[i] = '\0'; return bufG; } ファイルは 1,犬,ボルト,国語,2 2,猫,山田,数学,1 3,犬,鈴木,英語,2 4,犬,居合,国語,1 5,猫,伊藤,数学,2 6,猫,斎藤,数学,1 こういう感じになりますが 不思議なことにこのファイルの文字列の所を 表 にすると バグって表示されます。 例えば 1,表,山田,数学,2とか 1,犬,ボルト,国語,2 2,猫,山田,数学,1 3,犬,鈴木,英語,2 4,犬,居合,国語,1 5,猫,伊藤,表,2 6,猫,斎藤,数学,1 とかです。 この現象は何故起きるのでしょうか? デバグした所、代入のときにはちゃんとしたものが代入されていますが 次の項目を代入したときにバグ化しているようです V開発環境はC++6.0のコンソールappです。

  • ソート

    #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> void swap(char p[], char q[]); void get(char bufG[],char **p_str); typedef struct { int number; char *class_type; char* name; char *subject; int num_akaten; } my; my *data; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000]; char bufG[1111]; char *str; int m; int line2 = 0; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); printf("%d\n", line2); if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); while(fgets(buf,1000,fp) != NULL){ str = buf; while(*str != '\0'){ get(bufG,&str); switch(field){ case 0: data[line].number = atoi(bufG); break; case 1: data[line].class_type = (char *)malloc(strlen(bufG) +1); strcpy(data[line].class_type, bufG); break; case 2: data[line].name = (char *)malloc(strlen(bufG) + 1); strcpy(data[line].name, bufG); break; case 3: data[line].subject =(char *)malloc(strlen(bufG) + 1); strcpy(data[line].subject, bufG); break; case 4: data[line].num_akaten = atoi(bufG); } str++; field++; } line++; field = 0; } fclose(fp); for(m = 0; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject); printf("%d\n", data[m].num_akaten); } return 0; } void get(char bufG[],char **p_str) { int i; char *str; str = *p_str; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; *p_str = str; return ; } 前問題の解答例を提示してくださった方のサンプルをコピペさせてもらって成績の項目を追加しています。本文ではget関数の型はchar*型で文字列を返していますが今回の件では余り関係ないのでこのままで。 ファイルの中身は 1,犬,ボルト,国語,2 2,猫,山田,数学,1 3,犬,鈴木,英語,2 4,犬,居合,国語,1 5,猫,伊藤,数学,2 6,猫,斎藤,数学,1 のような感じになってます。 クラスの名前は今までアルファベットできたがこちらにしました。 名前自体に意味はありません。クラス名を文字列にしただけです。 やりたいソートの条件は赤点の多い順が優先でクラスと好きな教科が 同じものをソートしたい。優先順位は赤点→クラスとが一致→教科が一致 なので 1,犬,ボルト,国語,2 3,犬,鈴木,数学,2 5,猫,伊藤,数学,2 2,猫,山田,数学,1 6,猫,斎藤,数学,1 4,犬,居合,国語,1 このようなファイルに並び替えされます。 今試してるのは↑のソースで各値を入れ終わった後に for(p = 0; p < line; p++){ for(q = p + 1; q < line; q++){ if(data[p].num_akaten < data[q].num_akaten){ swap(&p,&q);//swapはp行とq行の全項目を入れ替える関数   } } } こうするととりあえず赤点数の順にはなります これからさらに上記のような並びにしたいです。(クラスと教科が同じ順) ここからどうすればいいでしょうか? 出来れば同じループ内で処理したいです。 私が考えていたのがp行のクラスとq行のクラスが同じ場合 p+1行目のクラスがp行目のクラスと異なっているなら p+1行目とq行目を交換するというのを試していましたが うまくいかないのでこの方法はダメなのでしょう。 他にもっとよい方法がある といった場合教えていただけると助かります。

  • ポインタ

    #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> typedef struct { char number[6]; char class_type[20]; char name[8]; char subject[5]; } my; my data[100]; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i; if((fp=fopen("test.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; // printf("%s", bufG); switch(field){ case 0: strcpy(data[line].number, bufG); break; case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; } field++; } else{ str++; } } line++; field = 0; } printf("%s", data[2].subject); fclose(fp); return 0; } このプログラムをベースにしてメモリの無駄を省けるような プログラムに修正したいのですが、 ポインタほんとできなくて困ってます。 教えていただいてメモリを取る位置とかは大体わかりました。 まず構造体のメモリをとります。しかしこのままでは固定長になってるので 構造体を少しいじくりますよね。 構造体の中身なのですが typedef struct{ int number; char *class_type; char *name; char *subject; } my; my *data; にして data = malloc(100); このような形でとります。 文字列の型ですがchar *class_typeのようにポインタで宣言しないと bufGを代入して値を入れるときに型が合いませんので 配列にしないのであればポインタ型宣言でいいと思います。 しかしポインタで宣言してstrcpy(・・)の所を data[line].class_type = bufG にするとエラーはでませんが*strの値が変わる度に data[line].class_typeの値が変動するのでdata[line].class_typeが 国語 とかになったりします。 なんかもうさっぱりわからないんですが どうすればいいのでしょうか? 変換したソースがほしいです。

  • メモリ2(ポインタ編)

    #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> int check(int a[100], int n); typedef struct { char *number; char *class_type; char *name; char *subject; } my; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i, len; my *o; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; len = strlen(buf); o = (my *) calloc(len + 1, sizeof(my *)); while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: o[line].number = bufG; break; case 1: o[line].class_type = bufG; break; case 2: o]line].name = bufG; break; case 3: o[line].subject = bufG; } field++; } else{ str++; } } line++; field = 0; } fclose(fp); return 0; } 固定なのがいけないといわれたのでこのように 変更しました。もちろん上手く動かないわけですが 原因を教えて下さい。 ちなみにエラーはo[0].numberが国語とかになってたり ちゃんとアクセスができません。

  • 関数化

    #include <ctype.h> #include <string.h> #include <stdlib.h> void swap(char p[], char q[]); char *get(char *str, char buf[], int line, int field); typedef struct { int number; char *class_type; char* name; char *subject; } my; my *data; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufG; int line2 = 0; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); printf("%d\n", line2); if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); while(fgets(buf,1000,fp) != NULL){ str = buf; while(*str != '\0'){ bufG = get(str, buf, line, field); switch(field){ case 0: data[line].number = atoi(bufG); break; case 1: data[line].class_type = (char *)malloc(strlen(bufG) +1); strcpy(data[line].class_type, bufG); break; case 2: data[line].name = (char *)malloc(strlen(bufG) + 1); strcpy(data[line].name, bufG); break; case 3: data[line].subject =(char *)malloc(strlen(bufG) + 1); strcpy(data[line].subject, bufG); break; } str++; field++; } line++; field = 0; } fclose(fp);     for(int m = 1; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject);     } return 0; } char *get(char *str, char buf[], int line, int field) { char bufG[1111]; int i; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; return bufG; } 前回の質問 http://okwave.jp/qa5094929.html で提示していただいたサンプルの関数化をはかりましたが うまくいきません。これを実行すると1しか表示されません。 原因はおそらくポインタだと思いますがどうすればいいのか わかりません。教えて下さい。bufを引数にする意味ないのでは という意見は今の所はとりあえずなしで fieldの値によってbufGが色々とってくる。 例えば1,A,山田,数学の場合 field = 0のときbufGは1 filed=1のときbufGはA field=2のときbufGは山田 filed=3のときbufGは数学という ような値が返ってくるようにしたいです。

  • 文字入れ替え

    #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> typedef struct { char number[6]; char class_type[20]; char name[8]; char subject[5]; } my; my data[100]; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: strcpy(data[line].number, bufG); break; case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; } field++; } else{ str++; } } line++; field = 0; } int p, q; for(p = 0; p < line; p++){ for(q = 0; q < line; q++){ if(strcmp(data[p].class_type, data[q].class_type) == 0 && strcmp(data[p].subject, data[q].subject) == 0 && p != q ){ printf("p=%d q=%d\n", p, q); } } } fclose(fp); return 0; } こちらのプログラムは 1,A,山根,音楽//番号、クラス、名前、好きな教科 2,B,本田,美術 3,B,松本,美術 4,A,横野,音楽 というファイルの内容を読み込んでクラスと好きな教科が同じものを 1,A,山根、音楽 4,A,横野、音楽 2,B,本田、美術 3,B,松本、美術のようにソートするプログラムの続きですが ソート方法についてです。 if(strcmp(data[p].class_type, data[q].class_type) == 0 && strcmp(data[p].subject, data[q].subject) == 0 && p != q ){ swap(data[p+1].number, data[q].number; swap(data[p+1].class_type, data[q].class.type); swap(data[p+1].name,data[q].name); swap(data[p+1].subject,data[q].subject); } void swap(char *p, char *q) { char *temp; temp = p; p = q; q= temp; } のように追加してみましたが入れ替えができていません。 どこがまずいのでしょうか?又他にも良い方法があれば教えて下さい。

  • ポインタ(追加質問)

    http://okwave.jp/qa5092628.html の続きです。補足にいれようかとも思いましたが 以前より前の質問は占めたほうがいいと言われつづけてたので 閉めてしまいました。 #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdio.h> typedef struct{ int number; char *class_type; char *name; char *subject; } my; my *data; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i, non_value = 0; data = malloc(sizeof(my)*100); //最大100人分とる。それを越えたケースは今は考慮しない。ここを変更 if((fp=fopen("test.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: data[line].number=atoi(bufG); //ここを変更 break; case 1: data[line].class_type = malloc(strlen(bufG)+1); //これを追加 strcpy(data[line].class_type, bufG); break; case 2: data[line].name = malloc(strlen(bufG)+1); //これを追加 strcpy(data[line].name, bufG); break; case 3: data[line].subject = malloc(strlen(bufG)+1); //これを追加 strcpy(data[line].subject, bufG); break; } field++; } else{ str++; non_value++; if(non_value == 2){ switch(field){ case 0: data[line].number=' '; //ここを変更 break; case 1: data[line].class_type = malloc(3); //これを追加 strcpy(data[line].class_type, " "); break; case 2: data[line].name = malloc(3); //これを追加 strcpy(data[line].name, " "); break; case 3: data[line].subject = malloc(3); //これを追加 strcpy(data[line].subject, " "); break; } non_value = 0; str++; field++; } } line++; field = 0; } //ここはおまけ for (i =0; i < line;i++){ printf("%d:%s:%s:%s\n", data[i].number,data[i].class_type,data[i].name,data[i].subject); } fclose(fp); return 0; } 前回載せてもらった解答ではcsvファイルに空欄があると 値が代入されなかったのでその機能をつけました。 具体的には,が連続してあると(csvファイルに空欄がある場合1,A,,数学のように,と,の間には何もない)場合半角スペースを入れてます。 この場合例えば1,A,,数学のように名前の欄を空白にするとdata[0].name は半角スペースが入ってますが その次の値、すなわちdata[0].subjectの値がばぐった値になっています。 改善方法を教えて下さい。 もう1点あります。上のソースでは data = malloc(sizeof(my)*100); //最大100人分とる。それを越えたケースは今は考慮しない。ここを変更 とありますがこれを while(fgets(buf,1000,fp) != NULL){ str = buf; data = malloc(sizeof(my)*100); ←このへんに  if(line > 100)){ //メモリ追加処理 } のようにすることは可能ですか?

  • 配列

    #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> typedef struct { char number[6]; char class_type[20]; char name[8]; char subject[5]; } my; my data[100]; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: strcpy(data[line].number, bufG); break; case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; } field++; } else{ str++; } } line++; field = 0; } int p, q; for(p = 0; p < line; p++){ for(q = 0; q < line; q++){ if(strcmp(data[p].class_type, data[q].class_type) == 0 && strcmp(data[p].subject, data[q].subject) == 0 && p != q ){ printf("p=%d q=%d\n", p, q); } } } fclose(fp); return 0; } こちらのプログラムは 1,A,山根,音楽//番号、クラス、名前、好きな教科 2,B,本田,美術 3,B,松本,美術 4,A,横野,音楽 というファイルの内容を読み込んでクラスと好きな教科が同じものを 1,A,山根、音楽 4,A,横野、音楽 2,B,本田、美術 3,B,松本、美術のようにソートするプログラムの途中で 一致する行を表示しようとしている所です。 これをコンパイルした場合 一致しているのは 0行目と3行目 1行目と2行目 2行目と1行目 3行目と0行目と表示され実際には同じ行が含まれています。 このような場合どのように改善すればいいのか教えて下さい。

専門家に質問してみよう