c/c++誤りやすい知識点整理3(引用とポインタ)(一)
4787 ワード
1.一般変数
#include
出力結果:20,20100,20,1
rnをaの参照として宣言し、rnにメモリユニットを別途開く必要はありません.rnとaはメモリ内の同じメモリセルを占め、同じアドレスを有する.
2.ポインタ変数参照
出力結果:a=2,b=10,*p=2,a=2,b=11,*p=11
3.コードを見てエラーを探す---変数参照
参照は宣言時にのみ付与され、以降はその参照名を他の変数名の別名として使用することはできません.
4.2つの文字列を交換する方法
ここでswap関数はポインタ参照を用いて文字列交換を実現する.swap関数はポインタ参照タイプであるため,伝達関数は実パラメータであり,形パラメータではない.
ポインタ参照を使用しない場合、ポインタ交換はswap関数でのみ有効です.なぜなら、関数スタックでは、2つの一時的なポインタ変数がそれぞれ2つのポインタ一時パラメータを指し、実際のapおよびbpには影響しないためです.
もちろん、参照を必要としない場合は、2 Dポインタで同じ目的を達成することもできます.swap関数の定義を次の形式に変更できます.
呼び出し関数形式swap 1(&ap,&bp);
このようなアドレス方式では,同様に2つの文字列を交換する目的を果たすことができる.
5.パラメータ参照
ここでfloat&b=f 1()エラー.f 1()関数では、グローバル変数fの値78.5がコンパイラによって暗黙的に確立された一時変数tempに与えられるため、このtemp変数はコンパイラによって暗黙的に確立され、このtempの参照bが確立される.ここで一時変数tempを参照するとエラーが発生する.
定数参照タイプパラメータ、すなわちconst type&またはtype const&は、関数内で変更できません.
定数タイプの変数の場合、その参照も定数タイプでなければなりません.非常量タイプの変数について.その参照は、非常に量的でも定数的でもよい.ただし、定数参照を使用して参照する変数の値を変更することはできません.
6.ポインタと引用の違い
(1)初期化の要件は異なります.参照は作成と同時に初期化する必要があります.すなわち、有効なオブジェクトに参照します.ポインタは定義時に初期化する必要はありません.定義の後の任意の場所で値を再割り当てできます.
(2)変更可能性が異なります.参照が1つのオブジェクトを指すように初期化されると、別のオブジェクトの参照に変更することはできません.ポインタはいつでも別のオブジェクトを指すように変更できます.参照に値を割り当てるのは、元のオブジェクトとのバインド関係を変更することではありません.
(3)NULL参照は存在せず、参照は空の値を指す参照を使用することができず、常にオブジェクトを指す必要がある.ポインタはNULLであってもよく、常に特定のオブジェクトを指す必要はなく、任意のオブジェクトを指すことができるので、ポインタはより柔軟で、エラーも発生しやすい.
(4)必要な違いをテストします.参照は空の値を指さないため、参照を使用する前にその正当性をテストする必要はありません.ポインタは常にテストする必要があります.したがって、参照を使用するコードの効率はポインタを使用するよりも高いです.
(5)適用の違い.1つのオブジェクトを指すと指向が変更されないことを意味する場合は、参照を使用します.NULL(オブジェクトを指さない)または異なる時点で異なるオブジェクトを指す可能性がある場合は、ポインタを使用します.
実際、言語の面では、引用の使い方は対象と同じです.バイナリレベルでは、リファレンスは一般的にポインタで実現されますが、コンパイラが変換を完了してくれました.全体的に、参照はポインタの効率と変数の使用の利便性と直感性を有する.
7.なぜリファレンスはポインタより安全なのか
空の参照は存在せず、参照がオブジェクトを指すように初期化されると、別のオブジェクトの参照に変更できないため、参照は安全です.
ポインタの場合、いつでも他のオブジェクトを指すことができ、初期化されていないか、NULLであるため、安全ではありません.constポインタはまだ空のポインタが存在し、野ポインタを生成する可能性があります.
8.複雑なポインタの宣言
変数aで以下の定義を与える
a.整数数
b.整数を指すポインタ
c.ポインタを指すポインタであり、そのポインタは整数数を指す
d.10個の整数数の配列
e.整数数を指す10個のポインタの配列
f.10個の整数配列を指すポインタ
g.整数パラメータを有し、整数数を返す関数を指すポインタ
h.10個のポインタを有する配列であって、このポインタは1つの関数を指し、この関数は1つの整数パラメータを有し、1つの整数数を返す
a.int a
b.int* a
c.int** a
d.int a[10]
e.int* a[10]
f.int (*a)[10]
g.int(*a)(int)
h.int (*a[10])(int)
9.ポインタ加減操作
出力:2;5
ポインタに1を加えると、元のアドレス値ではなく次の要素のアドレスが得られます.したがって、1つのタイプtのポインタの移動は、sizeof(t)を移動単位とする.
コード6行目、ptrはint型のポインタ&a+1、すなわちaを取るアドレスであり、このアドレスの値にsizeof(a)の値、すなわち&a+5*sizeof(int)、すなわちa[5]のアドレスを加算し、明らかに現在のポインタは配列の限界を越えている.(int*)(&a+1)は、前のステップで計算したアドレスを強制的にint*タイプに変換し、ptrに値を付与する.
10.ポインタ比較
0,0,1,1,1
このプログラムはメモリ内の各データの格納方法を調べている.
配列str 1、str 2、str 3、str 4はすべてスタックに割り当てられ、メモリの内容はすべて「abc」に「0」を追加しますが、それらの位置は異なります.
ポインタstr 5、str 6、str 7、str 8もスタック上で割り当てられ、それらはすべて「abc」文字列を指し、「abc」がデータ領域に格納されていることに注意し、str 5、str 6、str 7、str 8は実際には同じデータ領域のメモリを指す.
#include
#include
using namespace std;
int main()
{
int a=10;
int b=20;
int &rn=a;
int equal;
rn=b;
cout<
出力結果:20,20100,20,1
rnをaの参照として宣言し、rnにメモリユニットを別途開く必要はありません.rnとaはメモリ内の同じメモリセルを占め、同じアドレスを有する.
2.ポインタ変数参照
#include
using namespace std;
int main()
{
int a=1;
int b=10;
int* p=&a;
int* &pa=p; // p pa
(*pa)++;
cout<
出力結果:a=2,b=10,*p=2,a=2,b=11,*p=11
3.コードを見てエラーを探す---変数参照
#include
using namespace std;
int main()
{
int a=1,b=2;
int &c; // , , 。
int &d=a;
&d=b; // , d b
int *p;
*p=5; // , p ,p ,
return 0;
}
参照タイプの変数は、宣言とともに初期化する必要があります.参照は宣言時にのみ付与され、以降はその参照名を他の変数名の別名として使用することはできません.
4.2つの文字列を交換する方法
void swap(char *&x,char *&y)
{
char *temp;
temp=x;
x=y;
y=temp;
}
ここでswap関数はポインタ参照を用いて文字列交換を実現する.swap関数はポインタ参照タイプであるため,伝達関数は実パラメータであり,形パラメータではない.
ポインタ参照を使用しない場合、ポインタ交換はswap関数でのみ有効です.なぜなら、関数スタックでは、2つの一時的なポインタ変数がそれぞれ2つのポインタ一時パラメータを指し、実際のapおよびbpには影響しないためです.
もちろん、参照を必要としない場合は、2 Dポインタで同じ目的を達成することもできます.swap関数の定義を次の形式に変更できます.
void swap1(char **x,char **y)
{
char *temp;
temp =*x;
*x=*y;
*y=temp;
}
呼び出し関数形式swap 1(&ap,&bp);
このようなアドレス方式では,同様に2つの文字列を交換する目的を果たすことができる.
5.パラメータ参照
#include
const float pi=3.14f;
float f;
float f1(float r){
f=r*r*pi;
return f;
}
int main()
{
float f1(float=5);
float& b=f1();
}
ここでfloat&b=f 1()エラー.f 1()関数では、グローバル変数fの値78.5がコンパイラによって暗黙的に確立された一時変数tempに与えられるため、このtemp変数はコンパイラによって暗黙的に確立され、このtempの参照bが確立される.ここで一時変数tempを参照するとエラーが発生する.
定数参照タイプパラメータ、すなわちconst type&またはtype const&は、関数内で変更できません.
定数タイプの変数の場合、その参照も定数タイプでなければなりません.非常量タイプの変数について.その参照は、非常に量的でも定数的でもよい.ただし、定数参照を使用して参照する変数の値を変更することはできません.
6.ポインタと引用の違い
(1)初期化の要件は異なります.参照は作成と同時に初期化する必要があります.すなわち、有効なオブジェクトに参照します.ポインタは定義時に初期化する必要はありません.定義の後の任意の場所で値を再割り当てできます.
(2)変更可能性が異なります.参照が1つのオブジェクトを指すように初期化されると、別のオブジェクトの参照に変更することはできません.ポインタはいつでも別のオブジェクトを指すように変更できます.参照に値を割り当てるのは、元のオブジェクトとのバインド関係を変更することではありません.
(3)NULL参照は存在せず、参照は空の値を指す参照を使用することができず、常にオブジェクトを指す必要がある.ポインタはNULLであってもよく、常に特定のオブジェクトを指す必要はなく、任意のオブジェクトを指すことができるので、ポインタはより柔軟で、エラーも発生しやすい.
(4)必要な違いをテストします.参照は空の値を指さないため、参照を使用する前にその正当性をテストする必要はありません.ポインタは常にテストする必要があります.したがって、参照を使用するコードの効率はポインタを使用するよりも高いです.
(5)適用の違い.1つのオブジェクトを指すと指向が変更されないことを意味する場合は、参照を使用します.NULL(オブジェクトを指さない)または異なる時点で異なるオブジェクトを指す可能性がある場合は、ポインタを使用します.
実際、言語の面では、引用の使い方は対象と同じです.バイナリレベルでは、リファレンスは一般的にポインタで実現されますが、コンパイラが変換を完了してくれました.全体的に、参照はポインタの効率と変数の使用の利便性と直感性を有する.
7.なぜリファレンスはポインタより安全なのか
空の参照は存在せず、参照がオブジェクトを指すように初期化されると、別のオブジェクトの参照に変更できないため、参照は安全です.
ポインタの場合、いつでも他のオブジェクトを指すことができ、初期化されていないか、NULLであるため、安全ではありません.constポインタはまだ空のポインタが存在し、野ポインタを生成する可能性があります.
8.複雑なポインタの宣言
変数aで以下の定義を与える
a.整数数
b.整数を指すポインタ
c.ポインタを指すポインタであり、そのポインタは整数数を指す
d.10個の整数数の配列
e.整数数を指す10個のポインタの配列
f.10個の整数配列を指すポインタ
g.整数パラメータを有し、整数数を返す関数を指すポインタ
h.10個のポインタを有する配列であって、このポインタは1つの関数を指し、この関数は1つの整数パラメータを有し、1つの整数数を返す
a.int a
b.int* a
c.int** a
d.int a[10]
e.int* a[10]
f.int (*a)[10]
g.int(*a)(int)
h.int (*a[10])(int)
9.ポインタ加減操作
#include
int main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d
",*(a+1));
printf("%d
",*(ptr-1));
}
出力:2;5
ポインタに1を加えると、元のアドレス値ではなく次の要素のアドレスが得られます.したがって、1つのタイプtのポインタの移動は、sizeof(t)を移動単位とする.
コード6行目、ptrはint型のポインタ&a+1、すなわちaを取るアドレスであり、このアドレスの値にsizeof(a)の値、すなわち&a+5*sizeof(int)、すなわちa[5]のアドレスを加算し、明らかに現在のポインタは配列の限界を越えている.(int*)(&a+1)は、前のステップで計算したアドレスを強制的にint*タイプに変換し、ptrに値を付与する.
10.ポインタ比較
#include
using namespace std;
int main()
{
char str1[] ="abc";
char str2[] ="abc";
const char str3[]="abc";
const char str4[]="abc";
const char* str5 ="abc";
const char* str6 ="abc";
char* str7="abc";
char* str8="abc";
cout<
0,0,1,1,1
このプログラムはメモリ内の各データの格納方法を調べている.
配列str 1、str 2、str 3、str 4はすべてスタックに割り当てられ、メモリの内容はすべて「abc」に「0」を追加しますが、それらの位置は異なります.
ポインタstr 5、str 6、str 7、str 8もスタック上で割り当てられ、それらはすべて「abc」文字列を指し、「abc」がデータ領域に格納されていることに注意し、str 5、str 6、str 7、str 8は実際には同じデータ領域のメモリを指す.