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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

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

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

Q&A

解決済

6回答

9222閲覧

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

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

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

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

0グッド

2クリップ

投稿2017/11/24 10:01

編集2017/11/24 10:03

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

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

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

C

1int main(void) 2{ 3 int n, data[100], *p; // ←*pがintで定義されている 4 printf("数を入力してください->"); 5 scanf("%d", &n); 6 p = data; 7 while (n >= 0) { 8 *p = n; 9 p++; 10 printf("数を入力してください->"); 11 scanf("%d", &n); 12 } 13 while (p > data) { 14 p--; 15 printf("%d\n", *p); 16 } 17}

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

C

1int main(void) 2{ 3 int n, data[100]; 4 long *p; // ←*pをlongに変更 5 printf("数を入力してください->"); 6 scanf("%d", &n); 7 p = data; 8 while (n >= 0) { 9 *p = n; 10 p++; 11 printf("数を入力してください->"); 12 scanf("%d", &n); 13 } 14 while (p > data) { 15 p--; 16 printf("%d\n", *p); 17 } 18}

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

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

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

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

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

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

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

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

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

guest

回答6

0

こんにちは。

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

C

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

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

C

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

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

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

投稿2017/11/24 10:42

Chironian

総合スコア23272

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

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

退会済みユーザー

退会済みユーザー

2017/11/25 00:50

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

0

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

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

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

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

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

投稿2017/11/24 17:02

Eki

総合スコア429

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

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

退会済みユーザー

退会済みユーザー

2017/11/25 00:19

EKi様 あぁ、なるほど! そういう事ですか! ポインタ型の変数は、どの型でもその後の挙動が違うだけでポインタ変数のメモリ容量は変わらないんですね! なるほどぉ。。。 ありがとうございました!
guest

0

ベストアンサー

T *p;

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

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

C

1#include <stdio.h> 2 3int main() { 4 float f = 1.0F; 5 int *pi = (int*)&f; 6 int i = *pi; 7 8 printf("0x%8x\n", i); // => 0x3f800000 9 return 0; 10}

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

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

投稿2017/11/24 11:15

KSwordOfHaste

総合スコア18394

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

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

退会済みユーザー

退会済みユーザー

2017/11/25 00:24

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

2017/11/25 00:34

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

退会済みユーザー

2017/11/25 01:00

KSwordOfHastes様 あぁ、なるほど! 変数の方によって、メモリの扱いかたが違うという事ですね! ご丁寧にありがとうございました。 (当たり前ですが)まだまだ未熟者です^-^;
guest

0

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

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

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

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

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

投稿2017/11/24 10:47

CodeLab

総合スコア1939

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

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

退会済みユーザー

退会済みユーザー

2017/11/25 00:31

CodeLab様 あぁ、void型。 なるほど、それもテクニックとして使えるんですね。 勉強になりました。ありがとうございました!
guest

0

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

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

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

c

1#include<stdio.h> 2#include<stdlib.h> 3#include<string.h> 4 5void clear(int* buf){ memset(buf, 0, 4 * sizeof(int)); } 6void dump(int* buf){ 7 for(int i = 0; i < 4; i++){ 8 printf("%08X ", buf[i]); 9 } 10 printf("\n"); 11} 12 13int main(){ 14 int buf[4]; 15 int* p1 = buf; 16 long* p2 = buf; 17 short* p3= buf; 18 char* p4 = buf; 19 20 int* last = buf + 4; 21 22 clear(buf); 23 for(int i = 0; p1 < last;) 24 *(p1++) = i++; 25 dump(buf); 26 27 clear(buf); 28 for(int i = 0; p2 < last;) 29 *(p2++) = i++; 30 dump(buf); 31 32 clear(buf); 33 for(int i = 0; p3 < last;) 34 *(p3++) = i++; 35 dump(buf); 36 37 clear(buf); 38 for(int i = 0; p4 < last;) 39 *(p4++) = i++; 40 dump(buf); 41} 42
00000000 00000001 00000002 00000003 00000000 00000001 00000002 00000003 00010000 00030002 00050004 00070006 03020100 07060504 0B0A0908 0F0E0D0C

投稿2017/11/24 10:44

asm

総合スコア15147

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

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

退会済みユーザー

退会済みユーザー

2017/11/25 00:49

ams様 おお! なるほど! intやlong型ポインタにintの数を入れると問題ないですが、shortやcharでは桁あふれのようなものを起こして関係ないメモリ了以域の値まで表示されてしまっていますね。 なるほど! よく理解できました。 ありがとうございました!
asm

2017/11/25 01:12

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

0

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

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

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

投稿2017/11/24 10:14

showkit

総合スコア1638

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

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

退会済みユーザー

退会済みユーザー

2017/11/25 00:52

showkit様 なるほど。 ポインタ型はのサイズと型のサイズは関係なく、ポインタ型のサイズは処理系で異なるんですね。。。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問