🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

解決済

4回答

1265閲覧

mallocを利用して配列のサイズを決める

AdultMr.

総合スコア14

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

0グッド

1クリップ

投稿2019/09/24 14:39

書籍を読んでいると、char title[64]などとすると、時には[64]では収まらないときや、[64]では大きすぎて無駄なときもある。
そこで、titleの宣言を以下のようにすれば、タイトルの文字列の領域を必要なだけ割り当てることができる。
このようにサンプルプログラムがありますが、mallocにより*titleが指すポインタからlen+1分のメモリを動的に確保しているのだろうと理解しています。
これによって、len+1分のメモリは確保できているとは思いますが、どのようにしてtitleに本のタイトルを格納するのでしょうか。
data->title = "HarryPotter";
data.len = strlen("HarryPotter");
とメイン文に書けばよいのでしょうか?

typedef struct BookData_tag{ char *title; //本のタイトル int len; //タイトルの長さ }BookData; int main(void){ BookData *data; data->title = malloc(sizeof(char)*(len+1));//lenはタイトルの文字数、+1はナル文字の分

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

あえて少しズレた回答をすると、
基本的にメモリはページサイズ単位(4KBが一般的)で割り当てられます。
C言語の標準ライブラリ内で、これを細切れにして管理しますが
64byte程度を細々と割り当てるのでは無駄を省くという意図とは逆に無駄が発生する事を覚えておくとよいでしょう。


C言語で可変文字列をstructで実現するのにはちょっとした裏技があります。

まず、1文字の配列とし、struct末尾に持っていきます。

c

1typedef struct BookData_tag{ 2 int len; //タイトルの長さ 3 char title[1]; //本のタイトル 4} BookData;

使う時は、意外と簡単です。

c

1char* p = "HarryPotter"; 2int len = strlen(p); 3BookData *ptr = malloc(sizeof(BookData)+len); 4ptr->len = len; 5strcpy(ptr->title, p);

注意点としては、

  • 可変にできるデータは末尾に1つだけ
  • 末尾にデータ置き場があるので、配列(BookData data[100])などはできない
    どうしても、配列がほしければポインタの配列(BookData *data[100])を使う
  • malloc等をせずにローカル変数として扱おうとするとメモリ破壊の原因になる

感じです。

生成関数を作っておくと楽でしょう。

c

1// 不要になったらfreeを忘れずに 2BookData* BookData_Init(const char* title){ 3 if(title == NULL) 4 return NULL; 5 int len = strlen(p); 6 BookData *ptr = malloc(sizeof(BookData) + len); 7 ptr->len = len; 8 strcpy(ptr->title, title); 9 return ptr; 10}

投稿2019/09/24 23:59

asm

総合スコア15149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

strcpy関数またはmemcpy関数を使います。

追記
なお、提示のソースコードでは実行エラーが置きます。ポインタ変数dataが有効な先を示しておりません。data->titleの先を割り当てる前に、dataの先を用意する必要があります。

投稿2019/09/24 14:41

編集2019/09/24 14:45
HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AdultMr.

2019/09/24 15:17

ご回答いただきありがとうございます。 ご指摘いただいた通り、このままでは実行エラーが起きました。 下記の通りコードを修正したところ、コンパイルは通り、HarryPotterと表示されるようになりました。 そこで、2点質問させていただけないでしょうか。 1.memcpyを使ってコードを書き直して見ましたが、間違った使い方をしていますでしょうか。 2.構造体をポインタ変数dataで受けた場合に、有効な先とはどのように用意すればよいのでしょうか…。今回の修正コードでは、ポインタ変数の使い方が分からず、*data→dataに変更をしております。 typedef struct BookData_tag{ char *title; //本のタイトル int len; //タイトルの長さ }BookData; int main(void){ char *mozi = "HarryPotter"; BookData data; data.len = strlen(mozi); data.title = malloc(sizeof(char) * (data.len+1)); memcpy(data.title, mozi, data.len+1 ); printf("%s\n",data.title); return 0; }
yumetodo

2019/09/24 16:20

> char *mozi = "HarryPotter"; 重箱の隅をつつくようですがconstがないです。 const char *mozi = "HarryPotter"; あとは合ってます
asm

2019/09/24 23:55

C言語では合法だったはず
yumetodo

2019/09/25 01:58

Cでもどのみち文字列リテラルのある領域への書き換えは許されていないので、ならconstつけておくべき。
HogeAnimalLover

2019/09/25 10:37

(1について)はい。あっています。まあ文字列についてならstrcpy使うほうが多いです。(2について)「BookData bookdata; BookData* data = &bookdata;」とするか、「BookData* data = (BookData*)malloc(sizeof(BookData) );」とします。
guest

0

文字列の長さが 64 で構わないなら構造体の中に大きさ 64 の文字配列を設けても構わないが、実際は文字列の長さはいろいろですからね。固定長の配列にとらわれない方が良いと思います。

構造体のメンバを char *title; というポインタ変数にするなら、malloc() は必要無いと思う。次のように構造体変数 data を初期化できるからです。

C

1int main(void) 2{ 3 BookData data = { 4 "HarryPotter", sizeof("HarryPotter") 5 }; 6 7 printf("title = %s, length = %d\n", 8 data.title, data.len);

実行結果は

title = HarryPotter, len = 12

気になる点が無いわけではないが。。。

投稿2019/09/25 03:31

rubato6809

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/09/25 03:44

これって,構造体を使う利点は何なのだろう?
Zuishin

2019/10/16 08:55

質問者の意図とは違うようですね。
rubato6809

2019/10/16 08:58

そりゃあ違っちゃう場合もありますよ。
Zuishin

2019/10/16 08:58

違った場合は低評価していいんでしょう?
rubato6809

2019/10/16 09:00

あなたの判断次第です。私も私の判断で低評価をつけたので。
guest

0

mallocにより*titleが指すポインタからlen+1分のメモリを動的に確保しているのだろうと理解しています。

data->title = malloc(sizeof(char)*(len+1));

若干違っていると思います.
「mallocによりlen+1分のメモリを動的に確保して, 返されるポインタを*titleに入れている」
です.
この後は, 例えば len=11 でしたら char title[12]; と同様に title を利用できます.

投稿2019/09/24 15:48

jimbe

総合スコア13201

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問