文字列を配列に

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ウズ

文字列を配列に

#1

投稿記事 by ウズ » 16年前

お世話になります。

タイトルどおりですが、

何個あるかわからない文字列("ABC"、"DEFG"、・・・などなど)を

配列に持ちたいのですが、

どうやったらいいのか、さっぱりわかりません。

どなたか教えてください。


何個あるかわからない文字列、とは、

実際は別関数でとってくる文字列があって、それを配列にセットしていきたいのです。

説明足らずで申し訳ないですが、宜しくお願いします。

non

Re:文字列を配列に

#2

投稿記事 by non » 16年前

環境がわかりませんので、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です。

Blue

Re:文字列を配列に

#3

投稿記事 by Blue » 16年前

C言語でstd::vector<std::string>みたいなのをやりたいってことでは?

reallocする対象がchar**になるわけで。
http://homepage1.nifty.com/MADIA/vc/vc_ ... 20032.html
が参考になるかも。



ちなみに、開発環境は必ず明記しましょう。(コンパイラ等)

ウズ

Re:文字列を配列に

#4

投稿記事 by ウズ » 16年前

>non様
>Blue様
返答ありがとうございます。
開発環境はCでコンパイラはGCCです。バージョンは3.2.2です。

領域を増やす場合、よく定数で増やしたり、倍に増やしたりとしていますが、
それは何故なんでしょう??(とんちんかんなことを聞いているのかもしれませんがすみません)
strlen()で文字列の長さはわかるのに??と思ってしまいます。。

non

Re:文字列を配列に

#5

投稿記事 by non » 16年前

strlenで長さがわかるなら、(既に別の配列に格納されているのなら)何も、reallocしなくても
いっぺんにcallocかmallocでかまいませんよ。
これは、少しずつ文字数が増えるような場合の手段です。
例えば、この掲示板に書き込むときコメントを入力する欄がありますが、この欄のために何文字分の
配列を用意しますか?1行入力するたびに、次の1行分の領域を広げると無駄がないと思いませんか?

non

Re:文字列を配列に

#6

投稿記事 by non » 16年前

上に添付したプログラム間違いがありました。
reallocは再確保した領域のバイト数をsizeで指定しなくてはいけませんでしたね。
str=(char *)realloc(str,6+sizeof(char)*5*(n/5));
のようにすればいいでしょうか。

YuO

Re:文字列を配列に

#7

投稿記事 by YuO » 16年前

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:文字列を配列に

#8

投稿記事 by ウズ » 16年前

皆様稚拙な質問に答えていただいてありがとうございます。


①文字列”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なるものがまた必要?とかいろいろぐるぐるしてしまって。。

toyo

Re:文字列を配列に

#9

投稿記事 by toyo » 16年前

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:文字列を配列に

#10

投稿記事 by 初級者 » 16年前

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:文字列を配列に

#11

投稿記事 by ウズ » 16年前

>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はきました。。

toyo

Re:文字列を配列に

#12

投稿記事 by toyo » 16年前

私なら
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:文字列を配列に

#13

投稿記事 by ウズ » 16年前

>toyo様
toyo様の提示していただいたソースに入れ替えてみました。
が、coreははかなくなりましたが、
mainにもどってからのprintfでの表示部分が動きませんでした。
変数countがカウントアップされませんでした。

non

Re:文字列を配列に

#14

投稿記事 by non » 16年前

確認しましたが、toyoさんのプログラムは動きました。

ウズ

Re:文字列を配列に

#15

投稿記事 by ウズ » 16年前

>toyo様
>non様
返信ありがとうございます。
toyo様申し訳ないです、私のコーディングミスでした。
toyo様のプログラムは問題なく動きました。
non様、ご指摘ありがとうございます。

初級者

Re:文字列を配列に

#16

投稿記事 by 初級者 » 16年前

動的確保した領域の後始末を含めて…


#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:文字列を配列に

#17

投稿記事 by ウズ » 16年前

皆様ありがとうございます。

配列のポインタを戻り値としないで、
実現できるようご教授お願いします。

toyo

Re:文字列を配列に

#18

投稿記事 by toyo » 16年前

じゃあポインタのポインタのポインタ使って
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:文字列を配列に

#19

投稿記事 by ウズ » 16年前

>toyo様
完璧です!!すごいです。ちゃんと動きました。
本当にありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る