質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.92%

ポインタのバイト数について

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 1,902

michiaki

score 29

前提・実現したいこと

構造体で、char型をポインタで宣言した場合って4byteになるんでしょうか?

発生している問題・エラーメッセージ

特にエラーはなし。

該当のソースコード

struct hoge{
    int a;
    int b;
    int c;
    char *name;
};

struct hoge data;
data.a = 1;
data.b = 1;
data.c = 1;
data.name = "hoge";



printf("%d\n",sizeof(hoge));
printf("%d\n",sizeof(data.name));

試したこと

  • ポインタのサイズが4byteになっている。
  • 下記のプログラムの出力結果が
    16
    4
    となっていました。
  • 構造体の説明では、よく配列で範囲を決めた使い方が紹介されていますが
    ポインタを使うと4byte固定になるなら、こちらの方が簡単だからですか?
    まああらかじめ文字の入力がわかっているなら配列の方がいいのかなと
    も思いますが。

もしかして根本的に間違っているかもしれません。

補足情報(言語/FW/ツール等のバージョンなど)

bcc5.5 c++版

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+2

こんにちは。

ポインタを使うと4byte固定になるなら、こちらの方が簡単だからですか? 
まああらかじめ文字の入力がわかっているなら配列の方がいいのかなと 
も思いますが。

文字数があらかじめ分かっているなら配列の方が良いかも知れません。極端な話最大3文字しか要らないなら、最後のNULL文字を含めて4バイトあれば記録できるので配列を選択するべきでしょう。

しかし、分かっていない場合は、もしかすると、超レアケースで2,000,000文字とか入れることも有るのかも知れないです。するとめったに発生しない時のことを考慮して2MBytesもの配列を確保しておくのはいくらなんでも勿体ないわけです。
そのような時は、ポインタにしておき、必要に応じて適切なサイズのメモリを確保するという使い方が多いです。

このようにどちらが好ましいかはケースバイケースです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/14 20:50

    自分も配列=ポインタなんで、結局扱いやすい配列でいいやと思い、あまり考えずに配列を使用していました。やはり深い部分の違いを考え、使い分ける必要があるのですね。勉強になります。

    キャンセル

checkベストアンサー

+1

それぞれの長さを出力しました。

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

struct hoge{
    int a;
    int b;
    int c;
    char *name;
};

int main(void){

struct hoge data;
data.a = 1;
data.b = 1;
data.c = 1;
data.name = "hoge1";

printf("構造体:   %d\n",sizeof(struct hoge));
printf("int a:    %d\n",sizeof(data.a));
printf("int b:    %d\n",sizeof(data.b));
printf("int c:    %d\n",sizeof(data.c));
printf("ポンタ長: %d\n",sizeof(data.name));
printf("文字列長: %d\n",strlen(data.name));

return 0;
}

#結果
構造体:   24
int a:    4
int b:    4
int c:    4
ポンタ長: 8
文字列長: 5


ポインタは64環境なので8バイトになっています。
文字は分かり易く5文字しています。
構造体は明細の合計と合いませんが、これはメモリ上に変数が取られるときは、
アドレスが、ある決められた区切りに合わせられます。これを「バイト境界」と呼びます。
構造体はこれにより、適当にメンバ間に空間が入れられます。構造体の「アライメント」と言います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/14 20:47

    そんな境界があったのですね。C言語も深いところまで勉強になります。

    キャンセル

  • 2017/05/14 21:02

    私のプログラムで調べていただき、また違う考え方まで教えていただいたので、ベストアンサーにさせていただきます。毎回思うのですが、ベストアンサーをいろんな人につけれるようにしてほしいです。

    キャンセル

+1

ポインタのサイズは4byteです。
これはアドレスの表現が4byteだからです。
そのため、プログラムのメモリ上の位置を記憶しておくのに4byte必要ということになります。
(これは32bitプログラムだからで、64bitプログラムだとポインタは8byteになります。)


構造体の説明で配列が使われない理由…ですか。
たぶん、配列を使った場合値をコピーしなくてはならないから、ではないでしょうか。

構造体の外で生成された文字列の参照を持てばよいだけの場合は、ポインタにすると簡単です。
構造体でも配列を使うことはありますが、配列を確保すればその分だけ構造体は大きくなってしまいます。
そのうえ、文字数には制限も生まれます。

配列は文字列を保持するために、その値をコピーする必要があります。
普通は下記のように初期化時に設定することができますが…

char s[100] = "Hello World!\n";

たしか、構造体内だと初期化では設定できなかった気がしますし
初期化以外ではそもそも下記のように明示的にコピーしなければなりません。

char s[100];
strcpy(s, "Hello World!\n");

指定された配列の長さを超えると構造体のデータが壊れてしまいますし、なかなか取り扱いが難しいのです。

一方、下記のようにあらかじめどこかにあるい文字列の位置を覚えておくだけでよい場合は
ポインタさえ持っていればいいことになります。

const char *s = "Hello World!\n";

なので、大抵構造体の説明ではポインタだけ持っているんだと思いますね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/14 20:56

    C言語の文字は1byteづつの処理になれるので、コピーとかはstrcpyとか使わないとダメなんですね。
    自分もあまりここまで考えていなかったので、勉強になります。

    キャンセル

+1

ポインタ型のサイズはメモリ空間の大きさに依存します。32ビットプログラムならば32ビット、この場合4バイトとなります。64ビットならば当然倍です。定まっていないのは、C言語の文法で定められているわけではないためです。

一番下の質問はよくわかりません。が、「構造体データのやりとりにポインタを経由することが多い」という意味ならば、これは明確な有効性があります。サイズの大きい構造体データを丸ごとコピーする際には「機械語レベルでは」複数の処理が必要となります。データの受け渡しにはCPU内の記憶領域「レジスタ」を用いるわけですが、これの容量に収まらないデータは一度に処理できません(つまり、複数に分けて処理をする必要がある)これに対して、メモリ番地のデータであれば、(この場合は)固定4バイトなので、一回で処理を進めることができます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/14 20:59

    機械語レベルでの違いまで存在するのですね。確かにポインタの方が、配列より使いやすいですね。なるほどポインタのほうがいいと明確にわかりました。

    キャンセル

+1

ポインタのサイズが4byteになっている。

環境によります。
32bit環境では4バイト、64bit環境では8バイトになります。
構造体の中か外かというのは関係ありません。

下記のプログラムの出力結果が 

構造体全体のサイズについては、先日ちょうど良い質問をされている方がいたので紹介しておきます。
https://teratail.com/questions/75460

構造体の説明では、よく配列で範囲を決めた使い方が紹介されていますが

これは言っている意味が良くわかりません。
ポインタ宣言で4バイト確保されるなら、そこに4文字分入れられる、という考え方でしょうか。
それはもちろん可能ですが、コード上アドレス値として扱う変数に文字を入れても、処理が面倒になるだけなので何のメリットもありません。
またそういうトリッキーなことをやると、可読性が悪くなります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/14 20:44

    C言語の構造体の説明で、char型が[200]ぐらいの大きさで宣言していることが多く、違う本でchar型のポインタで入力しているのを見て、これなら何文字でも入るみたいだなと関心しました。

    本を読んでいると、printf関数は、与えられた文字列の先頭のアドレスを返しているだけと書いてあったので、一々適当な値を代入しなくてもいいのかと考えました。

    キャンセル

  • 2017/05/15 08:40

    解決済みですが、気になるコメントがあったので補足しておきます。
    >ポインタで入力しているのを見て、これなら何文字でも入るみたいだなと関心しました。
    ポインタはあくまでもアドレスを指す変数です。
    なので、char型のポインタを宣言しただけで大きな領域が使えるわけではありません。
    char *p;
    p[199] = 1; // これはできない
    通常はmalloc等で動的にメモリを確保し、そのアドレスを割り当てて使います。
    char *p = (char*)malloc(200);
    p[199] = 1; // これはOK
    もしくは[200]などで確保された変数のアドレスを割り当てることで、同じ領域を指す変数として使うことができます。
    char a[200];
    char *pa = a;
    pa[199] = 1; // これはOK。a[199]と同じ意味

    キャンセル

  • 2017/05/15 19:03

    そうですよね。枠を設定しないと、入れる文字の大きさが決まらないですね。
    メモリの動的確保のところがよくわからなったので、勉強になりました。
    しかし、あらかじめ入れたい文字数を想定して、大きめのサイズを確保しないといけないのですね?
    なんか効率が悪い気もします。



    キャンセル

  • 2017/05/15 23:59

    そうですね、C言語は文字列の処理が苦手と言ってもいいでしょう。
    しかし実際のプログラミングで文字列を可変で扱うということはあまりないので、それほど困らなかったりします。
    また予め決まった文字列を定義しておく場合は以下のように書けるので、バイト数も気にする必要はありません。
    char msg[] = "Hello World!"; // これでmsgは13バイト確保される

    キャンセル

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

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る