
現在C++を本で独学しており、ポインタの章を終えて配列の章を
学んでいるのですがでわからないところがあります。
『配列名は配列の先頭要素のアドレスをあらわす。』と習ったのですが、
下記のコードにての
#include <iostream>
using namespace std;
int main()
{
char str[] = "Hello";
cout << str << '/\';
return 0;
}
を実行すると"Hello"が出力されるとのことですが、
どうしてchar型配列strの要素をそのまま出力することになるのでしょうか?
この場合、『配列名は配列の先頭要素のアドレスをあらわす。』に
のっとれば出力されるのは「char型配列strの先頭要素のアドレス」に
なり、アドレスが出力されなければおかしいと思うのですが・・・?
同様に
#include <iostream>
using namespace std;
int main()
{
char* char = "Hello";
cout << str << '/\';
return 0;
}
のコードでもどうして間接参照演算子*さえ使わずに
strの要素を出力できるのかがさっぱりわかりません。
ご説明頂ければ幸いです。
No.4ベストアンサー
- 回答日時:
cout の << は。
その後の型によって何を表示するかが変わります。このような仕組をポリモーフィズムと言って、C++の重要な仕組の一つです。
他のポインタだと、そのアドレスを出力する、となっています。
対して、 char * だと「その示すアドレスから順番に、'\0'の前までの『文字』を出力する」となっています。
これは、以下のような理由があります。
・C++の元になったC言語では、「文字列型」というものが無く、「charの配列の先頭から'\0'の前までを文字列として扱う」というルールを使っている。
C++でも、そのルールを引き継いで、char * / char[] を文字列として扱うケースが多い。
・cout << にchar * を指定したとき、圧倒的に「文字列を出力したい」ケースが多い
アドレスを出力させたいのなら、char *でないポインタにキャストすることです。
そういう時は、汎用につかえる void * にキャストするのが常套手段です。
C言語由来の記法では (void * ) str と、(型)とします。
ですが、このキャストはなんでも有りすぎるので、C++ではC++専用のキャスト方法が用意されているので、そちらを使いましょう。
static_cast<void *>(str)
ご返答ありがとうございます。
>cout の << は。その後の型によって何を表示するかが変わります。
>このような仕組をポリモーフィズムと言って、C++の重要な仕組の一つです。
ポリモーフィズムの説明は使っている本の
私が今読んでいるところの後の章で
おそらくなされていることと思います。
私も以前に別のオブジェクト指向言語の書籍を読んだことがありましたが・・・
現在は「どんなものだったか?」の具体例を忘れてしまっておりまして(汗)
>他のポインタだと、そのアドレスを出力する、となっています。
>対して、 char * だと「その示すアドレスから順番に、
>'\0'の前までの『文字』を出力する」となっています。
そうだったのですね!
>C++の元になったC言語では、「文字列型」というものが無く、
>「charの配列の先頭から'\0'の前までを文字列として扱う」というルールを使っている。
はい。確かC言語ではstring型というものがなく、
char型の配列で文字列を扱っていたのだったと思います。
>アドレスを出力させたいのなら、char *でないポインタにキャストすることです。
>そういう時は、汎用につかえる void * にキャストするのが常套手段です。
先にご返答頂いていた、User20103さんもlong型にキャストすればよいと
仰られておりました。
>C言語由来の記法では (void * ) str と、(型)とします。
>ですが、このキャストはなんでも有りすぎるので、C++では
>C++専用のキャスト方法が用意されているので、そちらを使いましょう。
>static_cast<void *>(str)
「static_cast<void *>(str)」というこの構文は今日初めて目にしました。
まだこの構文の意味は私にはわかりませんが、疑問に感じていたところから
何歩か前進できた気がします。
No.7
- 回答日時:
>どうしてchar型配列strの要素をそのまま出力することになるのでしょうか?
C++が(ある意味)賢いからです
(賢くない) C言語 で同じ部分を書き直せば、配列とポインタの違いも納得できると思います。
それでもわからなければ、展開されたアセンブラコードを読まれると、C++が行っている「賢さ」に納得できると思います
No.6
- 回答日時:
こんな初歩的な段階で
オペレータオーバーローディングとかは
きついでしょ。
とりあえず、c++のCの部分だけを学習の対象にしては?
#include <stdio.h>
int main() {
char *greeting ="Hello";
printf("%s¥n", greeting);
return 0;
}
ご返答ありがとうございます。
>こんな初歩的な段階で
>オペレータオーバーローディングとかは
>きついでしょ。
>とりあえず、c++のCの部分だけを学習の対象にしては?
C言語は昔学習してみた経験がありますが、もう忘れている部分も
多いです(汗)
C++が最高難度レベルの難しい言語であるということは
承知してはいるのですが、私が今回C++の学習を始めたのは
『プログラマの考え方がおもしろいほど身につく本』という書籍を
入手しまして、いずれその本を読んでみたいと思ったからなのです。
(※この書籍の解説はC++のコードでなされています。)
ですが、
「構造化プログラミングの考え方はオブジェクト指向プログラミングを
学ぶ上で逆に障害となる」という声に賛否両論あるようですし
私も自分のレベルにあった学習段階がどこにあるのか?に
試行錯誤しております。
No.5
- 回答日時:
cout << の動作をきちんと理解するには、演算子オーバーロードの仕組みと、型継承におけるオーバーライドの仕組みの両方を理解していないと難しいと思いますよ。
std::coutはstd::ostreamクラスのオブジェクトで、<<はstd::ostream.operator<<というメンバ関数の呼び出しになります。このメンバ関数は引数の型ごとに異なる動作の関数がオーバーロードされていて、引数がchar*のときとint*のときとでは別の関数が呼ばれるのです。
ちなみにstd::ostream.operator<<は返値として自身への参照を返し、これにより次の<<を呼び出せるようになっています。
例えば
cout << str << '/\';
では、まず cout << str で str の中身が出力され、coutへの参照が返されます。このcoutへの参照に対して << '/\' が呼ばれ、'/\' が出力されます。ここでもcoutへの参照が返されますが、これは無視されます。
なお『配列名は配列の先頭要素のアドレスをあらわす。』は厳密には間違いです。多くの場合に先頭アドレスを示すのは事実ですが、違う場合もあります。
例えば
char str[] = "Hello";
と
char* str = "Hello";
では
sizeof(str)
の値が違います。
ご返答ありがとうございます。
>cout << の動作をきちんと理解するには、演算子オーバーロードの仕組みと、
>型継承におけるオーバーライドの仕組みの両方を理解していないと難しいと思いますよ。
cout << の動作に鍵があるのですね!
まだオーバーロード、オーバーライドの章まで読み進められておりません・・・。
そこまでたどり着いたら、また調べてみたいです。
>なお『配列名は配列の先頭要素のアドレスをあらわす。』は厳密には間違いです。
>多くの場合に先頭アドレスを示すのは事実ですが、違う場合もあります。
>例えば
>char str[] = "Hello";
>と
>char* str = "Hello";
>では
>sizeof(str)
>の値が違います。
!
そうなのですか!?
教えて頂きましたこちらは、知識として知っておきたいと思いました。
No.3
- 回答日時:
>配列名は配列の先頭要素のアドレスをあらわす
とは言ってるがそれをcoutでそのまま出力するとは言ってない
>char* char = "Hello";
これもポインターだからstrは先頭要素のアドレスが格納されてる
No.1
- 回答日時:
coutの<<はタイプがchar*だとnull文字まで出力するからです。
アドレスが見たければタイプをlongにキャストするのです。
char* str = "Hello";
cout << (long)(str) << endl;
char* も char[]も同じです。つまりこうしても結果は"e"です。
char* iampointer = "Hello";
cout << iampointer[1] << endl;
ご返答ありがとうございます。
せっかくお答え頂いたのに、私にはまだピンとこないのですが・・・
>coutの<<はタイプがchar*だとnull文字まで出力するからです。
>アドレスが見たければタイプをlongにキャストするのです。
char型の配列及びポインタの場合は
『配列名は配列の先頭要素のアドレスをあらわす。』の定義の
例外的で、longキャストして始めてアドレスが見られるということで
よろしいのでしょうか?
スミマセン・・・こんな短いコードなのに理解できない
自分が不甲斐ないです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C言語 少しの疑問 4 2022/11/08 02:48
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# str[j++]の意味 2 2022/08/30 16:20
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語 配列の長さの上限
-
銀行ATMの数字キーの配列
-
2次元配列でエラーがでます。
-
C言語Char型配列に小数値を入れ...
-
配列をEraseしてもメモリが開放...
-
C# Listを使わずに2次元配列の...
-
テキストファイルから文字列を...
-
C言語初心者 構造体 課題について
-
自販機での金銭収受を想定した...
-
アクセスランキングを作成する方法
-
C# 配列の変数宣言について。
-
配列で格納したものをmsgboxで...
-
シーケンスの解析に使うclustal...
-
配列とポインタについて。 配列...
-
【C言語】配列の中に配列を入れ...
-
C言語で特定列だけを抽出して配...
-
ゼロサプレスって?
-
vectorで文字列の配列を使う方法
-
配列を使わずに、変数名を動的...
-
ExcelVBAで質問です。離れた二...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語 配列の長さの上限
-
C# Listを使わずに2次元配列の...
-
配列を使わずに、変数名を動的...
-
配列で格納したものをmsgboxで...
-
【速いブラインドタッチ】手を...
-
配列をEraseしてもメモリが開放...
-
ExcelVBAで質問です。離れた二...
-
Redimした動的配列はEraseする...
-
C# 配列の変数宣言について。
-
複数の選択範囲の行番号を個別...
-
VBで構造体の配列を関数に渡す...
-
先頭アドレスとは何ですか?
-
配列の参照渡しで型が一致しま...
-
銀行ATMの数字キーの配列
-
配列を含む構造体の初期値について
-
C言語で特定列だけを抽出して配...
-
unsigned char配列への入力の仕方
-
VB.NET 構造体の配列の検索機能...
-
C++ vectorに配列をプッシュしたい
-
C言語初心者 構造体 課題について
おすすめ情報