配列の先頭要素を指すポインタ自体のアドレスについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sys
記事: 27
登録日時: 14年前

配列の先頭要素を指すポインタ自体のアドレスについて

#1

投稿記事 by sys » 14年前

配列の宣言で生成される、配列の先頭要素を指すポインタ自体のアドレスについての質問です。(環境 Xcode 3.2.5 64bit)

char array[3] = "ab"; と宣言したとき、
[C99 6.3.2.1]から式中の array は配列の先頭要素を指すポインタ(points to the initial element of the array object)となりますが、
このポインタ自体はメモリ上に確保されるのか、と疑問に思い調べていたのですがわかりません。

検索で探してみたら、
char a[5];」の宣言では、配列要素のchar型5個分のメモリ(5バイト)が実際に確保されます。そして、配列名aは、配列の先頭アドレスを示すアドレス定数となります。アドレス定数は、値が定数であるポインタと考えられます。なお、aは定数であるため、a自体を格納するメモリ領域は存在せず、aの値を変更するような操作(a++とかaへの代入など)はできません。つまり、配列の宣言とは、「配列要素分のメモリ確保を伴う定数のポインタの宣言である」と言えます。[http://journal.mycom.co.jp/articles/200 ... /index.htm から一部引用]
と載っていて、なるほどと思う内容だったのですが、アドレス定数の定義とは反していると思いました。

C99 6.6 Constant expressions 9段落 address constant には

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator;

となっており、array は、
address constant is a null pointer
pointer to an lvalue designating an object of static storage duration
pointer to a function designator
のいずれでもないですよね?

ただその後に、
implicitly by the use of an expression of array or function type.
から、「アドレス定数は配列型の使用によって暗黙に生成される。」とも読めるのですが
pointer to an lvalue designating an object of static storage duration の
of static storage duration と書いてあることで意味がわからなくなります。
array は静的記憶域期間のオブジェクトを指し示す左辺値ではないですよね?

配列に対する単項&演算子の例外[C99 6.3.2.1]がなければ、単項&演算子を使い &array で確認出来ると思うのですが、、、。
それとも処理系依存の定義なのでしょうか?
もしそうなら、それが定義されている項目が知りたいです。

正直知らなくて困らないことだとは思うのですが、はっきりポインタと書かれているので
興味本位で知りたくなりました。
ご存知の方いらっしゃいましたらご教示下さい。
よろしくお願いします。

box
記事: 2002
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#2

投稿記事 by box » 14年前

発言内容に誤りを含んでいましたので、削除しました。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#3

投稿記事 by ISLe » 14年前

ポインタという言葉は、
  • メモリ領域の特定の場所を指すアドレス値
  • アドレス値を格納する変数
のどちらにも使われるので文脈で区別するようにしましょう。

かずま

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#4

投稿記事 by かずま » 14年前

sys さんが書きました:となっており、array は、
address constant is a null pointer
pointer to an lvalue designating an object of static storage duration
pointer to a function designator
のいずれでもないですよね?
array がどこで宣言されているかによります。

コード:

char array1[3] = "ab";

void func(void)
{
    char array2[3] = "ab";
    printf("%p\n", array1);
         // array1 は、暗黙のうちにポインタとなり、アドレス定数
    printf("%p\n", &array1[0]); 
        // &array1[0] は、単項&演算子によりポインタとなるから、アドレス定数
    if (func == &func) puts("OK");
        // func は、関数指示子であるが、暗黙のうちにポインタになり、アドレス定数
        // %func は、単項&演算子により関数指示子へのポインタとなるからアドレス定数
}
この場合、array1 は、
宣言において、static storage duration のオブジェクトを指し示す左辺値であり
式の中で使用されると暗黙のうちに array1[0] へのポインタとなりますから、
アドレス定数です。
array2 は、automatic storage duraion のオブジェクトを指し示す左辺値であり
式の中で使用されると暗黙のうちに array2[0] へのポインタとなりますが、
アドレス定数では ありません。array2[0] が static storage duration ではないから。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#5

投稿記事 by sys » 14年前

ISLeさん、ご回答ありがとうございます。

では、「配列の宣言で生成される、配列の先頭要素を指すポインタ」はどちらのポインタになりますか?
ISLe さんが書きました: メモリ領域の特定の場所を指すアドレス値
というのは、「メモリ領域に確保されない」メモリ領域の特定の場所を指すアドレス値
ということでしょうか?
これはISO_IEC9899に定義されていますか?処理系依存でしょうか?

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#6

投稿記事 by YuO » 14年前

ちょっと現在規格書を参照できない環境なのですが……。
sys さんが書きました:
ISLe さんが書きました: メモリ領域の特定の場所を指すアドレス値
というのは、「メモリ領域に確保されない」メモリ領域の特定の場所を指すアドレス値
ということでしょうか?
これはISO_IEC9899に定義されていますか?処理系依存でしょうか?
確か,「アドレス」という言葉の定義はないはずです。「アドレス定数」という言葉が唯一定義されていたかと。
単項&および単項*演算子のあたりで一応本文中に出てきたりしていた気はしますが……。
「アドレス」を定義するなら,オブジェクトを構成する各バイトを識別するための値でしょうか。
ちなみに,「メモリ」があることは必須条件ではありません。

ポインタはポインタなので,わかりやすくなるわけでもない「アドレス」なる言葉を使う必要は無いですよ。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#7

投稿記事 by sys » 14年前

かずまさん、ご回答ありがとうございます。

array1の場合は[C99 6.6]の通りに理解出来るのですが、array2に関してがわかりません。
この例でのarray2はアドレス定数でなければ何になるのでしょうか?
自動変数としてメモリ上に確保されているけど、確認しようがないポインタということなのでしょうか?
出来ればそれが記述されてある規格での定義が知りたいです。

あと、
かずま さんが書きました: printf("%p\n", &array1[0]);
// &array1[0] は、単項&演算子によりポインタとなるから、アドレス定数
で、単項*演算子([]演算子の暗黙の単項*演算子も)に対する単項&演算子は、C99 6.5.3.2 より
  • If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator.
と定義されているので、&array1[0]の*演算子に対する&演算子は評価されず、
&array1[0] → &*(array1+0) → (array1+0)
となり、 array1(ポインタが指す配列の先頭要素のアドレス)に対してポインタ演算していることになると思います。
仮に[C99 6.5.3.2]を適用しなくても「char('a')へのポインタ」とは読めますが、、、。

少々質問した趣旨への補足となりますが、最初に配列の先頭要素へのポインタは、
&演算子の「そのオペランドのアドレスを返す」ポインタと同じようなものかと考えました。
&演算子のポインタも何なのかも今探し中です。定義ご存知の方いましたら是非教えて下さい。(アドレス定数ではないですよね?)
ただそうすると、
  • ・なぜ static の配列型の場合だけ、暗黙にアドレス定数が生成されると定義されているのか、
    ・それ以外の、配列型の場合だけ暗黙に生成されるのはアドレス定数じゃなければなんなのか?
という疑問が出て質問に至りました。
最後に編集したユーザー sys on 2011年5月22日(日) 05:43 [ 編集 2 回目 ]

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#8

投稿記事 by sys » 14年前

YuOさん、ご回答ありがとうございます。

上記No.7のコメント投稿後にYuOさんのコメントを拝見しました。

「アドレス」の定義というより、
  • 「メモリ領域の特定の場所を指すアドレス値」
が、定義として存在するのかという疑問です。
メモリ上に確保されるのか、どのような場合にこれは作られるのか、などです。
YuO さんが書きました: ちなみに,「メモリ」があることは必須条件ではありません。
「ポインタ」にメモリは必須条件ではない、ということでしょうか?
YuO さんが書きました: 単項&および単項*演算子のあたりで一応本文中に出てきたりしていた気はしますが……。
C99 6.5.3.2 Address and indirection operators の3段落目の
  • The unary & operator returns the address of its operand.
でしょうか?
そうするとNo7でも書きましたが、
  • ・なぜ static の配列型の場合だけ、暗黙にアドレス定数が生成されると定義されているのか
    ・それ以外の、配列型の場合だけ暗黙に生成されるのはアドレス定数じゃなければなんなのか
という疑問が出てきます、、、。

ちなみに単項&演算子は、「メモリ領域の特定の場所を指すアドレス値」ということなのでしょうか?

[5/22 12:20頃訂正]
そうするとNo5でも書きましたが、→ そうするとNo7でも書きましたが、

かずま

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#9

投稿記事 by かずま » 14年前

sys さんが書きました: array1の場合は[C99 6.6]の通りに理解出来るのですが、array2に関してがわかりません。
この例でのarray2はアドレス定数でなければ何になるのでしょうか?
自動変数としてメモリ上に確保されているけど、確認しようがないポインタということなのでしょうか?
出来ればそれが記述されてある規格での定義が知りたいです。
「宣言では配列であったものが、式の中ではポインタになる」
だから、array1 も array2 もポインタになります。
そのポインタの値が、どこにあるかは実装依存です。
レジスタ上かもしれないし、メモリ上かもしれないし、どこにもない場合もあり得ます。
array1 はポインタになり、かつそれはアドレス定数と呼ぶことができます。
array2 はポインタになりますが、それはアドレス定数と呼ぶことができません。
アドレス定数と呼べないなら何になるのかといわれても、答えようがありません。

ちょっと、違う例をあげてみましょう。

3 + 5 は式です。定数だけを含む式なので、これを定数式です
a + 5 は式です。変数を含む式なので、これは定数式ではありません。

sysさんの質問は、「a + 5 が定数式でなければ何になるのでしょうか?」と言っているのと同じです。
記述されてある規格での定義はありません。

array1 は、式の中ではポインタです。static storage duration のオブジェクトを指すので
アドレス定数です。
array2 は、式の中ではポインタです。automatic storage duration のオブジェクトを指すので
アドレス定数ではありません。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#10

投稿記事 by ISLe » 14年前

sys さんが書きました:
ISLe さんが書きました: メモリ領域の特定の場所を指すアドレス値
というのは、「メモリ領域に確保されない」メモリ領域の特定の場所を指すアドレス値
ということでしょうか?
これはISO_IEC9899に定義されていますか?処理系依存でしょうか?
JIS X3010にある記述ですが、『6.2.4 オブジェクトの記憶域期間』に「オブジェクトは、生存期間を通じて存在し、一定のアドレスをもち、最後に格納された値を保持する。」とあります。
sys さんが書きました:では、「配列の宣言で生成される、配列の先頭要素を指すポインタ」はどちらのポインタになりますか?
配列の宣言で、ポインタが『生成される』ことはないので、どちらでもありません。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#11

投稿記事 by ISLe » 14年前

sys さんが書きました:
  • ・なぜ static の配列型の場合だけ、暗黙にアドレス定数が生成されると定義されているのか、
    ・それ以外の、配列型の場合だけ暗黙に生成されるのはアドレス定数じゃなければなんなのか?
オブジェクトはかならず一定のアドレスをもち、特定の場面で配列名はポインタに変換できます。
その上で、静的オブジェクトのアドレスは、定数として扱うことができる、というだけのことです。

&演算子(アドレス演算子)はポインタを返すわけですが、それは、対象のオブジェクト型へのポインタ(型)であるアドレス(値)、です。
アドレスという言葉は定義されていないから使うなということであれば、対象のオブジェクト型へのポインタ(型)であるポインタ(値)、ということになりますかね。
わけがわからないですね。


規格も含めてポインタという単語の周りはいろいろ省略されている気がします。

コード:

#include <stdio.h>
void twice(int *n) {
	*n *= 2;
}
int main(void) {
	int i = 12;
	int *p = &i;
	twice(p);
	printf("%d\n", i);
	return 0;
}
  1. intへのポインタpを宣言します。
  2. iへのポインタでポインタpを初期化します。
  3. 関数twiceの引数はintへのポインタです。
違和感ありますか?ありませんか?

(追記)
「整数i」は違和感ありますよね。
最後に編集したユーザー ISLe on 2011年5月22日(日) 18:40 [ 編集 2 回目 ]

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#12

投稿記事 by sys » 14年前

かずま さんが書きました: 3 + 5 は式です。定数だけを含む式なので、これを定数式です
a + 5 は式です。変数を含む式なので、これは定数式ではありません。
この例に対しては、int a;と宣言されているとして(intじゃなければ他の表現ですが、例に記載がないのであくまで仮で)
  • ISO/IEC 9899:1999(以下C99)
    ・6.2.5 type 4段落 standard signed integer types
    ・6.4.4.1 Integer constants
    ・6.5 Expressions
    ・6.5.6 Additive operators
の定義から、
3 + 5 は、「整数定数と整数定数の加算の式」
a + 5 は、「標準符号付き整数型と整数定数の加算の式」
だと考えられて、上記定義から、
「3 + 5」は定数式、「a + 5」は記述されてある規格での定義はない式
とは言えないと私は思います。
かずま さんが書きました: 「a + 5 が定数式でなければ何になるのでしょうか?」
の問に対しては、
  • 「a + 5 は標準符号付き整数型と整数定数の加算の式」
と答えることが出来ると思います。
(ざっと読んだだけなので a は「標準符号付き整数型」ではなく、もっと相応しい言い方が
あるかも知れませんが、少なからず「a + 5」は「記述されてある規格での定義はありません。」
とは言えない思います。)
いかがでしょうか?

では、本題です。
かずま さんが書きました: そのポインタの値が、どこにあるかは実装依存です。
レジスタ上かもしれないし、メモリ上かもしれないし、どこにもない場合もあり得ます。
「配列のポインタの値は実装依存」とは、どこかに定義されていますか?
実装依存の場合、処理系定義(implementation-defined)と定義されているのかな、と思い質問に至りました。

それとも、定義はされていなく、[C99 6.3.2.1]に記載されている、
「配列の先頭要素を指すポインタ(points to the initial element of the array object)」
とは、
  • 実装依存であるが、それは定義されてはいなく、automatic storage duration のオブジェクトを指すポインタ
ということでしょうか?

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#13

投稿記事 by sys » 14年前

ISLe さんが書きました: 配列の宣言で、ポインタが『生成される』ことはないので、どちらでもありません。
失礼しました、「生成」は自分なりの用語でした。

ISLeさんのコメントで気が付きました。いままで、
  • [C99 6.3.2.1]
    式中の array は配列の先頭要素を指すポインタ(points to the initial element of the array object)
と書いていましたが、
"pointer"ではなく"points"ですね。
JIS X3010 でも、
  • 「配列オブジェクトの先頭の要素を指し(points)」
と翻訳してあり、けして、
  • 「配列オブジェクトの先頭の要素へのポインタ(pointer)」
ではないですね。
ISLe さんが書きました: JIS X3010にある記述ですが、『6.2.4 オブジェクトの記憶域期間』に「オブジェクトは、生存期間を通じて存在し、一定のアドレスをもち、最後に格納された値を保持する。」とあります。

オブジェクトはかならず一定のアドレスをもち、特定の場面で配列名はポインタに変換できます。
その上で、静的オブジェクトのアドレスは、定数として扱うことができる、というだけのことです。
とても納得できました。
ISLe さんが書きました: &演算子(アドレス演算子)はポインタを返すわけですが、それは、対象のオブジェクト型へのポインタ(型)であるアドレス(値)、です。
もう一度単項&演算子も確認しました。
  • ・The unary & operator returns the address of its operand.
    (単項&演算子は、そのオペランドのアドレスを返す。)
「pointer」とは記載がなく、JIS X3010でもポインタとは翻訳してませんでした。

理解出来たと思います。
「pointer」「points」「returns the address」
は、違うものだときちんと区別し、「points to the initial element of the array object」とは何かと説明すると、
  • 配列はオブジェクトなので一定の自動記憶域期間(automatic storage duration)のアドレスをもち、
    (※static宣言なら[C99 6.6]に定義されているように、アドレス定数として扱える。)
    [C99 6.3.2.1]に定義されている特定の場面では、配列名は配列の先頭要素を指す(points)
という言い方は、いかがでしょうか?

かずま

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#14

投稿記事 by かずま » 14年前

sys さんが書きました: ISO/IEC 9899:1999(以下C99)
・6.2.5 type 4段落 standard signed integer types
・6.4.4.1 Integer constants
・6.5 Expressions
・6.5.6 Additive operators
の定義から、
なぜ、6.6 Constant expressions を省略するのですか?

3 + 5 は、6.5.6 までなら「整数定数と整数定数の加算の式」ですが、
6.6 により「定数式」とも呼ぶことができます。 一方、
a + 5 は、6.6 により「定数式でない」ことがわかりますが、
その名前(例えば「非定数式」などの用語)は定義されていません。
だから、「a + 5 が『定数式でなければ』何になるのでしょうか?」
の問いに対して「記述されてある規格での定義はありません」と答えました。
ご理解いただけませんか?

かずま

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#15

投稿記事 by かずま » 14年前

sys さんが書きました: では、本題です。

 かずま さんが書きました:
  そのポインタの値が、どこにあるかは実装依存です。
  レジスタ上かもしれないし、メモリ上かもしれないし、どこにもない場合もあり得ます。

「配列のポインタの値は実装依存」とは、どこかに定義されていますか?
「配列のポインタ」って何ですか?
私が、「そのポインタ」と書いたのは、
「宣言では配列であったものが式の中ではポインタになる。そのポインタ」
ということですよ。
「値は実装依存」とも言っていません。
「『値が、どこにあるか』は実装依存です」です。

これも、別の例を挙げてみましょう。

int a = 2; だとして、(a + 5) * 3.4 という式では、
a + 5 の演算結果は int ですが、その値はどこにあると思いますか?
その値は次に double に変換されますが、その値はどこにあると思いますか?
規格書に、レジスタに置けだとか、メモリ上に置けだとか、は書かれていないはずです。
だから、「その値をどこに置くか」は実装依存です。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#16

投稿記事 by sys » 14年前

かずま さんが書きました: なぜ、6.6 Constant expressions を省略するのですか?
失礼しました。省略したというよりは返答にも書いてある通り
ざっとしか見てなかったからです、すいません。
6.6 から
  • ・3 + 5 は、「整数定数と整数定数の加算の整数定数式(integer constant expression」
でしょうか?
No9でかずま さんが書きました: sysさんの質問は、「a + 5 が定数式でなければ何になるのでしょうか?」と言っているのと同じです。
私は、かずまさんの上記のコメントに対して仮にもし私だったら
「a + 5 は標準符号付き整数型と整数定数の加算の式」
と答えるだけで、
かずま さんが書きました: だから、「a + 5 が『定数式でなければ』何になるのでしょうか?」
の問いに対して「記述されてある規格での定義はありません」と答えました。
私は問いてません、、、。
正直、式の定義については、私は目を通していなくわからない部分が多く
正確な回答を出来るだけの知識を持ち合わせていません。
もし上記の知識が質問の本筋を理解するのに必要不可欠なら勉強してきます。
その場合具体的な指摘を頂けるとありがたいです。
かずま さんが書きました: 「配列のポインタ」って何ですか?
私が、「そのポインタ」と書いたのは、
「宣言では配列であったものが式の中ではポインタになる。そのポインタ」
ということですよ。
「値は実装依存」とも言っていません。
「『値が、どこにあるか』は実装依存です」です
そのポインタの値が、どこにあるかは実装依存です。
"その"が意味するものを、かずまさんの意図とは違って私が捉えてしまいました。失礼しました。
No12で私 さんが書きました: 実装依存の場合、処理系定義(implementation-defined)と定義されているのかな、と思い質問に至りました。
それとも、定義はされていなく、[C99 6.3.2.1]に記載されている、
「配列の先頭要素を指すポインタ(points to the initial element of the array object)」
とは、
実装依存であるが、それは定義されてはいなく、automatic storage duration のオブジェクトを指すポインタ
ということでしょうか?
出来れば上記についてのかずまさんの見解をお聞かせ頂きたいです。
かずまさんが教えて下さったご意見に対して、私なりにかずまさんのご意見をまとめた答えです。

それと合わせて、ISLeさんのコメントで教えてもらった内容をふまえた、
No13で私 さんが書きました: 「pointer」「points」「returns the address」
は、違うものだときちんと区別し、「points to the initial element of the array object」とは何かと説明すると、

配列はオブジェクトなので一定の自動記憶域期間(automatic storage duration)のアドレスをもち、
(※static宣言なら[C99 6.6]に定義されているように、アドレス定数として扱える。)
[C99 6.3.2.1]に定義されている特定の場面では、配列名は配列の先頭要素を指す(points)
という言い方は、いかがでしょうか?
についてのご意見も是非お聞かせ頂きたいです。

私としては、上記(No13)が一番納得出来る答えだと思うので、ここが違う、等がありましたら
ご指摘頂ければと考えています。

かずま さんが書きました: int a = 2; だとして、(a + 5) * 3.4 という式では、
a + 5 の演算結果は int ですが、その値はどこにあると思いますか?
その値は次に double に変換されますが、その値はどこにあると思いますか?
規格書に、レジスタに置けだとか、メモリ上に置けだとか、は書かれていないはずです。
だから、「その値をどこに置くか」は実装依存です。
私も、現在は同意見です。
  • C99 6.2.4
    オブジェクトは、その生存期間を決定する記憶域期間(storage duration)をもつ。
と定義してあるだけなので、上記例だと演算結果などそれぞれの値は記憶域期間はもっているけど
「その値をどこに置くか」は実装依存と考えられると思います。

そもそもなのですが、私はずっと
「pointer」「points」「returns the address」
を一緒くたんに「ポインタ」と勘違いしていたので
皆さんのご意見をうまく理解出来なかったんだと思います。
ですので、No13のコメントが皆さんが教えて下さったことを自分なりに消化して上での
私が出した結論です。
No13に対しての皆さんのご指摘を頂けたらと思います。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#17

投稿記事 by sys » 14年前

ISLe さんが書きました: 規格も含めてポインタという単語の周りはいろいろ省略されている気がします。

コード:

#include <stdio.h>
void twice(int *n) {
	*n *= 2;
}
int main(void) {
	int i = 12;
	int *p = &i;
	twice(p);
	printf("%d\n", i);
	return 0;
}
  1. intへのポインタpを宣言します。
  2. iへのポインタでポインタpを初期化します。
  3. 関数twiceの引数はintへのポインタです。
違和感ありますか?ありませんか?
(追記)
「整数i」は違和感ありますよね。
失礼しました。こちらについての返答が漏れてました。
違和感?に対する答えをなんと答えていいのかわかりませんが、
私なりに書くと、
  1. intへのポインタ(pointer type)pを宣言します。
  2. iへのアドレスを返し(returns the address)、ポインタ(pointer type)pを初期化します。
  3. 関数twiceの引数はintへのポインタです。
    (関数の引数でのポインタの正確な表現方法がわからないのですが、
    ここでのポインタは、ポインタ型の変数pが持っている値(iのアドレス)を引数として渡す。
    という意味のポインタ)
になると思います。
同じポインタという表現でも、
  • 「pointer」「points」「returns the address」
のように全然意味が違うということに注意しないといけない、ということでしょうか?

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#18

投稿記事 by ISLe » 14年前

sys さんが書きました:同じポインタという表現でも、
  • 「pointer」「points」「returns the address」
のように全然意味が違うということに注意しないといけない、ということでしょうか?
先の回答では文脈で判断して2つの意味を区別してくださいと書きました。
実際には3つの意味があります。
  • 「変数」
  • 「値」
  • 「型」
いろんなところで当たり前のように区別しないで使われているんですが、入門書に最初に出てくるポインタ変数が刷り込まれて混乱するひとがたくさんいますね。

過不足無く表現するとしたら、
  1. intへのポインタ型の変数pを宣言します。
  2. int型の変数iのアドレスでintへのポインタ型の変数pを初期化します。
  3. 関数twiceの仮引数nはintへのポインタ型です。
となるでしょうか。
sysさんの回答していただいた中にあるtwice関数を呼び出すときの実引数p。
pに格納されている値が渡るという至極当然のこともポインタが絡むと分からなくなってしまうひとが続出するようです。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#19

投稿記事 by ISLe » 14年前

sys さんが書きました:
  • 配列はオブジェクトなので一定の自動記憶域期間(automatic storage duration)のアドレスをもち、
    (※static宣言なら[C99 6.6]に定義されているように、アドレス定数として扱える。)
    [C99 6.3.2.1]に定義されている特定の場面では、配列名は配列の先頭要素を指す(points)
自動記憶域期間をもつように宣言された配列、というふうにしないとおかしくないですかね。
あと配列名がポインタに変換されるのは、記憶域期間の種別とは無関係なのでまとめる必要がないと思います。

6.3.2.1の記述をアレンジすれば
「特定の場合を除いて、配列名はその要素型へのポインタに型変換される。それは配列の先頭要素を指す。」
という感じになると思いますが。
要素型ってところがいまいち。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#20

投稿記事 by sys » 14年前

ISLe さんが書きました:
  • 「変数」
  • 「値」
  • 「型」
これらをまとめて「ポインタ」とだけ理解していた点が
おっしゃる通り混乱していた原因だと思いました。
ISLe さんが書きました: 6.3.2.1の記述をアレンジすれば
「特定の場合を除いて、配列名はその要素型へのポインタに型変換される。それは配列の先頭要素を指す。」
という感じになると思いますが。
要素型ってところがいまいち。
日本語に翻訳するのがなんとも難しい気がしますね…。
ただ、上記で私は納得出来ました。
配列を理解するには、当然と言えば当然ですがC99の添字演算子、配列宣言子の項目だけでなく、
  • ・配列型(array type)、ポインタ型(pointer type)は派生型(derivation type)である。
    ・配列型(array type)は、要素数(サイズ)と要素の型(要素型、element type)の2つで特徴化されるデータ型である。
    ・派生型(derivation type)を構築するこれらの方法は、再帰的に適用できる。
など型への理解もないと、配列やポインタは理解し難いものだと思いました。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#21

投稿記事 by sys » 14年前

ご指摘等のコメントもなく私も納得できたので、ひとまず収束したいと思います。
皆さんのコメントのおかげで、配列型への理解が深まりました。
ありがとうございました。

まだ知らないことも多く、皆さんのように質問への回答コメントは難しいので、皆さんとmixC++への感謝と微力ながらの貢献として、
マイ日記に今回の質問で教えて頂いたことと、私なりに配列型を理解するのに必要な定義をまとめたものを投稿してみました。
http://dixq.net/forum/blog.php?u=688&b=1963
http://dixq.net/forum/blog.php?u=688&b=1964

配列、ポインタについての解説書籍、サイトは多いと思いますが
それらを読んでも理解出来なかった点について、私なりに調べたことを記載しています。
もし、私の様な疑問を持った人がここにたどり着いたら、参考にして頂けると幸いです。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#22

投稿記事 by ISLe » 14年前

かなりむかし他所のメーリングリストで同じようなやり取りをしたことがあったのですが気になってそのころのメールを詳しく読みなおして分かったことがありました。

ポインタという単語がいいかげんに使われているのは、『プログラミング言語C 第2版』の翻訳でした。
原文を確認してはいないのですが、A7.1 ポインタの生成 とか A7.4.2 アドレス演算子 のところは、規格に照らせば「~を指す」と訳すべきところが「~へのポインタである」になっていますね。
こちらはメモリセルといった例えが出てきますが、アーキテクチャとしてのアドレスと、規格にあるアドレスと、いいかげんな使われ方をしているポインタがまざりあっていっそうわけのわからないことになっています。

最近はすぐにネットでJISを参照できるので読まなくなってて忘れてました。
最後に編集したユーザー ISLe on 2011年5月25日(水) 02:41 [ 編集 3 回目 ]

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#23

投稿記事 by sys » 14年前

やっぱり翻訳というのは難しい作業なのですね。
今回の件で定義を確認するときは、ISOの英語原文も注意深く確認するようになったので、
とても良い教訓になりました。
親切に導いて下さった方々に、ほんと感謝の気持ちでいっぱいです。

再度の補足ありがとうございます。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#24

投稿記事 by ISLe » 14年前

追記中に返信が付いてしまったので新規に投稿しなおします。

自分がポインタの3つの意味を考えるきっかけになったのは『C言語 ポインタ完全制覇』という書籍の補足ページです。
最初に目にしたときはすごい衝撃を受けました。
『C言語 ポインタ完全制覇』自体は読んだことがないんですけどね。

あと件のメーリングリスト投稿によると8年前の時点で『プログラミング言語C 第2版』と同様にJIS X3010で「points ~」は「~のポインタである」と訳されていたようです。
確認取れませんが。

sys
記事: 27
登録日時: 14年前

Re: 配列の先頭要素を指すポインタ自体のアドレスについて

#25

投稿記事 by sys » 14年前

「C言語 ポインタ完全制覇」は購入しました。
これを読んで配列やポインタに対して格段と理解出来るようになりました。
入門書としては最適だと思います。

ただそれでも、載ってないことなど学べば学ぶほど疑問が出てきて、、、
まだポインタ、配列から抜けだせません。
ここ数日、まだまだ配列への質問続きですが…ご教示して頂ければ幸いです。

閉鎖

“C言語何でも質問掲示板” へ戻る