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

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

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

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

Q&A

解決済

3回答

780閲覧

C言語のエラーの不可思議な動作について教えて下さい

babbleman

総合スコア107

C

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

0グッド

0クリップ

投稿2020/05/05 02:51

c

1#include <stdio.h> 2#include <stdlib.h> 3 4int main(void) 5{ 6 int n=5; 7 int *p; 8 p=malloc(sizeof(int)*n); 9 printf("%d\n",p[1]); //←ここのp[1]では大きな値が表示される 10 for(int i=0;i<10;i++){ 11 printf("%d\n",p[i]); //←ここのp[1]では0と表示される 12 } 13 printf("%d\n",sizeof(p)); //ここではなぜか8と表示される 14 15

上記のコードを実行したところ、上のコメントアウトでも示しましたように
一回目のp[1]では-63789980のような大きな値が表示されておりますが
for文の中でp[1]を取得すると0となっています。
ちなみにループで回った10回文、全て0となっていました。
そして、sizeofでpの確保領域の8となっておりました。領域の長さを5で指定したはずですが、int型の場合は1領域に1.6メモリ使う、と言うようなイメージでしょうか?

自分の認識ですと、pには確保されたメモリ領域の先頭が16進数でhaitteori,p[1]などすると指定されたpにプラス1された値が表示されるのかなと思いました。
なので一回目に大きな値が表示されるのはわかるのですが、for文で中身が全て0になると言うことがわからないです。

ポインターに使う添字演算子の基本がわかっていないと思います。
よろしくお願いもうしあげます。

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

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

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

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

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

cateye

2020/05/05 03:10 編集

int n=5;といいながら、for(int i=0;i<10;i++)で10回回しているのは何故でしょう? pの領域はintで5個(0から4まで)しか有効ではありません。・・・実際はもっと大きいでしょうが(処理系依存)・・・
babbleman

2020/05/05 03:08

メモリの領域を確保しているものだと言うことだったので、動作上でどのようになっているかを確認するためにこのように書きました。
thkana

2020/05/05 04:07

> 一回目のp[1]では-63789980のような大きな値が表示されておりますが > for文の中でp[1]を取得すると0となっています。 私の手元ではそのような症状が出ません。システム、コンパイラは何をお使いでしょうか。実行画面のスクリーンショットなど、出力結果の「生のデータ」をとれますか? なお、cateyeさん指摘の「確保していないエリアへのアクセス」は未定義動作つまり「何が起こっても文句は言えない」ものです(お暇でしたら'未定義 鼻から悪魔'あたりで検索してみたらいろいろ書かれているかと思います)。その辺は覚悟の上操作を行って下さい。
dodox86

2020/05/05 04:27

> printf("%d\n",p[1]); //←ここのp[1]では大きな値が表示される > for(int i=0;i<10;i++){ > printf("%d\n",p[i]); //←ここのp[1]では0と表示される 普通であれば考えられないです。考えられるとすれば、p[1]で大きな値を出力した後、p[2]以降の出力で何らかのエスケープシーケンスに相当するゴミ文字を出力してしまい、上の行に行ってしまってp[1]の出力内容を上書きしてしまうとか。画面に出力した内容を質問文中に追記してください。ただ、何回かやっているうちに起きなくなってしまうかもしれません。
dodox86

2020/05/05 04:31 編集

> p[2]以降の出力で何らかのエスケープシーケンスに相当するゴミ文字を出力してしまい まぁこれも、printf("%c\n", a[x])ではないから考えづらいのですけど。
cateye

2020/05/05 06:10

今気が付いたのですが、“printf("%d\n",p[1]); //←ここのp[1]では大きな値が表示される”の//の前に全角空白が有りますが?・・・ソースそのままですか?
guest

回答3

0

p=malloc(sizeof(int)*n);

mallocでは、中身の初期化までは行いません。
そのまま読み出せば、そのときにたまたま入ってた内容になります

printf("%d\n",sizeof(p)); //ここではなぜか8と表示される

pはポインタなので、ポインタのサイズとなります
確保しているメモリ領域の量をみるすべはありません

投稿2020/05/05 02:54

編集2020/05/05 02:57
y_waiwai

総合スコア87800

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

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

babbleman

2020/05/05 03:02

回答ありがとうございます。 すみません、ポインターのサイズと言いますと、ポインターの先頭のアドレスのビット数のようなイメージでしょうか?
y_waiwai

2020/05/05 03:07

ポインタ変数のサイズ、です。 ポインタ変数というのは、アドレスを格納する変数です int変数はintを格納しますが、ポインタはアドレスを格納しますね
babbleman

2020/05/05 03:07

なるほどです。ありがとうございます。
babbleman

2020/05/05 03:43

その時にたまたま入っていたと言うことですが、一回目にプリントした時と二回目にプリントした時とではやはり結果が変わってしまうように見えます。 0が入っているように思われます。 何がいけないのでしょうか?
y_waiwai

2020/05/05 04:18

それはちょっとわかりませんね 全部0というのも実際にはありえないような気もします (まあ、あっても文句は言えないですが)
babbleman

2020/05/05 05:16

一応確認ですけれど、p[1]は添字演算子を使っているので、アドレスではなくて値を参照しているという認識であっておりますか?
y_waiwai

2020/05/05 05:26

そうです。 *(p+1) と同じ動作です C言語では、配列名とポインタは相互に読み替えることができるとなってますんで、ポインタを持ってきて配列のように書くことが可能です ましかし、同じように扱えるってだけで別モンです char uni[16];があるとすると、 sizeof(uni) は、16になりますね
guest

0

ベストアンサー

printf("%d\n",sizeof(p)); //ここではなぜか8と表示される

他の方がご回答されているようにポインタ宣言された変数の大きさ(バイト数)です。
蛇足かもしれませんが、
8と表示されたという事は64bit用のコンパイラを使用していると思います。
64bitのアドレスを示す値を格納する変数なので8バイトが必要になります。
アドレスとはメモリ上の位置を示す値でこの場合、0000000000000000~FFFFFFFFFFFFFFFF の値です。
(実際には全てを使えませんし、勝手に割り当てはできません)
ポインタ変数はアドレスを保持するもので、当然その値を記憶しておくメモリ領域が割り当てられています。
このコンパイラが処理するポインタ変数は8バイトのメモリ領域が割り当てられているという事です。
このプログラムでのpは、mallocで確保したメモリ領域のアドレスを保持するメモリ領域で、
mallocで確保したメモリ領域とは別もので(場所も違います)。

自分の認識ですと、pには確保されたメモリ領域の先頭が16進数でhaitteori,p[1]などすると指定されたpにプラス1された値が表示されるのかなと思いました。

従って上記の解釈も少し違うかもしれません。
「pには確保されたメモリ領域の先頭」のアドレス(の値)が入っているまでは良いのですが、
「pにプラス1された値が表示」ではなく、pの示す先頭アドレスから2つ目の「int」の値を参照する
という事です。

また、下記について

そして、sizeofでpの確保領域の8となっておりました。領域の長さを5で指定したはずですが、int型の場合は1領域に1.6メモリ使う、と言うようなイメージでしょうか?

この処理系の場合、int型のサイズは32bit(0~FFFFFFFF)と思います。サイズは4バイト必要です。
「sizeof(int)*5」としていますので、int型を5個分、4(バイト)×5=20バイトの領域を確保しています。

for(int i=0;i<10;i++){

printf("%d\n",p[i]); //←ここのp[1]では0と表示される

}

上記では確保した領域以外の場所にアクセスしている事になります。本来なら問題が発生します。
(今回は参照しているだけなのでたまたま問題にならなかっただけ。そもそも値が設定されていないので全て無意味な値です)

p[0]は、pが示すアドレスの先頭(0番目)のintの値を参照し、p[1]はその次(1番目)intの値を
参照します。pが示す先頭アドレスから4バイトプラスされた位置にあります。
(p+4ではありません。pが示すアドレスの値+4という事です。)

sizeofで返される値は処理系やコンパイルオプションによっても変わるので注意が必要です。

もう一つ気になった事があります。

メモリ領域の先頭が16進数でhaitteori(入っており?)

16進数はあくまで値を表現する方法で、値が16進数で入ってのでは無いと思います。
今回のポインタの場合は、64bitのサイズのアドレスの値で、
16進数で表すと 0000000000000000~FFFFFFFFFFFFFFFFで表現されるという事です。

なので一回目に大きな値が表示されるのはわかるのですが、

上記も少し違い、たまたま入っていた値でメモリ領域の先頭のアドレス値でもありません。

投稿2020/05/13 02:30

編集2020/05/13 02:52
kazuhi

総合スコア15

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

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

0

printf("%d\n",sizeof(p)); //ここではなぜか8と表示される

これはポインタ自体のサイズです。pに取った領域のサイズとは無関係です。

投稿2020/05/05 02:57

maisumakun

総合スコア145208

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問