ページ 1 / 1
文字列を配列に
Posted: 2009年5月21日(木) 09:02
by ウズ
お世話になります。
タイトルどおりですが、
何個あるかわからない文字列("ABC"、"DEFG"、・・・などなど)を
配列に持ちたいのですが、
どうやったらいいのか、さっぱりわかりません。
どなたか教えてください。
何個あるかわからない文字列、とは、
実際は別関数でとってくる文字列があって、それを配列にセットしていきたいのです。
説明足らずで申し訳ないですが、宜しくお願いします。
Re:文字列を配列に
Posted: 2009年5月21日(木) 10:12
by non
環境がわかりませんので、Cだとしたら、
reallocで必要に応じて領域を広げる方法があります。
下のプログラムは1例です。5文字分ずつ領域を広げてます。
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *str;
int ch,n;
str=(char *)calloc(6,sizeof(char));//ナル文字分を含む
n=0;
while((ch=fgetc(stdin))!=EOF){
str[n]=ch;
n++;
if(n % 5 ==0)
str=(char *)realloc(str,sizeof(char)*5);
}
str[n]='\0';
puts(str);
free(str);
return 0;
}
キー入力の終了はCTRL-Zです。
Re:文字列を配列に
Posted: 2009年5月21日(木) 10:43
by Blue
C言語でstd::vector<std::string>みたいなのをやりたいってことでは?
reallocする対象がchar**になるわけで。
http://homepage1.nifty.com/MADIA/vc/vc_ ... 20032.html
が参考になるかも。
ちなみに、開発環境は必ず明記しましょう。(コンパイラ等)
Re:文字列を配列に
Posted: 2009年5月21日(木) 11:21
by ウズ
>non様
>Blue様
返答ありがとうございます。
開発環境はCでコンパイラはGCCです。バージョンは3.2.2です。
領域を増やす場合、よく定数で増やしたり、倍に増やしたりとしていますが、
それは何故なんでしょう??(とんちんかんなことを聞いているのかもしれませんがすみません)
strlen()で文字列の長さはわかるのに??と思ってしまいます。。
Re:文字列を配列に
Posted: 2009年5月21日(木) 11:52
by non
strlenで長さがわかるなら、(既に別の配列に格納されているのなら)何も、reallocしなくても
いっぺんにcallocかmallocでかまいませんよ。
これは、少しずつ文字数が増えるような場合の手段です。
例えば、この掲示板に書き込むときコメントを入力する欄がありますが、この欄のために何文字分の
配列を用意しますか?1行入力するたびに、次の1行分の領域を広げると無駄がないと思いませんか?
Re:文字列を配列に
Posted: 2009年5月21日(木) 12:25
by non
上に添付したプログラム間違いがありました。
reallocは再確保した領域のバイト数をsizeで指定しなくてはいけませんでしたね。
str=(char *)realloc(str,6+sizeof(char)*5*(n/5));
のようにすればいいでしょうか。
Re:文字列を配列に
Posted: 2009年5月21日(木) 12:26
by YuO
malloc系の処理が重いことが多く,その実行時間を軽減する目的で過剰に確保しています。
例えば,下のプログラムで確認すると,
time1 : 63.662000
time2 : 0.024000
と,非常に大きな差がでました。
注) 例示プログラムは,size_tが25bit以上の幅を持つことを前提に書いています。
下記の結果は,一文字ずつ文字列に文字を追加する場合にmalloc/reallocにかかる時間の計測になります。
文字列やコレクションにおいて,このようなことは度々おこるため,
大きめにメモリを確保しておいて,その一部を利用するという手法がとられています。
Example)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define MAX_SIZE (size_t)(1UL << 24)
size_t increment (size_t size)
{
return size + 1;
}
size_t times2 (size_t size)
{
return size * 2;
}
clock_t measure (size_t max_size, size_t (*func)(size_t))
{
clock_t start, end;
void * ptr;
size_t size;
start = clock();
ptr = 0;
for (size = 1; size < max_size; size = func(size)) {
void * nptr = realloc(ptr, size);
if (nptr == 0) {
fprintf(stderr, "memory allocation error.\n");
free(ptr);
exit(EXIT_FAILURE);
}
ptr = nptr;
}
free(ptr);
end = clock();
return end - start;
}
int main (void)
{
clock_t first, second;
first = measure(MAX_SIZE, increment);
second = measure(MAX_SIZE, times2);
printf("time1 : %f\n", first / (double)CLOCKS_PER_SEC);
printf("time2 : %f\n", second / (double)CLOCKS_PER_SEC);
return EXIT_SUCCESS;
}
Re:文字列を配列に
Posted: 2009年5月21日(木) 14:11
by ウズ
皆様稚拙な質問に答えていただいてありがとうございます。
①文字列”ABC”がきたら
|A|B|C|\0|
という入れ物をつくり
②次に文字列”DEFG”がきたら
|D|E|F|G|\0|
という入れ物をつくる。。
③最後には
|A|B|C|\0|
|D|E|F|G|\0|
という(2次元?)配列ができていればいいのですが、
(mojiには文字列がはいってくるとします。毎回中身は別物です)
①は
char *cp_tmp;
char **cp_table;
cp_tmp = (char * )malloc(sizeof(strlen(moji))+1);
strcpy(cp_tmp, moji);
cp_table = (char *)realloc(cp_table, sizeof(char)+1);
cp_table[0] = &cp_tmp;
というかんじになるのかとは思ったのですが、
②になるとcp_tmpなるものがまた必要?とかいろいろぐるぐるしてしまって。。
Re:文字列を配列に
Posted: 2009年5月21日(木) 14:39
by toyo
temporary作らなくても
char **cp_table = NULL;
cp_table = (char **)realloc(cp_table, sizeof(char*) * 1);
cp_table[0] = (char *)malloc(sizeof(strlen(moji))+1);
strcpy(cp_table[0], moji);
cp_table = (char **)realloc(cp_table, sizeof(char*) * 2);
cp_table[1] = (char *)malloc(sizeof(strlen(moji2))+1);
strcpy(cp_table[1], moji2);
で出来ます
1個ずつreallocで増やさずにあらかじめある程度の個数を確保して足らなくなったらreallocでいいと思いますが
Re:文字列を配列に
Posted: 2009年5月21日(木) 15:01
by 初級者
1行あたりの文字数に制限があってよいならば、こんな方法があるかもしれません。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN (80)
int main(void)
{
char **p, s[LEN];
int n, i;
for (p = NULL, n = 0; printf("文字列 > "), fgets(s, sizeof(s), stdin); n++) {
s[strlen(s)-1] = '\0';
p = (char **) realloc(p, sizeof(char *) * (n + 1));
if (!p) {
exit(1);
}
p[n] = (char *) malloc(sizeof(char) * (strlen(s) + 1));
if (!p[n]) {
exit(1);
}
strcpy(p[n], s);
}
for (i = 0; i < n; i++) {
printf("%s\n", p);
}
for (i = 0; i < n; i++) {
free(p);
}
free(p);
return 0;
}
Re:文字列を配列に
Posted: 2009年5月22日(金) 09:55
by ウズ
>toyo様
>初級者様
返信ありがとうございます
参考にさせていただいて自分なりに簡単ですがサンプルソースを組んでみましたが、
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern void table();
int main(void)
{
int i_i,count=0;
char moji[50];
char *c1;
printf("*** input moji (but 50 made)...\n");
while(1){
gets(moji);
if ( moji[0] == 'e' ) {
break;
}
table(&c1, moji, &count);
}
printf("***** moji list *****\n");
for(i_i=0; i_i<count; i_i++ ) {
printf("%s\n",c1[i_i]);
}
return 0;
}
void table(char **c1, char *moji, int *count)
{
if ( *count == 0 ) {
c1 = (char **)malloc(sizeof(char *));
} else {
c1 = (char **)realloc(c1,sizeof(char *)*((*count)+1));
}
strcpy(c1[*count], moji);
(*count)++;
}
がうまくうごきませんでした。。
2行目の文字を入力しようとすると、coreはきました。。
Re:文字列を配列に
Posted: 2009年5月22日(金) 10:34
by toyo
私なら
char **c1 = NULL;
c1 = table(c1, moji, &count);
char** table(char **c1, char *moji, int *count)
{
c1 = (char **)realloc(c1,sizeof(char *)*((*count)+1));
if (c1)
{
c1[*count] = (char *)malloc(strlen(moji) + 1);
strcpy(c1[*count], moji);
(*count)++;
}
return c1;
}
にしてrallocしたポインタを戻り値として受け取るようにします
Re:文字列を配列に
Posted: 2009年5月22日(金) 11:28
by ウズ
>toyo様
toyo様の提示していただいたソースに入れ替えてみました。
が、coreははかなくなりましたが、
mainにもどってからのprintfでの表示部分が動きませんでした。
変数countがカウントアップされませんでした。
Re:文字列を配列に
Posted: 2009年5月22日(金) 11:31
by non
確認しましたが、toyoさんのプログラムは動きました。
Re:文字列を配列に
Posted: 2009年5月22日(金) 11:55
by ウズ
>toyo様
>non様
返信ありがとうございます。
toyo様申し訳ないです、私のコーディングミスでした。
toyo様のプログラムは問題なく動きました。
non様、ご指摘ありがとうございます。
Re:文字列を配列に
Posted: 2009年5月22日(金) 12:00
by 初級者
動的確保した領域の後始末を含めて…
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN (80)
char **makeTable(char **p, int *n)
{
char s[LEN];
for (p = NULL, *n = 0; printf("文字列 > "), fgets(s, sizeof(s), stdin); (*n)++) {
s[strlen(s)-1] = '\0';
p = (char **) realloc(p, sizeof(char *) * (*n + 1));
if (!p)
return NULL;
p[*n] = (char *) malloc(sizeof(char) * (strlen(s) + 1));
if (!p[*n])
return NULL;
strcpy(p[*n], s);
}
return p;
}
void printTable(char **p, int n)
{
int i;
for (i = 0; i < n; i++)
printf("%s\n", p);
}
void freeTable(char **p, int n)
{
while (--n >= 0)
free(p[n]);
free(p);
}
int main(void)
{
char **p;
int n;
if (!(p = makeTable(p, &n)))
exit(1);
printTable(p, n);
freeTable(p, n);
return 0;
}
Re:文字列を配列に
Posted: 2009年5月22日(金) 14:05
by ウズ
皆様ありがとうございます。
配列のポインタを戻り値としないで、
実現できるようご教授お願いします。
Re:文字列を配列に
Posted: 2009年5月22日(金) 14:37
by toyo
じゃあポインタのポインタのポインタ使って
void table(char ***c1, char *moji, int *count)
{
*c1 = (char **)realloc(*c1,sizeof(char *)*((*count)+1));
if (*c1 == NULL) return;
(*c1)[*count] = (char *)malloc(strlen(moji) + 1);
if ((*c1)[*count] == NULL) return;
strcpy((*c1)[*count], moji);
(*count)++;
}
Re:文字列を配列に
Posted: 2009年5月22日(金) 14:54
by ウズ
>toyo様
完璧です!!すごいです。ちゃんと動きました。
本当にありがとうございます。