文字列の動的確保の追加

解決


origi  2005-02-11 07:43:54  No: 56365

WIndowsXP Visual C++ .NET です。

いま、外部のデータによって文字列を動的に確保しているのですが、
確保した後に確保ってできるのでしょうか?それとも一回全て消してから
もう一度確保しなければいけないのでしょうか?

realloc() を使って再割り当てしようとしたのですが、使い方がいまいち分かりません。また、newを使う場合どうすればいいのですか?
よろしくお願いします。

{
char** text;
char* str1 = "追加文字列";
int i;

text = (char**) malloc(sizeof(char**) * DataSize);

for(i=0;i<DataSize; i++)
{
  text[i] = (char*)malloc(sizeof(char*) * strlen(Str[i]));
}

//ここでText[4] を確保して str1 をいれる


Ban  2005-02-11 18:40:01  No: 56366

C++ であれば、標準ライブラリのstd::vector, std::string を
お勧めします。(用法によっては vector を list 等に変えることも検討)

std::string str = "文字列";
str = "新しい文字列";   // メモリは勝手に管理して変更してくれる

std::vector<std::string> text;

string を使えば、文字列の長さ管理が簡単。
vector を使えば、配列の長さ管理が簡単。
文字列の配列を string の vector で表現すると楽なので、後は

// あらかじめサイズを変更しておいて文字列を設定
text.resize(DadaSize);
for(int n=0; n < DataSize; ++n)  text[n] = "追加文字列";

とか、

// 必要なら text.reserve(DataSize);等もできるが、
// 特にサイズを指定しておかなくてもどんどん末尾に文字列を追加できる
for(int i=0; i < DataSize; ++n)    text.push_back("追加文字列");

とかで、あらかじめ Text[4]ちを用意しなくても簡単に文字列追加できます。
自分で malloc/free や new/delete の必要もありません。


K.  2005-02-11 20:22:34  No: 56367

realloc()を使うのであれば、
text[i] = (char*)realloc(text[i],(確保したいサイズ));
でできます。
使い終わったら解放するのをお忘れなく。


monkey  2005-02-11 20:31:52  No: 56368

> C++ であれば、標準ライブラリのstd::vector, std::string を
> お勧めします。(用法によっては vector を list 等に変えることも検討)

同感です。

"new"にも触れられているのでC++だとは思いますが、もし、Cでなくてはいけ
ないのであれば、reallocでメモリを再割当てすることになります。

> realloc() を使って再割り当てしようとしたのですが、
> 使い方がいまいち分かりません。

「いまいち分かりません」と言われちゃうと、どこまでが分かって何が分か
らないのかが曖昧で、どうお答えすれば良いか分からないのですが、とりあ
えずサンプルを書きましたので参考にしてください(メモリ確保に失敗した
ときのエラー処理は省いています)。

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define CAPACITY  16
#define BUFFSIZE 256

int main( void )
{
    size_t size;
    size_t capacity = CAPACITY;
    char** text = (char**)malloc( sizeof(char*) * capacity );

    size_t i;
    char buff[BUFFSIZE];
    for( size = 0; fgets( buff, BUFFSIZE, stdin ) != NULL; size++ ){
        if( capacity <= size ){
            capacity *= 2; // 領域を倍に広げる
            text = (char**)realloc( text, sizeof(char*) * capacity );
        }
        text[size] = (char*)malloc( sizeof(char) * ( strlen( buff ) + 1 ) );
        strcpy( text[size], buff );
    }

    for( i = 0; i < size; i++ ){
        printf( "%s", text[i] );
    }

    for( i = 0; i < size; i++ ){
        free( text[i] );
    }
    free( text );

    return 0;
}


origi  2005-02-12 21:54:25  No: 56369

みなさん、ありがとうございます。
vector と realloc() 両方でできました。
ありがとうございました。


Ban  2005-02-13 04:31:45  No: 56370

解決されてますが一応細かい注意点を一点。

>      text = (char**)realloc( text, sizeof(char*) * capacity );

realloc は再確保に失敗すると NULL を返すので、
直接 text に代入すると以前のアドレスを失ってしまいます。
実際に使う際には、一時変数にとって NULL チェックをしてから
text を更新することをお勧めします。


Ban  2005-02-13 04:34:57  No: 56371

# monkey さんが省略された部分の補足です。個人的には、
# この説明を端折ると、普通独力では気づけない気がしてます。


origi  2005-02-13 08:29:34  No: 56372

Banさん、どうも補足ありがとうございます  |(__)|
あと、c++ でなんですが、 new を使う場合 vector の push_back("")
と同じことをするにはどうすればいいですか?realloc()をつかうしかないですか?


Ban  2005-02-13 10:57:25  No: 56373

> 同じことをするにはどうすればいいですか?

「new [] / delete[] のやり直し」でしょうか。
必要がなければ泥臭いメモリ管理をしなくていいように便利な
STL(標準ライブラリ) が存在しますので、よほどのことがない限り
そちらの使用をお勧めします。

> realloc()をつかうしかないですか?

new で確保したメモリは realloc するべきではないと思います。
コンストラクタ/デストラクタの呼び出しが行われませんし、
そもそも new <-> malloc で確保されるメモリの管理は、
(実装上同じことはあっても)規格上必ず同一である保証は
なかったかと思います。


monkey  2005-02-13 17:54:36  No: 56374

> 実際に使う際には、一時変数にとって NULL チェックをしてから
> text を更新することをお勧めします。
> # この説明を端折ると、普通独力では気づけない気がしてます。

フォローありがとうございました >Banさん
たしかに、この説明を省略するのは不親切、不適当でした。
サンプルを次のように改めます。

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define CAPACITY  16
#define BUFFSIZE 256

int main( void )
{
    char** text;
    size_t size;
    size_t capacity = CAPACITY;

    char buff[BUFFSIZE];
    size_t i;

    if( ( text = (char**)malloc( sizeof(char*) * capacity ) ) == NULL ){
        fprintf( stderr, "memory allocation failure, malloc\n" );
        return 1;
    }

    for( size = 0; fgets( buff, BUFFSIZE, stdin ) != NULL; size++ ){
        if( capacity <= size ){
            char** temp;
            capacity *= 2; // 領域を倍に広げる
            temp = (char**)realloc( text, sizeof(char*) * capacity );
            if( temp == NULL ){
                fprintf( stderr, "memory allocation failure, realloc\n" );
                break;
            }
            text = temp;
        }
        text[size] = (char*)malloc( sizeof(char) * ( strlen( buff ) + 1 ) );
        strcpy( text[size], buff );
    }

    for( i = 0; i < size; i++ ){
        printf( "%s", text[i] );
    }

    for( i = 0; i < size; i++ ){
        free( text[i] );
    }
    free( text );

    return 0;
}

> あと、c++ でなんですが、 new を使う場合 vector の push_back("")
> と同じことをするにはどうすればいいですか?realloc()をつかうしか
> ないですか?

新たな領域をnew[]で確保し、それまでに格納されたデータを新たな領域にコ
ピーし、古い領域をdelete[]で削除することになるでしょう。
しかし、上のサンプルのような処理ならば、Banさんがおっしゃるように、標
準ライブラリのstring, vectorを使うのが普通であり、そうすべきです。

#include <string>
#include <vector>
#include <iostream>

int main()
{
    std::vector< std::string > text;

    for( std::string line; std::getline( std::cin, line ); ){
        text.push_back( line );
    }

    for( size_t i = 0; i < text.size(); ++i ){
        std::cout << text[i] << std::endl;
    }
}


origi  2005-02-13 20:29:27  No: 56375

サンプルの直しまで・・
これでわかりました。
Banさん、Monkeyさん、ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加