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

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

ただいまの
回答率

91.35%

  • C

    2524questions

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

  • エンベデッドシステムスペシャリスト

    2questions

    エンベデッドシステムスペシャリスト試験 (ES)は、IPA 独立行政法人 情報処理推進機構の実施している国家資格です。

ポインタ変数の型はアドレスが入る容量があれば、なんでもいいのでしょうか?

解決済

回答 6

投稿 2017/11/24 19:01 ・編集 2017/11/24 19:03

  • 評価
  • クリップ 1
  • VIEW 411

ogura87

score 68

C言語について勉強しています。

下記サイトに、このようなポインタを使ったプログラムが紹介されています。

【問題9】配列とポインタの深い関係 (1/4)

int main(void)
{
     int n, data[100], *p;   // ←*pがintで定義されている
     printf("数を入力してください->");
     scanf("%d", &n);
     p = data;
     while (n >= 0) {
         *p = n;
          p++;
         printf("数を入力してください->");
         scanf("%d", &n);
     }
     while (p > data) {
         p--;
     printf("%d\n", *p);
     }
}

この例では、*pがintで定義されていますが、

int main(void)
{
     int n, data[100];
     long *p;   // ←*pをlongに変更
     printf("数を入力してください->");
     scanf("%d", &n);
     p = data;
     while (n >= 0) {
         *p = n;
          p++;
         printf("数を入力してください->");
         scanf("%d", &n);
     }
     while (p > data) {
         p--;
     printf("%d\n", *p);
     }
}

このようにlongにすると、コンパイルでワーニングは出るのですが、動作は全く同じです。
また、shortやcharにしてもやはり同じで、ワーニングは出ますが動作は*pをintにした時と全く同じです。

ポインタ配列はアドレスを格納する変数という事は知っていますが、アドレスが格納できる容量があれば変数の型はなんでもいいのでしょうか?

今度、組み込み系の仕事をする予定なので、このあたりの違いなどを細かく知りたいと考えいます。

有識者の方、どうぞよろしくお願い致しますm(_ _)m

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 6

+8

こんにちは。

う~ん、かなりヤバイです。
ポインタをインクリメントすると、そのアドレス値はポインタが指す型のサイズだけ増えます。
例えば、char* p;の場合は++pでpの値は1増えます。int* p;の時は++pでpの値はsizeof(int)だけ増えます。多くの処理系でsizeof(int)は4ですが、その時は4増えます。また、sizeof(long)は4や8の処理系が多いです。

while (p > data) {
    p--;
    printf("%d\n", *p);
}


の部分を下記のようにしてみれば、*pの型を変えた時の変化を観察できると思います。

int n, data[100]={0};
   (中略)
for(i=0; i < 100; ++i) {
    printf("%d\n", data[i]);
}


なお、longとintが同じサイズの処理系の場合は同じ結果になります。charとintが同じサイズの処理系は非常にレアですのでこの2つで確認すると良いと思います。

ところで組み込み系の場合はsizeof(int)が2のものも普通にありますのでご用心。

投稿 2017/11/24 19:42

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/25 09:50

    Chironian様

    なるほど。
    インクリメントの幅が違いますね。
    ありがとうございました!

    キャンセル

+3

少しだけ補足をさせてください。

*pがintで定義されていますが、 

アドレスが格納できる容量があれば変数の型はなんでもいいのでしょうか? 

ということについてですが,
int *p; という表現は,「ポインタ変数を int 型の大きさで作っている」わけではなく,「int 型の領域を指すポインタ変数を宣言している」のです。どの型の変数もメモリ上にあることに変わりはないので,その場所を示すアドレスの大きさは同じです。つまりポインタ変数の型指定とそのポインタ変数自体の大きさは関係がありません (int * でも long * でも char * でも大きさは同じです) 。

なので,ポインタ変数の容量という観点からは,どの型の変数のアドレスも好きな型のポインタ変数に代入できることにはなります。もちろん警告は出るかもしれませんし,他の方々のおっしゃる通り,インクリメントまわりでも意図しない挙動を起こすでしょう。

投稿 2017/11/25 02:02

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/25 09:19

    EKi様

    あぁ、なるほど!
    そういう事ですか!

    ポインタ型の変数は、どの型でもその後の挙動が違うだけでポインタ変数のメモリ容量は変わらないんですね!

    なるほどぉ。。。

    ありがとうございました!

    キャンセル

checkベストアンサー

+2

T *p;

でT(int, long, etc.)のサイズによりpを介してアクセスしたときのメモリーのアクセス範囲(バイト数)が違う点に注意が必要なのは他の皆さんの回答のとおりと思いますが、それに加えてTによってデータのメモリー上での表現の違いがあることも指摘しておいた方がよいかも知れません。

あるプロセッサー用のコンパイラーでfloatとintがどちらも4バイトだとして、次のようなコードを動かすとそれがわかります。

#include <stdio.h>

int main() {
  float f = 1.0F;
  int   *pi = (int*)&f;
  int   i = *pi;

  printf("0x%8x\n", i); // => 0x3f800000
  return 0;
}


上のようにfloatで1.0だった値をintとしてアクセスすると全く違った値として解釈されてしまいます。このような点からも(特別な意図があってあえてやるのではない限り)違う型のポインターを用いてはならないと考えるべきだと思います。

(組み込み系で浮動小数点数(floatなど)をよく使うものかどうかわかりませんが知識としは必要ではないでしょうか)

投稿 2017/11/24 20:15

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/25 09:24

    KSwordOfHaste様

    なるほど。
    これは、float型のバイト数がint型よりも多いので、表示時にint形のメモリ領域分しか表示されないという事ですね!

    なるほど、よく理解できました。
    ありがとうございました!

    キャンセル

  • 2017/11/25 09:34

    > float型のバイト数がint型よりも多いので
    いえ、違います。回答に書いたようにどちらも4バイトと仮定した場合でもメモリーの中身の解釈が異なるということをいいたかったのです。
    ・・・ちなみに自分の回答は上記の点だけ補足したかっただけのもので、他の方の回答に大事な点が色々書かれてますのでできたらBAを再考していただければと思います。

    キャンセル

  • 2017/11/25 10:00

    KSwordOfHastes様

    あぁ、なるほど!
    変数の方によって、メモリの扱いかたが違うという事ですね!

    ご丁寧にありがとうございました。
    (当たり前ですが)まだまだ未熟者です^-^;

    キャンセル

+2

int *p はint型のポインタの作成です。
https://qiita.com/hatchinee/items/fc838f0809702d6b6a26

shortやcharにしてもやはり同じで

動作は異なっているはずです

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

void clear(int* buf){ memset(buf, 0, 4 * sizeof(int)); }
void dump(int* buf){
  for(int i = 0; i < 4; i++){
    printf("%08X ", buf[i]);
  }
  printf("\n");
}

int main(){
  int buf[4];
  int* p1  = buf;
  long* p2 = buf;
  short* p3= buf;
  char* p4 = buf;

  int* last = buf + 4;

  clear(buf);
  for(int i = 0; p1 < last;)
    *(p1++) = i++;
  dump(buf);

  clear(buf);
  for(int i = 0; p2 < last;)
    *(p2++) = i++;
  dump(buf);

  clear(buf);
  for(int i = 0; p3 < last;)
    *(p3++) = i++;
  dump(buf);

  clear(buf);
  for(int i = 0; p4 < last;)
    *(p4++) = i++;
  dump(buf);
}
00000000 00000001 00000002 00000003
00000000 00000001 00000002 00000003
00010000 00030002 00050004 00070006
03020100 07060504 0B0A0908 0F0E0D0C

投稿 2017/11/24 19:44

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/25 09:49

    ams様

    おお!
    なるほど!

    intやlong型ポインタにintの数を入れると問題ないですが、shortやcharでは桁あふれのようなものを起こして関係ないメモリ了以域の値まで表示されてしまっていますね。

    なるほど!
    よく理解できました。

    ありがとうございました!

    キャンセル

  • 2017/11/25 10:12

    いえ、違います

    shortの場合は上位16bit 下位16bitで分割されて0,1が代入され
    charの場合は8bit毎に分割され0,1,2,3が代入されています

    キャンセル

+2

おっしゃる通り、アドレスだけであれば、特に何でもいいかとは思います。
ポインタがさすメモリの内容を取り出す際に、ちゃんと型があっていれば(キャストが正しければ)問題は起きないかと思います。

ただ、データを取り出す際にいちいち型を気にしなければならなくなるので、面倒です。

例えば、配列の添え字の代わりとしてポインタを使う場合、ポインタと配列の方があっていないとポインタを進めたときにずれが生じてしまいます。

バグの素なので、可能な限り型は合わせたほうが良いでしょう。

また、アドレスだけを保存したいのであれば、通常void型のポインタを使う方が多いかと思います。
void型であれば、第三者がコードを読んだときに、このポインタはキャストしないとだめなんだな。と知らせることができるので、多少わかりやすくなるかと思います。

投稿 2017/11/24 19:47

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/25 09:31

    CodeLab様

    あぁ、void型。
    なるほど、それもテクニックとして使えるんですね。

    勉強になりました。ありがとうございました!

    キャンセル

+1

アドレスが格納できる容量です。
基本的にポインタは、それが指す変数の型に左右されません。

8bit 16bit 32bit 64bit の処理系で異なりますし。64bit でも 32bit でアドレッシングしているコンパイラであれば、必要な容量は 32it です。

ワーニングが出たというのは、ポインタの部分ではなく、int と long の間で代入を行おうとしたからではないですか?

投稿 2017/11/24 19:14

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/25 09:52

    showkit様

    なるほど。
    ポインタ型はのサイズと型のサイズは関係なく、ポインタ型のサイズは処理系で異なるんですね。。。

    ありがとうございました!

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

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

  • C

    2524questions

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

  • エンベデッドシステムスペシャリスト

    2questions

    エンベデッドシステムスペシャリスト試験 (ES)は、IPA 独立行政法人 情報処理推進機構の実施している国家資格です。

  • トップ
  • Cに関する質問
  • ポインタ変数の型はアドレスが入る容量があれば、なんでもいいのでしょうか?