• ベストアンサー

変数 および ポインタのサイズ(バイト数)について

sizeof演算子を使ってchar int float double型のバイト数を調べると、char 型については1バイトと決まっていて、int float doubleについては2から8バイト(処理系によって違う)なのは理解できます。しかし、char* int* float* double*型(ポインタ型)のバイト数は2から4バイトになるのが多いとおもいますが、どういう理由でポインタ型のバイト数が決まるのか、その理由をお教え願いたく思います。16ビットcpuあるいは32ビットcpuと言うハードの影響なのかそれとも何かソフトによるのか、その理由を知りたいと思います。なお私の処理系ではポインタは全て4バイトになっています。特に不思議に思うのはchar型は1バイトなのに、char*型が4バイトになっていることです。 宜しく願います。

質問者が選んだベストアンサー

  • ベストアンサー
  • php504
  • ベストアンサー率42% (926/2160)
回答No.3

例えば char a = 1; の場合メモリの特定のアドレスに1という値が保存されます。 アドレスを0x20000000番地とすると 0x20000000 : 01 という具合です。 この場合アドレスは4バイトなのでsizeof(char*)は4になります。 アドレスのサイズはCPUにより決まると考えていいと思います。 スモールモデル(アドレス2バイト)やラージモデル(アドレス4バイト)を切り替えられるCPUもありました。

その他の回答 (4)

noname#123613
noname#123613
回答No.5

こんにちは >私の処理系ではポインタは全て4バイト あなたのパソコンはCPUが32ビットだとわかりました。 つまり、32ビットなので約42億個(2の32乗)のメモリがあつかえます。 約42億個のメモリの一つ一つを4バイトのアドレスで管理しているのです。 ではdoubleはアドレスが8個になってしまうではないか? とまたまた疑問に思われるでしょう。 メモリの管理については 「はじめて読む Pentium マシン語入門編」アスキー出版 http://www.ascii.co.jp/books/books/detail/4-7561-4466-7.shtml を読まれるとよくわかります。 「アセンブラ入門 CASLII」 SCC出版局 http://www.scc-kk.co.jp/scc-books/book_data/6074/6074.html を読めばワード、バイトというメモリの確保の仕方もわかります。 この2冊を勉強してください。 これを読んでおけば、これから必ず出てくる構造体のアライメントの疑問も解決できます。 http://www5d.biglobe.ne.jp/~noocyte/Programming/Alignment.html

  • php504
  • ベストアンサー率42% (926/2160)
回答No.4

メモリモデルを切り替えるのはCPUではなくてコンパイラでした

  • masa6272
  • ベストアンサー率66% (93/140)
回答No.2

ポインタには、メモリ上のアドレスが入っています。 そして、データ本体はそのアドレスのところに格納されます。 ポインタに入っているのは、データ型に関らずデータの入っているアドレスですので、全て同じサイズになります。 32ビットのOSですと、アドレスは4バイトで表されますので、全てのポインタ型のサイズは4バイトになります。

  • SAYKA
  • ベストアンサー率34% (944/2776)
回答No.1

メモリモデルって言うんじゃなかったかな。 メモリを使う時に必要な「番地」を管理するのに必要なバイト数が、ポインタをsizeofで調べると返ってくるよ。

関連するQ&A

  • ポインタのサイズ

    ポインタのサイズは、 int型のポインタでも、char型のポインタでも、 doubleのポインタでも、構造体のポインタでも、 全部サイズは4バイトです。 というのを見かけましたが、ほんとうですか? 教えてください。

  • ポインタ変数のサイズ

     いろいろC言語のことを知りたくて、次のソースを作って動かしてみました。 ★ソース(□はタブ) ◆◆◆◆◆ #include <stdio.h> #include <stdlib.h> int main(void) { □char *s1; □int *s2; □ □s1 = (char *)malloc(1000); □s2 = (int *)malloc(1000); □ □printf("sizeof s1 = %d\n", sizeof s1); □printf("sizeof s2 = %d\n", sizeof s2); □ □printf("sizeof *s1 = %d\n", sizeof *s1); □printf("sizeof *s2 = %d\n", sizeof *s2); □ □printf("s1 = %d\n", s1); □printf("s2 = %d\n", s2); □ □printf("*s1 = %d\n", *s1); □printf("*s2 = %d\n", *s2); □ □return EXIT_SUCCESS; } ◆◆◆◆◆ ★実行結果1 ◆◆◆◆◆ sizeof s1 = 4 sizeof s2 = 4 sizeof *s1 = 1 sizeof *s2 = 4 s1 = 1323000 s2 = 1324008 *s1 = -60 *s2 = 1310916 ◆◆◆◆◆ ★実行結果2 ◆◆◆◆◆ sizeof s1 = 4 sizeof s2 = 4 sizeof *s1 = 1 sizeof *s2 = 4 s1 = 11087864 s2 = 11088872 *s1 = -60 *s2 = 11075780 ◆◆◆◆◆ ★実行結果3 ◆◆◆◆◆ sizeof s1 = 4 sizeof s2 = 4 sizeof *s1 = 1 sizeof *s2 = 4 s1 = 1519608 s2 = 1520616 *s1 = -60 *s2 = 1507524 ◆◆◆◆◆  OSはWindows Vista、コンパイラはMS Visual Studio 2010 コマンドプロンプトです。次の疑問についてご教授頂きたく、お願い致します。 (1)“sizeof s1”、“sizeof s2”の値が共に4となるのはなぜか。  char型へのポインタ、int型へのポインタとして宣言したs1、s2のサイズが同じ4になる理由が、どうしても分かりません。 (動かす前の予想は、でたらめな値になるかと思っていましたが) (2)“s1”、“s2”、“*s2”の値が毎回でたらめな値になったのに対して、“*s1”の値が毎回“-60”になったのはなぜか。  ポインタでつまずいており、いろいろ実験して体で理解したいと思っています。どうぞよしくお願い致します。

  • ポインタに ~0を入れること

    見かけたCのプログラムで、 ポインタに~0を代入するものを見ました。 そのプログラムをそのまま載せるのはわかりにくいので、 代わりに以下のプログラムを作って実行しました。 #include <stdio.h> int main(void) { char *pa[3]; int i; pa[0]=0; pa[1]=~0; pa[2]="Hello"; printf("sizeof(char*)=%d\n", sizeof(char*)); for(i=0; i<=2; i++) { if(pa[i]==NULL) printf("pa[%d] はNULLです。\n", i); if(pa[i]==(char*)0xFFFFFFFF) printf("pa[%d]は全ビット1です。\n", i); if(pa[i]==~0) printf("pa[%d]は~0です。\n", i); } return 0; } 結果 sizeof(char*)=4 pa[0] はNULLです。 pa[1]は全ビット1です。 pa[1]は~0です。 このプログラムはコンパイル時にエラーも警告も出ず、 動作も意図したとおりです。 pa[1]に入っている ~0 は、int型の定数なのでしょうか。 それならば、 pa[1]=~0; という代入や if(pa[i]==~0) という比較は 左辺はchar*型で右辺はconst int型であって型が異なりますが、 問題ないのでしょうか。 ~0は0の否定なので、全ビットは1なのでしょうけど、 int型(の定数)だと思います。 ~0というのは何か特別な値なのでしょうか。 ポインタに~0を入れるというのは、意味があるのでしょうか。 (例えば、「ポインタに0を入れるということは、ヌルポインタであって、ポインタとして無効なんですよ」のようなこと。)

  • ポインタのサイズ

    ポインタのサイズがintと同じになるのは知っているのですが、 以下のコードの場合、 typedef struct hoge{ char buf1[8]; char buf2[16]; }HOGE; void test_func(HOGE *pHoge) { printf("型[%d],実際[%d]\r\n", sizeof(HOGE), sizeof(*pHoge)); memset(pHoge, 0x00, sizeof(*pHoge)); } 正しくサイズが取得できるのですが、 この使い方はC99の仕様的には正しいのでしょうか? よろしくお願いします。

  • ポインタ変数とポインタのポインタ

    ポインタ変数の宣言 char *a[]; をしたとき僕の中では a[0],a[1]...という、ある文字列A,B,C...の最初のアドレスを指すポインタが、配列になっているものを宣言していると理解していました。 しかしこの次に、ポインタのポインタが出てきました。僕はこれを、 ある変数を指し示すアドレスのアドレスである、と理解しました。 この2つは1つめはいくつかのアドレスを指し示すもの、2つ目は1つのアドレスを指し示すものであるとして、僕の中で異なったものであると理解していましたが、参考書「C標準コースウェア」によると プログラムにおいて、関数でポインタ配列を受け取るときchar *p[]はchar **pとしてもよい と書かれており、またその実例として、 (9-5) #include <stdio.h> void disp (char *p[],int n){ int i; for (i= 1;i<n;i++){ printf("%s\n",p[i]); } } int main(void){ char *girl[] = {"Arica","Candy","Lisa"}; disp (girl,sizeof(girl)/sizeof(girl[0])); return 0; } というプログラムが書かれていました。 ここで一気に訳が分からなくなりました。 char *girl[] = {"Arica","Candy","Lisa"}; と宣言されているため、 girl[0]はAricaという文字列の最初のアドレスを指すポインタ、 *girl[0]はAricaという文字列を直接指し示していると解釈しています。 girlは{"Arica","Candy","Lisa"}という文字列の配列の最初のアドレスを指し示していると考えました。 sizeof(girl)を使った時に不思議なのですが、 girlはどのように配列の終わりを理解しているのでしょうか? (配列の要素数を渡していない点が不思議です。) また、 disp側が受け取ったのは*girl[]であり、いくつかのポインタの配列ですが、渡したものはgirlという要素数がないポインタ1つだけです。 そして最初の疑問が出てくるわけですが、*p[]を**pと書きかえてみると、 文字列のアドレスを示すgirlという名の1つのポインタを渡すと、pという名のポインタのポインタで受け取るというのも、よくわからなくなっています。 おそらくポインタ配列に対する理解がどこかでずれているようですが、自分でどこがわからないのかわからなくなっています。 どうかご教授ください。

  • ポインタがわからない

    C言語初心者です。 Int num; Int  *p=&num; という変数を宣言したとします。 下は「int *型」と呼び、pは「int型オブジェクトであるnumを指すポインタ」であることはわかりました。 ですが、「int型」と「int  *型」そのものの違いがわかりません。 たとえば、今読んでいるテキストに Printf(“int 型は%uバイトです。\n”,(unsigned)sizeof(int));→結果は2バイト Printf(“int *型は%uバイトです。\n”,(unsigned)sizeof(int *));→結果は4バイト 僕の環境では両方とも4バイトと結果は変わりませんでしたがテキストでは結果は上記のように変わってきてしまうようでした。これはなぜ変わってくるのでしょうか? 「int型」と「int  *型」そのものを比較した際の違いがわかりません。

  • ポインタ型配列のポインタを構造体のポインタ変数に格納する方法教えて!_ver2

    int型の配列は構造体のポインタ型のint型変数にはキャストすればうまくコンパイルが通りますが、同じ方法でfloat型の配列は構造体のポインタ型のfloat型変数にはキャストしてポインタの値を入れてもうまくコンパイルできず困っています。ちなみにコンパイルエラーは「互換でない型変換」と表示されます。 返答のほど、よろしくお願いいたします。 #include<stdio.h> #include<malloc.h> float time[] ={2.2, 2.3, 2.4}; int time2[] ={2, 2, 2}; struct timelist{ float *time; int *time2; struct timelist *next; }*head; void main(void) { struct timelist *p; p = (struct timelist *)malloc(sizeof(struct timelist)); p -> time = (float *)time[0]; p -> time2 = (int *)time2[0]; printf("time = %f\n", p -> time); printf("time2 = %d\n", p -> time2); }

  • 構造体へのポインタについて

    初心者です。 C入門書の著者のサポートページには正誤表とダウンロードしかないためこちらで質問させていただきます。 下記のコードの下から二行目の構造体へのポインタ (Car *) について、中学生に説明するように基本的な考え方、目的、書式、参考URLなどを教えて下さい。 ポインタについては、該当の章を読み直し基本事項については理解しておりますが、突然あるページから(Void *)や(Char *)など括弧で閉じるものが説明なしに出てきてちょっと混乱してます。(汗 どうぞ宜しくお願い致します。 #include<stdio.h> /* 構造体型struct Carの宣言 */ typedef struct Car{ int num; double gas; }Car; int main(void) { printf("int型のサイズは%dバイトです。¥n", sizeof(int)); printf("double型サイズは%dバイトです。¥n", sizeof(double)); printf("構造体structCar型のサイズは%dバイトです。¥n", sizeof(Car)); printf("構造体struct Car型へのポインタのサイズは%dバイトです。¥n", sizeof(Car *)); return 0; }

  • int型ポインタの加算

    void foo() {   int *ptrInt=0;   char *ptrChar=0;   ptrInt++;   ptrChar++; } Windows2000上で、上記を実行すると ptrIntは4になります。 ptrCharは1になります。 なぜでしょうか。 32ビットとはいえ、 ptrIntとptrCharはアドレスを示しますよね。 アドレスに1加算するのだから、 int型、char型に関係なく、 いずれも1になるべきだと思います。 int型のポインタの場合示すデータは4バイトなので、 ポインタ1加算は、4(バイト)加算になるということでしょうか。

  • 標準Cでのオブジェクト(変数)の定義について

    標準Cのオブジェクト(変数)の定義に「その内容によって、値を表現することができる実行環境中の記憶域の領域。ビットフィールド以外のオブジェクトは、連続する1つ以上のバイトからなる。そのバイトの個数、順序および符号化規則は、明示的に規定するかまたは処理系定義とする。 オブジェクトを参照する場合、オブジェクトは、特定の型をもっていると解釈してもよい。」とありますが、具体的に何を指しているのかが解りません。以下のように疑問点をまとめました。 1、「そのバイトの個数、順序および符号化規則は、明示的に規定するかまたは処理系定義とする。」    Int型 long型 double型等を例に取ると、「処理系定義」はそのバイト数が4バイト8バイトと考えられますが、「明示的に規定する」とは、Int型 long型 double型等で具体的にどのような定義を指しているのでしょうか? 2、「オブジェクトを参照する場合、オブジェクトは、特定の型をもっていると解釈してもよい。」とは、具体的に一体何を言いたいのか解りかねます。「参照」とは何を指しているのか?ポインタを指しているのか、「ポインタを指している」としたならなぜそれをここに書き加える必要があるのか?それとも、もっと一般的な事をいっているのか?もしもっと一般的な事を言っているならそれは何なのか? 宜しく願います。

専門家に質問してみよう