• ベストアンサー

配列内の文字列を読み込む方法

C++言語において質問です。あまり詳しくないので、変な質問でしたらすみません。 配列の文字列内にスペースが有る場合とない場合で表示を分けるものを作りたいと 思っています。 以下のようなものを書いた所、動くけど『iがいらない』、『メモリリークしている』 という風に言われました。自分でも調べてみたのですが、2つの事を解決できません。 どのようにすればよいのか、お教え願えませんか。 又、この場合のメモリリークとはどういう意味なのでしょうか? #include <stdio.h> #include <string.h> #include <ctype.h> char* name_list[] = {"", "AAA A", "BBBB", 0}; void main(){ int i = 1; char *b=0; for(char** a = &name_list[1]; *a != 0; a++, i++){ for(char* p = *a; *p != '\0' && !isspace((unsigned char)*p); p++) ; if(*p != '\0'){ b = new char[strlen(name_list[i]) + 3]; sprintf(b, "space %s", name_list[i]); } else { b = new char[strlen(name_list[i]) + 1]; strcpy(b, name_list[i]); } fprintf(stderr, "%s\n", b); } return; }

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

  • ベストアンサー
回答No.2

/*動くように修正しました、参考にでもしてください */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> char* name_list[] = {"", "AAA A", "BBBB", 0}; void main(){ int i = 1; char *b=0; for(char* a = name_list[1]; /* name_listの要素は char* です */ a != 0; i++, a = name_list[i]){ char *p; for(p = a; /* ポインターの扱いかたが間違っていました */ *p != '\0' && !isspace((unsigned char)*p); p++) ; if(*p != '\0'){ /* スコープ外でpを使用していたため宣言を移動しました */ b = new char[strlen(name_list[i]) + 3]; if (b == (char *)NULL) { /* エラー判断も入れましょう、大規模プログラムになると必要です */ printf("malloc error \n"); break; } sprintf(b, "space %s", name_list[i]); } else { b = new char[strlen(name_list[i]) + 1]; if (b == (char *)NULL) { printf("malloc error \n"); break; } strcpy(b, name_list[i]); } fprintf(stderr, "%s\n", b); free(b); /* これも必要です */ } }

2002hare
質問者

お礼

ありがとうございます。はい参考にさせて頂きます。 ご親切な解答、大変嬉しく思います。

その他の回答 (1)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

>『iがいらない』 後半部分の「name_list[i]」の参照は「*a」でOKです。 >『メモリリークしている』 「b = new char[strlen(name_list[i]) + 3];」で確保しているメモリ領域のサイズは「sprintf(b, "space %s", name_list[i]);」に4バイト足りません。 また、new演算子で確保された領域が開放されていません。 ループ内で毎回new演算子で確保される領域は、ループの終りでdelete演算子で開放しないといけません。 >又、この場合のメモリリークとはどういう意味なのでしょうか? ・確保したメモリサイズを超えてデータを代入している場合 ・確保したメモリを開放していない場合 など。 なお、実行文の無いfor文は「;」を見落とす事があるので for ( <初期化>; <条件>; <増分> ) ; と書かずに for ( <初期化>; <条件>; <増分> ) {;} と書くか for ( <初期化>; <条件>; ) { <増分>; } と書いた方が、可読性が向上します。 また、for文やif文など、命令語の後に括弧「(」が来る文では、命令語と括弧の間にスペースを入れた方が良いです。for文をテキスト検索する際に「for (」で検索をすれば、ユーザー定義の関数の「userfor()」が検索に引っ掛かったりしなくなるので便利です。 あと、isspaceでは、空白文字にタブ、改行、改ページ、なども含まれてしまうので、スペースのみを判定する場合はstrchrを使用すると良いでしょう。 プログラムを最適化すると、以下のようになります。 #include <stdio.h> #include <string.h> char* name_list[] = {"AAA A", "BBBB", NULL}; void main() {  for (char **a = name_list; *a != NULL; a++) {   if (strchr(*a,' ') != NULL) {    fprintf(stderr, "space %s\n", *a);   } else {    fprintf(stderr, "%s\n", *a);   }  }  return; } この例では、以下の最適化を行っています。 ・メモリの確保と開放を必要最低限にする。 ・極力、ループを減らす。 ・メモリのコピー(strcpy、sprintfなど)を減らす。 ・配列のインディックス参照の変わりにポインタを使う。 ・使用しない配列要素は配列から削除する。

2002hare
質問者

お礼

迅速な解答どうもありがとうございます。 丁寧に説明していただいたのでよくわかりました。

関連するQ&A