//OK
char **Str = new char*[Num];
////////////////////////////////////////
//実行時エラー
char **Str;
**Str = new char*[Num];
どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?からの分岐トピックです。分岐点はここから[80189]のbeatleさんまで、からです
//OK
char **Str = new char*[Num];
////////////////////////////////////////
//実行時エラー
char **Str;
**Str = new char*[Num];
この書き方が混乱の元になっています。
こちらは、char**型のStrに関節参照演算子*を二つくっつけています。
図にして見ました。
+------------+ +------------+ +-------------+
| char** Str | → | char * | → | char |
+------------+ +------------+ +-------------+
(1) x1=Str (2) x2=*Str (3) x3=**Str
これは良く分かります。
たかぎさんや初級者Bさんに教えていただいたのがなかったら(講座だけだったら)多分、「そうなんだ」と判った気になって受け取るだけだったでしょうね。softya(ソフト屋) さんが書きました:解説すると
(1)の値が確定しないと(2)のアクセスが出来ません。
(1)と(2)の値が確定しないと(3)のアクセスが出来ません。
**Str = new char*[Num];
は(3)から始めようとしているので(1)と(2)の値が確定していない訳です。
これをやって・・・・・・・・・・・・・softya(ソフト屋) さんが書きました:beatleさんが書いた
char *var2[4];
char (*var3)[4];
を図にしてみましょう。
char *var2[4];-------->(char* var)が[4]
+-----------------+ +------+
| char* var2[4] | -> | char |
+-----------------+ +------+
(1) x1 = var2[4] (2)x2 = *var2
char (*var3)[4];-------->(char var[4])の*var3
+------------+ +--------------+
| char* var3 | -> | char var3[4] |
+------------+ +--------------+
(1)x1 = var3 (2)x2 = *var3[4]
char *var2[4];-------->(char* var)が[4]
var2 = {"文字列1","文字列2","文字列3","文字列4"}
*var2----->"文字列1"のアドレス
char (*var3)[4];-------->(char var[4])の*var3
var3 = {'A','B','C','\0'}
*var3 = 'A'のアドレス
私の書き方も悪かったので訂正します。
●char **Str;
+------------+ +------------+ +--------+
| char** Str | → | char*[0] | -> | char[] |
+------------+ +------------+ +--------+ +--------+
| char*[1] | -------------------> | char[] |
+------------+ +--------+
| : |
| : |
+------------+ +--------+
| char*[n] | --------------> | char[] |
+------------+ +--------+
char*[n]がそれぞれの指すアドレスはバラバラです。
●char *var2[4]; -------->(char* var2)が[4]
+------------+ +--------+
| char*[0] | -> | char[] |
+------------+ +--------+ +--------+
| char*[1] | -------------------> | char[] |
+------------+ +--------+ +--------+
| char*[2] | -> | char[] |
+------------+ +--------+ +--------+
| char*[3] | --------------> | char[] |
+------------+ +--------+
char*[n]がそれぞれの指すアドレスはバラバラ。
●char (*var3)[4];
+-------------+ +------------+
| char (*)[4] | -> | char[0][0] |
+-------------+ +------------+
| char[0][1] |
+------------+
| char[0][2] |
+------------+
| char[0][3] |
+------------+
| char[1][0] |
+------------+
| char[1][1] |
+------------+
| char[1][2] |
+------------+
| char[1][3] |
+------------+
#include <iostream>
using namespace std;
int main(void)
{
// 宣言
char (*var3)[4];
char *var4;
// 動的確保
var3 = new char[2][4];
var4 = new char[4];
// 初期化
for( int i=0 ; i<4 ; i++ ) {
for( int j=0 ; j<2 ; j++ ) {
var3[j][i] = i + j*10;
}
}
var4 = var3[1];
// 出力
for( int j=0 ; j<2 ; j++ ) {
for( int i=0 ; i<4 ; i++ ) {
cout << "var3[" << j << "][" << i << "] = " << (int)var3[j][i] << endl;
}
}
for( int i=0 ; i<4 ; i++ ) {
cout << "var4[" << i << "] = "<< (int)var4[i] << endl;
}
}
#include <iostream>
using namespace std;
int main(void)
{
// 宣言
char (*var3)[4];
char *var4;
// 動的確保
var3 = new char[3][4];
var4 = new char[4];
// 初期化
for( int j=0 ; j<3 ; j++ ) {
for( int i=0 ; i<4 ; i++ ) {
var3[j][i] = i + j*10;
}
}
var4 = var3[2];
// 出力
for( int j=0 ; j<3 ; j++ ) {
for( int i=0 ; i<4 ; i++ ) {
cout << "var3[" << j << "][" << i << "] = " << (int)var3[j][i] << endl;
}
}
for( int i=0 ; i<4 ; i++ ) {
cout << "var4[" << i << "] = "<< (int)var4[i] << endl;
}
}
それは凄いですねwbeatle さんが書きました:なんでC++ではprintfじゃなくて,あんな面倒な書き方をするのかというと,C++の書き方のほうが安全だからです.
printfを使うとき,書式指定子と違った型の値を渡してもコンパイルエラーにはなりませんが,実行時におかしな値が表示されますよね?例えば%dなのにdouble型を渡しちゃったり.
coutならそういうエラーがないのです.
それはそうなんですが、あくまでポインタが理解できたかの課題なのでbeatle さんが書きました:合ってるかどうかは課題を実行してみれば分かることでは・・・?
gccなら-Wformatオプションで警告を出せます。beatle さんが書きました:なんでC++ではprintfじゃなくて,あんな面倒な書き方をするのかというと,C++の書き方のほうが安全だからです.
printfを使うとき,書式指定子と違った型の値を渡してもコンパイルエラーにはなりませんが,実行時におかしな値が表示されますよね?例えば%dなのにdouble型を渡しちゃったり.
coutならそういうエラーがないのです.