🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

6回答

1944閲覧

str[i]の別表現について

carnage0216

総合スコア194

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/02/15 06:45

編集2021/02/20 16:15

str[i] と*(str + i) および &str[i] と str + iと&*(str + i) は同じですか?
仮にiを+1していくとして、
iが+1されるとstr[i]のポインタのアドレス自体ではなく、
アドレスに入っているメモリの値が+1され、
iが+1されるとつぎのアドレスに移行すると聞いたのですが、それは上の5つのうちどれですか?
また、が+1されるとstr[i]のポインタのアドレス自体ではなく、
アドレスに入っているメモリの値が+1され、のは5つのうちどれですか?

str[i]はiが+1(4バイト)されるとstr[]がポインタのアドレス自体が上がり、次のアドレスに進む。

*(str + i)はiが+1されるとstrのアドレスが+1
上がり次のアドレスに進む

&str[i]は&がついているから上と同じ

str + iはが+1されたらstr自体がアドレス表すのでアドレス自体が次のアドレスに進む。

(str + i) は左辺部の&より他と同じということでしょうか?
すなわちstr[i] と
(str + i) および &str[i] と str + iと&*(str + i) は同じですか?

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

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

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

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

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

fana

2021/02/15 07:05

同じ内容を同じ場所で複数回質問しても,得られる回答が大きく変化することは期待し難いのではないでしょうか? 何やらプライベートで教えてくれるという方とコンタクトを取っておられる様子(?)ですし,まずは一旦そちらを頼ってみてはどうでしょうか. https://teratail.com/questions/322540#reply-447652
episteme

2021/02/15 07:39

マルチポストしないと死んじゃう病なんですかね?
episteme

2021/02/15 08:35

> 同じかどうかなんてコード書けばわかるでしょ… その検証コードが書けないから訊くしかないのかも。
m.ts10806

2021/02/15 22:18

見た目簡単そうに見えて回答するから食いつくだけに思います。 指摘は全て敵。アドバイスと捉える気概がない。 もはや餌すら不要じゃないですかね。
guest

回答6

0

質問者より

言語はcです。今後はタグにcのみにします。strの型はcharです。

とのコメントを受けました。下記の回答は前提が間違っていますので、無視してください。


実際に同じか試してみました。

質問文に詳しいコードがなかったため、前提として、下記であると推測しました。

  1. 質問にはCとC++の二つの異なる言語のタグがついています。C++は(一部を除いた)Cの拡張であり、Cについて聞きたいのであれば、わざわざC++のタグを付けると言うことはない判断しました。よって、Cの話ではなくC++に限定した話である前提とします。
  2. 質問にはstrがどのような型であるかの情報がありません。strと言う名前からstring、つまり、文字列だと推測されます。C++で文字列を扱うのであればstd::stringがもっとも妥当とおもわれるため、std::stringであると判断しました。strstd::stringであることを前提とします。

質問での推測が正しいか確認するために、下記のコードを用意しました。

C++

1#include <iostream> 2#include <string> 3 4int main() 5{ 6 std::string str = "abcdef"; 7 std::size_t i = 1; 8 std::cout << str[i] << std::endl; 9 std::cout << &str[i] << std::endl; 10 return 0; 11}

C++

1#include <iostream> 2#include <string> 3 4int main() 5{ 6 std::string str = "abcdef"; 7 std::size_t i = 1; 8 std::cout << *(str + i) << std::endl; 9 std::cout << (str + i) << std::endl; 10 std::cout << &*(str + i) << std::endl; 11 return 0; 12}

それぞれの実行結果は下記にあるWandboxを確認してください。

見ればわかりますが、下のコードはコンパイルエラーになります。つまり、最初の前提で話を進めた場合、「同じであるという前にコンパイルエラーになる」が結論となります。

なお、前提が異なる、例えばCの話であったり、strcharの配列であると言った場合は、また別の結論になります。もし、私の前提が間違っているのであれば、質問文に言語や型がわかるようコンパイル可能なコードを明記するようにしてください。そして、この回答は忘れて下さい。

投稿2021/02/15 12:48

編集2021/02/15 22:18
raccy

総合スコア21737

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

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

carnage0216

2021/02/15 15:33

どうもありがとうございます。 あの実際に下のプログラムをコンパイラしたのですが、なぜエラーになるのでしょうか? 文字列の"abcdef"の配列の[1]に入っている文字bのアドレスを表示するプログラムだと思うのですが。
episteme

2021/02/15 17:38

str が (char*ではなく) std::string だから。
carnage0216

2021/02/15 18:21

しかし、strをchar*に変えてもエラーは残ったままでした。 一体どう書きなおせばエラーは消えるのやら。。。 それともアドレスを表示する術がない、、、とはさすがにあり得ないですね。
raccy

2021/02/15 22:10

> carnage0216さん まず、あなたがすべきことは「前提が合っているか間違っているか」を判断し、それを示すことです。私は以前何度も言ったと思いますが、CとC++は違います。二つを混同している内はどちらも理解することは永遠にできません。あなたが知りたいのはCなのか、C++なのか、はっきりして下さい。また、Cで文字列といえばNULL終端文字列しか標準ではありませんが、C++ではstd::stringというのも用意されています。C++では演算子をオーバーロードできるため、型が異なると+や[]の動作が全く異なります。そのため、strの型次第では全く異なる回答になる可能性があります。ひとまず、 1. この回答の前提は合っている。 2. この回答の前提が間違っている。 3. この回答の前提が理解できない。 のどれなのかをはっきりし、1.または2.であれば、「どちらの言語なのか」「strの型は何か」を質問文に明確に追記してください。
carnage0216

2021/02/15 22:14

言語はcです。今後はタグにcのみにします。strの型はcharです。
raccy

2021/02/15 22:20

では、質問文にも明記してください。そして、この回答は前提が間違っていますので、忘れて下さい。
guest

0

C

1#include <stdio.h> 2 3int main(void) 4{ 5 char str[8] = "abcdefg"; 6 int i = 3; 7 8 printf("str[i] = '%c'\n", str[i]); 9 printf("*(str + i) = '%c'\n", *(str + i)); 10 printf("&str[i] = %p\n", &str[i]); 11 printf("str + i = %p\n", str + i); 12 printf("&*(str + i) = %p\n", &*(str + i)); 13}

実行結果

text

1str[i] = 'd' 2*(str + i) = 'd' 3&str[i] = 00000045D00FFECB 4str + i = 00000045D00FFECB 5&*(str + i) = 00000045D00FFECB

質問する前に、このようなコードを書いて確かめようとしなかったのでしょうか?
str と i の型が知りたいという回答があったのに、なぜそれには対応しないのでしょうか?
str[i] と *(str + i) が等しくないこともあるという回答があった時、str の型を示せば
C でも C++ でも構わなかったのに、そうはせず、C++ のタグをはずしましたね。


char str[8] = "abcdefg"; という宣言があったら、
str は変数です。str は配列です。str は配列変数です。
str の型は、「char の配列」です。str の型は、「char [8]」です。
str の値は、{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', '\0' } です。
配列の要素数は 8 です。
配列変数 str のサイズは sizeof(str) = 8 です。
str に入っている文字列 "abcdefg" の長さは strlen(str) = 7 です。

さらに int i = 3; という宣言があったら
str[i] は、配列変数 str の i番目の要素です。str[i] は配列ではありません。
str[i] の型は char です。str[i] の型は、配列型ではありません。
str[i] の値は 'd' ですと言いたいところですが、ちょっと待ってください。
str[i] が 'd' なら、str[i] = 'x';'d' = 'x'; となって
コンパイルエラーになるはずです。

str[i] の値は「左辺値」です。
左辺値というのは変数のようなものです。
代入演算子の右辺には、a = b + 7; のように式が書けます。
式というのは演算子を使った式もありますが、
演算子を使わない定数や変数も式と言っていいのです。
式には評価結果の値があります。変数は値を持っています。定数は値です。
代入演算子の右辺には値が来ればよいのです。

ところが、代入演算子の左辺には値が来てはいけません。
5 = 9; はエラーです。b + 7 = 9; もエラーです。
左辺には定数も「演算子を使った式」も書けませんが、変数は書けます。
左辺に書けるものを示す式を「左辺値」と言います。
変数は左辺値です。
str[i] も左辺値です。
添字演算子 [] を使った式ですが、代入演算子の左辺に書けます。
左辺値は変数みたいなものであり、値を持っていて、その値を使うことができます。
だから、str[i] が代入演算子の右辺にあったり、関数の引数だったりする場合は
値を取り出すことができて、str[i] は 'd' となります。

ここまでの説明を全部理解できますか?

理解できない場合は、どこが分からないのかを書いてください。
理解できた場合は、次の *(str + i) の説明に進みます。

なぜ、str[i] を配列だと思ったんですか?
まだ str[i] は配列だと思っていますか?

投稿2021/02/20 12:53

編集2021/02/20 13:45
kazuma-s

総合スコア8224

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

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

carnage0216

2021/02/20 16:15

>>C++ のタグをはずしましたね。 すいません、なんかじゃじゃ馬がうるさくてつい。ですがまた貼っておきます!
carnage0216

2021/02/20 17:33 編集

プログラムどうもありがとうございます。 理解できない場合は、どこが分からないのかを書いてください。いえ、今のところありません。 理解できた場合は、次の *(str + i) の説明に進みます。お願いいたします。 ただ、私自身も勉強させて頂いているため、ちゃんと理解できているかを確認をさせていただきたく思います。 *(str + i)はアスタリスクが付いているため、(str + i)は値を扱う変数の塊であります。 strはアドレスを扱う変数(Cの決まりより)であり、それに変数iが足されています。なので、例えば、アスタリスクが付いているため、i = 0として、 *(str + 0)は 変数str + 0が指すアドレスのメモリが持っている値を扱うものである。 なぜ、str[i] を配列だと思ったんですか?参考書を読んだためです。 まだ str[i] は配列だと思っていますか?はい。思っています。間違っている場合は、どうかご指摘ください。
kazuma-s

2021/02/20 17:35

私の回答でわからないところは、今のところないんですよね。 > str[i] は、配列変数 str の i番目の要素です。str[i] は配列ではありません。 > str[i] の型は char です。str[i] の型は、配列型ではありません。 これも理解できたのですよね。 でも、str[i] は配列だと思っているのですよね。 矛盾していませんか? str[i] が配列だと書いてある参考書の書名を教えてください。
kazuma-s

2021/02/21 00:32 編集

最初の質問に対する raccyさんの回答へのコメントで、 「strの型はcharです。」と carnage0256さんは言っています。 raccyさんの「質問にも明記してください。」という依頼は無視しています。 strの型はchar だと今でも思っていますか?
kazuma-s

2021/02/21 00:37

char str[8]; という宣言があったとして、 ・str[i] は、[] が付いているから配列だ。 ・str は、[] が付いていないから char だ。 と思っていませんか?
carnage0216

2021/02/21 08:16

>>str[i] が配列だと書いてある参考書の書名を教えてください。 勝手な妄想でした。正しい答えを教えてください。 >>strの型はchar だと今でも思っていますか? わかりません。というかstrは変数名なので型はcharでなくてもいいと思っています。 >>char str[8]; という宣言があったとして、 ・str[i] は、[] が付いているから配列だ。 ・str は、[] が付いていないから char だ。 と思っていませんか?str[i] は、[] が付いているから配列だ。とは思っています。 上と同様にstr は、[] が付いていないから char だとは思わず型によって定義が変わる変数としか思ってないです。
guest

0

どうでもいい話ですが、

str[i] と*(str + i) は同じですか。に関して

str[i]と*(str + i)は同じです。さらにi[str]も同じです。
なぜならば、*(i + str)だからです。

嘘だと思う人もいますが、コンパイルしてみればわかります。

投稿2021/02/15 13:48

ppaul

総合スコア24670

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

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

carnage0216

2021/02/16 03:07 編集

ありがとうございます。 *(i + str)とも書けるのは、もし変数iが++されるとして、 変数iが+1されると変数strのポインタの表すアドレス自体に+1されるので、 str[i]自体も、もし変数iが++されるとして、 変数iが+1されると変数strのポインタの表すアドレス自体に+1されるので、 別表現としてstr[i]は*(i + str)とも書けるのですね。 仮に&*(i + str)の場合は変数iが++されるとして、 変数iが+1されると変数strのポインタの表すメモリのアドレスは&*(1 + str)となるのでアドレス値が増えるのですね。
thkana

2021/02/16 12:26

「コンパイルしてみればわかる」はちょっと危険ですね。例外はないのですか? と聞かれると、「あらゆる場合を試せばいい」ということになりますがそんなの無理です。 str[i]と*(str+i)は等価だとCの規格書に書いてある、が根拠になると思います。
guest

0

まずは型の情報が欲しいです。
多分charだとは思いますが。

投稿2021/02/15 06:54

HogeAnimalLover

総合スコア4830

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

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

0

ベストアンサー

str[i] と*(str + i) および &str[i] と str + iと&*(str + i) は同じですか?

はい。

また、が+1されるとstr[i]のポインタのアドレス自体ではなく、

アドレスに入っているメモリの値が+1され、のは5つのうちどれですか?

どれとも関係しません。いずれも、単体ではアクセスしたメモリを書き換える、という意味は持ちません。

投稿2021/02/15 06:49

編集2021/02/15 06:51
maisumakun

総合スコア145965

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

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

carnage0216

2021/02/15 11:27 編集

全部同じことのことですが、 *(str + i)  →str配列の先頭アドレスにiを加算したアドレスの中身の値 &str[i]    →str配列のi番地のアドレス に関しては、*(str + i) は*が付いているが、strは自体はポインタの指すアドレス自体を表しているため*の効果?がなくなり、&str[i] と同じということですか?しかし&str[i]はstr配列のi番地のアドレスであり、アドレスの中身の値とは書いていませんが、なぜ同じなのでしょうか?
maisumakun

2021/02/15 11:27 編集

> 全部同じことのことですが いえ、「str[i] と*(str + i)」が同じ、「&str[i] と str + iと&*(str + i)」が同じという解釈です。
carnage0216

2021/02/15 11:28

あ、なるほど、もう一度読み直します。
carnage0216

2021/02/15 11:34

ってことは、 以前に書いた *(str+i)…str+iを逆参照した左辺値 は上より、*(str + i)は*より数値を表すのでstrは「str」自体が既に先頭のアドレスを表しますが*よりポインタで指定されたアドレスのメモリの値を表す。そして、iが+1するたびにポインタのアドレスのメモリの数値も+1されるわけですね。(アドレスのメモリの数値が上がるだけでアドレスに変化はないため上に書いたままでしかない) &*(str+i)…上の左辺値のアドレス は左辺を優先するため、&が優先され、*はなくなるんで、アドレスを表す。変数iが+1増えるとstrのアドレスも+1されていく。(そして、配列よりアドレスが+1されたので、次のアドレスに値が入るわけですね。) なので書き方としては、 str+iに関しては、「str」自体が既に先頭のアドレスを表し、変数iが+1されることによってアドレス+1されるのでstr+iは&*(str+i)と同じというわけなのですね。 &str[i] も&がついているためiが変化するとstr[i]のポインタの指すアドレスが+1されるわけですね。 もう一つの str[i] と*(str + i) と同義なのは、str[i] は値を扱うので、変数iが+1されるとstr[i]のアドレスの値も+1されるため、書き方として*(str + i)と同じと言える。 正しいでしょうか?
carnage0216

2021/02/15 11:40

また、以前に書いていただいた、 iが変われば、str[i]が指すメモリ位置、つまり&str[i]が変化します。それで問題ないのではないでしょうか? については、「&str[i] と str + iと&*(str + i)」がこれに当てはまるということでしょうか?
maisumakun

2021/02/15 11:44

> *(str + i)は*より数値を表すので この考え方が間違っています。単なる数値ではなく、*(str + i) = 8;のような代入も成立する「左辺値」です。
maisumakun

2021/02/15 11:45

> iが変われば、str[i]が指すメモリ位置、つまり&str[i]が変化します。それで問題ないのではないでしょうか? については、「&str[i] と str + iと&*(str + i)」がこれに当てはまるということでしょうか? すべて、iが変化すれば結果が変化します。「アドレスのメモリの数値が上がるだけでアドレスに変化はないため上に書いたままでしかない」という意味がわからないです。
maisumakun

2021/02/15 11:47

> &str[i] も&がついているため このあたりの解釈方法に、根本的におかしな点がある気がしてきました。&も式の途中に置きうる1つの演算子であって、「あるかないかで動作を切り替えるスイッチ」ではありません。
maisumakun

2021/02/15 11:48

> 左辺を優先するため、&が優先され、*はなくなるんで、アドレスを表す。 違います。*で生成した左辺値のアドレスを&で取得するため、元のアドレスに戻る、というだけです。
carnage0216

2021/02/15 12:05 編集

ありがとうございます。 >>すべて、iが変化すれば結果が変化します。「アドレスのメモリの数値が上がるだけでアドレスに変化はないため上に書いたままでしかない」という意味がわからないです。 に関しては、Hogeさんから頂いたプログラムよりいiが+1されると 「str[i] と*(str + i)」はiが+1されたため、ポインタの指すアドレスの番号が変化してアドレス中身の文字を表示する、「&str[i] と str + iと&*(str + i)」はiが+1されたため、アドレス自体が変化するため、変化したアドレスが表示された。とわかりました。
carnage0216

2021/02/15 12:14 編集

間違っているように思える部分もありますが、なんやかんやで理解はできてきました。
carnage0216

2021/02/15 20:30

あのstr[i]はポインタのような変数の働きをして(だから*pと置き換えることもできる。)、仮に++iの時、 変数iが+1増えると、str[i]の指す配列のアドレスが含む値が+1されるということでしょうか? ちなみに、ポインタと配列の違いは何ですか?使い分けはありますか?
maisumakun

2021/02/15 22:46

> あのstr[i]はポインタのような変数の働きをして(だから*pと置き換えることもできる。)、仮に++iの時、 変数iが+1増えると、str[i]の指す配列のアドレスが含む値が+1されるということでしょうか? iを変化させても、配列がメモリを移動したりすることはありません。str[i]の指す位置が変わるだけです。 > ちなみに、ポインタと配列の違いは何ですか?使い分けはありますか? 一部の事例(配列自体のアドレスを取る、sizeofを適用するなど)を除けば、「式に現れた」配列は「配列の先頭アドレスを指すポインタ」として解釈されます(適切な場所を指すchar *pに対して、p[i]と書いても問題なく動作します)。 もちろん、「宣言」としては配列とポインタで意味が違います。
maisumakun

2021/02/15 22:48 編集

> str[i]の指す配列のアドレスが含む値 これが「&str[i]」(アドレス)なのか「str[i]」(中身の値)なのかが曖昧です。
carnage0216

2021/02/16 00:41 編集

曖昧な説明申し訳ありません。 str[i]について、iが変化する際にstr[i]は配列でもあるため、アドレスのが変化すると思いますが、正しいでしょうか?アドレスを変化させて、そのアドレスのメモリの「数値」を扱うということでしょうか?
maisumakun

2021/02/16 00:54

> str[i]について、iが変化する際にstr[i]は配列でもあるため、アドレスのが変化すると思いますが、正しいでしょうか? 質問の意味がわかりません。str[i]は配列ではなく、「1要素を指す左辺値」です。
maisumakun

2021/02/16 03:26

すでに多数の回答がついていますが、それ以上に何を求めるのか、具体的に書いていただけないでしょうか?
carnage0216

2021/02/16 04:50

上から物を言うようで申し訳ないのですが、しっくりくる回答がなくて。
carnage0216

2021/02/16 05:20

ちなみに、 &(*p)はポインタを表すので、&str[i] と str + iと&*(str + i)と同じものですね!
carnage0216

2021/02/16 06:04

もう一つ、&(*p)と&*(str + i)に*をつけるのはなぜですか? ポインタのようなアドレスを表すならば、*はいらないと思うのですが。 要は&(*p)と&(str + i)でいいのでは?と考えてしまいます。
maisumakun

2021/02/16 06:07

> もう一つ、&(*p)と&*(str + i)に*をつけるのはなぜですか? *はアドレスから指す先をたどるための演算子です。&演算の逆の働きです。
maisumakun

2021/02/16 06:09

> ポインタのようなアドレスを表すならば、*はいらないと思うのですが。 「*でアドレスを指す先に変換する→&でアドレスを取る」という操作でもとに戻るので、&*の「両方をまとめて」省略しても結果は変わりません。
maisumakun

2021/02/16 06:10

&(str + i)では、「計算結果(右辺値)のアドレスを取る」という意味になってしまい、成立しません。
carnage0216

2021/02/16 06:18

ありがとうございます。ってことはあるアドレスに&によって行って、*によって帰ってくるから、そのまんまの元のアドレスなわけですね。要は元のアドレスから移動していないも同然であるため、ポインタは(行って、帰ってくるような元の)アドレスを作るだけなのでポインタと同じ。 &*(str + i)に関してもstrがアドレスを表すが、&によって行って、*によって帰ってくる結局は同じアドレスのままってわけですね。独特な文章ですいません。
carnage0216

2021/02/16 06:27

「*でアドレスを指す先に変換する→&でアドレスを取る」 えーと、*でアドレスを指す先にある何を変換するのでしょうか? &はアドレスを表すため、取るですね。
carnage0216

2021/02/16 07:28

なるほど、単純に演算子*はアドレスに「行く」、そして、&はそこのアドレスを「得る」 働きがあるのですね。 だからポインタと同じ働きなわけですね。 &*(str + i)に関してもstrがアドレスを表すが、*にアドレスまで行って、 &によってそこのアドレスを得る、結局これもポインタP(アドレスを得る)と同じ働きですね。 &(str + i)だけだったら「行く」だけになってしまいますもんね。
carnage0216

2021/02/17 23:31

あの質問があります。 なぜアドレスに入っている数値を+1したい場合、 (*(&str))++と書くと確かに中身の値が変わりますが、原理がわかりません。 &strでアドレスを指定したうえで*により中身を+しているためでしょうか? カッコの中から処理される仕様なのでしょうか?
kazuma-s

2021/02/18 00:06 編集

> (*(&str))++と書くと確かに中身の値が変わりますが、 実際にコードを書いて実行して、中身の値が変わりましたか? (*(&str))++ はコンパイルエラーになります。 妄想で質問しても、何も得られません。
kazuma-s

2021/02/18 00:20 編集

str の宣言の仕方によってはコンパイルエラーにならないこともあります。 char str[] = "abc"; ではコンパイルエラーになりますが、 char s[] = "abc", *str = s; ではコンパイルエラーになりません。 前者の str の型は「char [4]」です。 後者の s の型は「char [4]」で、str の型は「char *」です。 どのようなコードを書いて中身の値の変化を確認したのですか?
carnage0216

2021/02/18 00:54

妄想であったためプログラムはありません。すいません。
carnage0216

2021/02/18 19:36

char *strはアドレスの「数値」ではなく、アドレスそのものを扱うとわかりました。
kazuma-s

2021/02/18 19:50

分かっていませんね。 「扱う」の主語は何ですか?「char *str」ですか? 「char *str」は宣言ですよ。宣言が何かを扱うことはありません。 宣言は変数がどういうものか指定するものです。 その変数を使って、何かを扱うのです。 「アドレス」とは何のアドレスですか? 意味のある文章にするなら、「char *str; で宣言されたポインタ変数 str は、ある変数のアドレスで初期化されると、*str でその変数を扱える」です。 「char *str; で宣言されたポインタ変数 str は、ある配列の要素のアドレスで初期化されると、 str 自身の値を変更して、配列の他の要素を扱える」です。
carnage0216

2021/02/18 19:57

>>char *str; で宣言されたポインタ変数 str は、ある変数のアドレスで初期化されると、*str でその変数を扱える すいません、私の頭でも理解できるようにもう少しかみ砕いて説明して頂けないでしょうか?
kazuma-s

2021/02/18 20:19 編集

「char *str; で宣言されたポインタ変数 str は」 str は初期化されていないので、str の値は不定です。 「ある変数のアドレスで初期化されると」 char c; で宣言された char型変数 c があったとします。これが「ある変数」です。 str = &c; でポインタ変数 str を c のアドレスで初期化します。 「*str でその変数を扱える」 *str は変数 c です。c を扱えます。 *str = '$'; で c に '$' が入ります。 printf("%c", *str); で c の値を表示できます。 かみ砕いてここで説明しました。 まだ疑問がありますか? 何が分からないのですか?
carnage0216

2021/02/18 20:28

では仮にchar *p; 「*p でその変数を扱える」 *p は変数 c です。c を扱えます。 *p = '$'; で c に '$' が入ります。 printf("%c", *p); で c の値を表示できます。 といいますが、変数とはアドレスなどの番号ではないのですよね? ならばなぜ*pはポインタの指すアドレスの値を取るのに、 strchr(str, '\0');の返り値(アドレスの番号)をなぜ受け入れられるのですか?char* p = strchr(str, '\0');のように strchr(str, '\0');はアドレスを返り値に出すので、左辺部はアドレスを受け入れる形でなければならないと考えています。それなのにどうしてアドレスの「値」を取る*pにしているのか解説を読んでもいまいちわからないのです。
kazuma-s

2021/02/18 21:14 編集

「変数とはアドレスなどの番号ではないのですよね?」 メモリ上に確保されたデータ領域に名前を付けた時、 その名前を変数名、データ領域を変数という。 メモリ上にデータ領域を確保したということは、 そのデータ領域のアドレスが確定したということ。 すなわち、変数のアドレスが確定した。 アドレスとは、メモリのある特定の位置を指定する値のこと。 変数はアドレスではないが、 アドレスが確定しているので「&変数」でそのアドレスを取得できる。 「*pはポインタの指すアドレスの値を取るのに」 ポインタはある変数のアドレスを持つことによって、その変数を指す。 ポインタがアドレスを指すのではない。 ポインタは変数のアドレスを持っているだけ。 ポインタが指すのは変数。ポインタが指すのはデータ領域。 p がある変数を指しているとき、*p はその変数である。 その変数の値を取り出すこともできるし、その変数の値を変更することもできる。 「strchr(str, '\0');の返り値(アドレスの番号)をなぜ受け入れられるのですか」 主語は何ですか? *p と読めますが、それは間違いです。 char* p = strchr(str, '\0'); という宣言における = は代入演算子ではなく、 初期化のための = なので、*p ではなく、宣言されている変数 p を初期化します。
carnage0216

2021/02/19 06:26

char *p = strchr(str,'¥0') (や他にはchar *pなど)と 変数宣言をした後、pはポインタ変数であり、このように変数宣言したため、*pはポインタが指定したアドレスの値を操作でき、 pは上の変数宣言によりポインタと扱えるためアドレスを扱える。そして、余談ですが&pはポインタ自体のアドレスを表している。 まぁ、たしかにchar pはただのポインタに全く関係ないpのchar型の変数宣言で、変数pに1バイトの1文字(1バイト)が入るだけですよってだけですからね。今までpとすればなんでもポインタのアドレスだと思っていましたが誤解が解決しました。本当にありがとうございます。 ちなみに、仮に一文字ではなく、文字列を表したい場合は先程のポインタで先頭アドレスを得てprintfと%sで表示するなり、配列char str[ ]のどちらかで表せばよいのですからね。 とりあえず正しいでしょうか? 結構考えてやっと出来たことなので、あまりきついことを言わずにとりあえず正しいといいなと、思います。
carnage0216

2021/02/19 11:48

あの今更なのですが str[i] と*(str + i)」とか「&str[i] と str + iと&*(str + i)ってポインタみたいに動くだけでポインタではなく配列ですよね?
kazuma-s

2021/02/19 11:55

文章が変です。 」 と 「 の対応が変です。 何が配列だと言っていますか? str[i] が配列ですか? &str[i] が配列ですか?
kazuma-s

2021/02/20 04:17

なぜ、返事がないんでしょうか? 例えば、「ハエトリソウの葉とかウツボカズラの葉って動物みたいに動くだけで動物ではなく植物ですよね?」という文章があったとします。 日本語が理解できる人なら、 「動くのは、葉。植物であるのは、ハエトリソウやウツボカズラ」 ということが分かりますよね。 carnage0216さんは、日本語がとても苦手で、日本語の読み書きがうまくできず、 入門書が読めず、質問の文章が書けない人なんですね。 元の質問の「str[i]のポインタのアドレス自体ではなく、」からあとは意味不明の文章です。 「str[i]のポインタ」って何ですか? 「ポインタのアドレス」って何ですか?
carnage0216

2021/02/20 07:42

ごめんなさい、通知が遅れていたみたいで気が付きませんでした。 str[i] が配列ですか?はい、配列です。 &str[i] が配列ですか?いいえ、配列str[i] の持つアドレスです、 >>例えば、「ハエトリソウの葉とかウツボカズラの葉って動物みたいに動くだけで動物ではなく植物ですよね?」という文章があったとします。 日本語が理解できる人なら、 「動くのは、葉。植物であるのは、ハエトリソウやウツボカズラ」 ということが分かりますよね。 確かにここでの「プログラミング」に関する日本語の文章はおかしい部分が多いと思います。 ですが、それはなんか失礼だなあと思いました。プログラミングとは関係なくそのくらいはさすがに理解できますよwww プログラミングに関するの専門用語や動きが難しいだけで。 >>「str[i]のポインタ」って何ですか?str[i]はただの配列なのでポインタなどは扱わないと理解しています。 >>「ポインタのアドレス」って何ですか?例えば、int *pとポインタの変数宣言をされた際の、ポインタpが指すアドレスのことです。
guest

0

str[i] と*(str + i) および &str[i] と str + iと&*(str + i) は同じですか?

YES

それぞれを日本語で説明するとこんな感じ。
fanaさんの指摘を受け、修正

str[i]    →str配列のi番目の要素の値
(str + i)  →str配列の先頭アドレスにiを加算したアドレスの中身の値
&str[i]    →str配列のi番地のアドレス
str + i    →str配列の先頭アドレスにiを加算したアドレス
&
(str + i)  →str配列の先頭アドレスにiを加算したアドレスの中身の値のアドレス

サンプルも併せて記載

C

1#include <stdio.h> 2int main(void){ 3 // Your code here! 4 char str[5]={"abcde"}; 5 int i; 6 for(i = 0; i < 5; i++){ 7 printf("%c\n", str[i]); 8 printf("%c\n", *(str + i)); 9 printf("0p%x\n", &str[i]); 10 printf("0p%x\n", str + i); 11 printf("0p%x\n", &*(str + i)); 12 } 13} 14 15出力結果 16a 17a 180x7ffc155edf10 190x7ffc155edf10 200x7ffc155edf10 21b 22b 230x7ffc155edf11 240x7ffc155edf11 250x7ffc155edf11 26c 27c 280x7ffc155edf12 290x7ffc155edf12 300x7ffc155edf12 31d 32d 330x7ffc155edf13 340x7ffc155edf13 350x7ffc155edf13 36e 37e 380x7ffc155edf14 390x7ffc155edf14 400x7ffc155edf14

投稿2021/02/15 07:00

編集2021/02/15 07:57
kaina

総合スコア418

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

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

fana

2021/02/15 07:17

> アドレスの値 と書くと, アドレス値 という意味に読めてしまいます. > i番目のアドレス 等も微妙な表現に思えます. (面倒なことですが)
carnage0216

2021/02/15 11:50

ありがとうございます。 >str[i] と*(str + i) および &str[i] と str + iと&*(str + i) は同じですか? YES とのことですが、 「str[i] と*(str + i)」が同じ、「&str[i] と str + iと&*(str + i)」が同じという解釈と言われました。 プログラムを拝見するとstr[i] と*(str + i)がアドレスの中身を表し、&str[i] と str + iと&*(str + i)がアドレス自体を表すとわかりました。 そして、各 「printf("%c\n", str[i]); printf("%c\n", *(str + i)); printf("0p%x\n", &str[i]); printf("0p%x\n", str + i); printf("0p%x\n", &*(str + i));」 が+iされることでアドレスの中身の文字と、アドレス自体の数値が変化することがわかりました。
carnage0216

2021/02/15 11:57 編集

ちなみに、なぜアドレス自体を表示するときの演算子は0p%xなのですか?文字列を表す%sでは駄目なのですか?
kaina

2021/02/15 12:00

失礼、以下の間違いです。 printf("%p\n", &str[i]); printf("%p\n", str + i); printf("%p\n", &*(str + i)); 参考URL https://www.mm2d.net/main/prog/c/printf_format-01.html ただ、質問をする前に自分で試してみましたか? 書式指定子部分を%sや%cに変更すればすぐ動作確認が可能ですが、何故試してみないのですか?
carnage0216

2021/02/15 21:27

例題の通り、 変数str自体はiの変化により変化するという理解で正しいでしょうか?
kaina

2021/02/16 00:16

変数strではなく、str[5]でchar型の配列ですよ? 通常の変数と配列で定義した変数がごっちゃになっていませんか? 配列なので当然str[0]、str[1]、str[2]、str[3]・・・とchar型の変数を複数個持っており、 それぞれの要素の値を取得する場合は[]の中の添え字の値を変更するか ポインタを使って要素の値を取得するかのいずれかの方法を取っているだけです。 但し、C言語では色々な記述方法が出来るだけです。 変数とは何か、配列とは何か、ポインタとは何か、アドレスとは何か、 もっと本質を理解するようにして下さい。
kaina

2021/02/16 00:35

そもそもあなたのこれまでの質問内容を見るとプログラムの一部分を指して これが分からないから教えて欲しい、あれが分からないから教えて欲しいというような 内容ばかりですが、プログラムの一部の書き方だけを理解しようとしているから 何時まで経っても同じような質問の繰り返しになるのです。 何度も書きますが、もっと本質を理解するようにして下さい。 そうすればプログラムの一部の書き方のみを質問するような無駄な質問は 出てこないようになるはずです。
carnage0216

2021/02/16 00:46

おっしゃる通りです。 そのためにもこれでも本を読んでサイトを漁って、デバッグを何度もしています。 言い訳ではないですが、まだまだなんだなと痛いほど実感しています。
kaina

2021/02/16 01:06

だったら今のようなやり方ではなく、以下のサイトのように簡単なテスト用プログラムを作成し、 メモリ空間上に変数がどのように取られるのかを一つ一つデバッグして変数の中身やアドレスを 確認しながら自分で図に書き落としてみましょう。 https://daeudaeu.com/pointer/ 以下の内容を自分でテストプログラムを作成し、変数の値、アドレスをデバッグで確認した内容を 図に書いてみて、動作を一つ一つ確認して下さい。 そうすれば本質の理解が出来るはずです。  通常の変数  配列  ポインタ  構造体  関数の引数(値渡しとポインタ渡し)
carnage0216

2021/02/16 01:15

ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問