C++における配列名とポインタの使い方の比較分析を検討する

4242 ワード

ポインタはC/C++言語の特色であり、配列名はポインタと似ていることが多く、配列名はポインタとして使用できることも多い.しかし、配列名にはポインタとは異なるところもあります.ここでは配列名とポインタの使い方の違いをまとめ(インターネットからの資料もある)、不適切な点を指摘してください.(本プログラムはWIN 32プラットフォームの下でコンパイルする):
1、配列名とその配列を指すポインタ、アドレスは同じですが、大きさの違いは例で説明します.
 
  
#include "stdafx.h"
#include
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
 int arr[10]={1,1,1,1,1,1,1,1,1,1};
 int* p=arr;
 cout< cout<

 cout< cout< return 0;
}


arrは配列名,pはポインタである.10,11行目に出力される値は同様であり,arrとpはいずれも配列のヘッダアドレスである.12行目、13行目の結果は異なり、arrのサイズは配列全体のサイズであり、pのサイズはポインタのサイズである.
2、配列名はポインタ定数とすることができ、自増(++)、自減(-)、修正することはできない.配列名がポインタではないことを証明しましたが、プログラムの9行目を見てみましょう.このロー・プログラムは、配列名をポインタに直接割り当てます.これは、配列名がポインタであるように見えます.配列名がポインタのように見える例もわかります.
 
  
#include "stdafx.h"
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
 char str1[10] = "I Love U";
 char str2[10];
 char *p = "I Love U";
 strcpy(str2,str1);
 cout << "string array 1: " << str1 << endl;
 cout << "string array 2: " << str2 << endl;
 cout << strlen(str1) << " " << strlen(str2) << " " << strlen(p) << endl;
 return 0;
}

プログラム出力:string array 1:I LoveU
string array 2: I Love U
8 8 8
標準Cライブラリ関数strcpyの関数原形に受け入れられる2つのパラメータはchar型ポインタですが、呼び出しで渡されるのは2つの配列名です.標準Cライブラリ関数strlen()は、パラメータが指す先頭アドレスから最初の'0'文字までの長さを返します.これらのプログラムでは配列名がポインタの役割を果たしている.この点配列名はポインタに似た性質を示しています!
しかし、次のコードは成立しますか?
int intArray[10];intArray++;読者はコンパイルすることができて、コンパイルの間違いを発見します.なぜなら、配列名は、エンティティを指すポインタに変換できますが、ポインタ定数としか見なされず、変更できません.ポインタは、構造体、配列、基本データ型を指すポインタにかかわらず、元のデータ構造の内包は含まれておらず、WIN 32プラットフォームではsizeof操作の結果は4である.ついでに多くのプログラマーのもう一つの誤解を直します.多くのプログラマーはsizeofが関数だと思っていますが、実際にはオペレータですが、その使い方は確かに関数のように見えます.文sizeof(int)はsizeofが確かに関数ではないことを説明することができる.関数はパラメータ(変数)を受け入れ、世界にはintのようなデータ型を「パラメータ」として受け入れるC/C++関数はないからだ.配列へのポインタは別の変数タイプ(WIN 32プラットフォームでは長さ4)であり、配列の格納アドレスのみを意味する
3、配列名は一種のデータ構造を指す:配列
int intArray[10];cout << sizeof(intArray) ;2行目の出力結果は40(整数配列が占めるメモリ領域サイズ)であった.
C/C++プログラムがこのように書くことができる場合:
int[10] intArray;cout << sizeof(intArray) ;intArrayはint[10]というデータ構造の一例として定義されていることがわかりますが、残念ながらC/C++は現在この定義方式をサポートしていません.
4、データ名は関数のパラメータとしての时にそのデータ构造の内包を失うことになる.ここには配列名の魔幻问题が円満に解决したようだが、穏やかな湖面には再び波が巻き起こっている.次のプログラムを見てください.
 
  
#include "stdafx.h"
#include
using namespace std;
 void arrayTest(char str[])
 {
  cout << sizeof(str) << endl;
 }
 int main(int argc, char* argv[])
 {
  char str1[10] = "I Love U";
  arrayTest(str1);
  return 0;
 }

プログラムの出力結果は4です.ありえないでしょう?恐ろしい数字で、針の長さについて前述しました!
結論1では,データ名は配列というデータ構造を内包し,arrayTest関数内でstrは配列名であるが,sizeofの結果はポインタの長さであるのはなぜであるかを指摘した.なぜなら、
(1)配列名が関数パラメータとして機能する場合、関数体内では、それ自体の内包を失い、ただのポインタである.
(2)残念ながら,その内包を失うとともに,その定数特性を失い,自己増加,自己減少などの操作が可能となり,修正される.
したがって,データ名が関数形パラメータとして機能すると,その全体が通常のポインタに転落する!その貴族の身分は奪われ、4バイトしか持たない庶民になった.
5、配列名aと&aの違いについて次の小さなプログラムを読み、プログラムの出力結果を書き出します.
 
  
#include "stdafx.h"
#include
using namespace std;
int main(int argc, char* argv[])
{
 int a[5] = {1,2,3,4,5};
 int *p1 = a + 1;
 int *p2 = (int *)(&a+1)-1;
 cout << *a << " " << *p1 << " " << *p2 << endl;
}

出力結果は:1 2 5解釈:配列名は配列のヘッダアドレスを表し、*aは配列の最初の要素の値1である.p 1は先頭アドレスに1を加え、2番目の要素を指し、2を出力する.一方*p 2=(int*)(&a+1)-1;aは配列のヘッダアドレスを表し、&aは配列のポインタ、&a+1はaを先頭とするアドレスを表し、1つの配列サイズ(ここでは5つのintのサイズ)をオフセットし、(int*)(&a+1)は配列の6番目の要素を指し、(int*)(&a+1)−1;配列の5番目の要素を指すため、出力は5である.
ここではaと&aの違いを重点的に区別します.