木を植えるのに最適な時期は10年前で、今がそれに続きます。
ポインタと配列
1つ、ポインタ操作
ポインタは次の3つの操作を実行できます。
1.ポインターと整数:
ポインタpが配列a [i]を指している場合、ポインタp + jはa [i + j]を指します(a [i + j]が存在する場合)。
2.ポインタから整数を引いたもの:
ポインタpが配列a [i]を指している場合、ポインタp-jはa [i-j]を指します(a [i-j]が存在する場合)。
3. 2つのポインターの加算と減算(2つのポインターは同じ変数を指している必要があります!!!そうでない場合、操作は無意味です!)
2つのポインターを引くと、結果はメモリー内のポインターの距離になります。これは、配列要素の数で測定できます。したがって、ポインターpがa [i]を指し、qがa [j]を指す場合、 pqはi-jと同じです。
ポインターの比較:ポインターは、> <=> = <= ==!=などの記号を使用して比較できます(ポインターが同じ配列を指している場合のみ、関係演算子を使用したポインターの比較は意味があります!)
2つ目は、配列処理にポインターが使用されることです。
ポインタの算術演算により、ポインタをインクリメントおよびデクリメントすることで配列の要素にアクセスできます。
#include<stdio.h>
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int *p;
for(p = &a[0];*p < a[10];p++)
{
printf("%d\n",*p);
}
return 0;
}
配列の添え字を使用すると、ポインターなしでループを記述できます。ポインターを使用すると時間を節約できるという議論がありますが、現在のコンパイラーでは、添え字を使用するループは実際には自動的に最適化されます。つまり、添え字に依存するループはより良いコードを生成します(大物は[ ^。^])
* ++との併用:
#include<stdio.h>
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = &a[0];// *p = a;
while (*p < a[10])
{
printf("%d\n",*p++);
}
return 0;
}
もちろん、* ++ p、(* p)++があります
3つ目は、配列名をポインターとして使用する
1.配列名は、配列の最初の要素へのポインターとして使用できます。たとえば、int a [10]; * a = 7;これは、a [0]要素に7を割り当てるためのものです。通常、a + iは&a [i]と同等であり、*(a + i)はa [i]と同等です。
2.配列変数自体がアドレスを表すため、配列を使用して、アドレス記号int a [10]; int * p = a;を使用せずにポインターを初期化します。ただし、配列の各要素は変数を表し、アドレス文字&を使用する必要があります。
3. []はポインターに対しても実行でき、p [0]はa [0]と同等です。*配列でも実行できます。* aはa [0]と同等です。
注:配列変数がconst型のポインターである場合、割り当てることはできません。
4.関数パラメーターとしての配列
面白いことを見てみましょう(それは素晴らしいです!):
#include<stdio.h>
void test1(int a[]);
int main()
{
int a[5] = {0,1,2,3,3};
printf("main中sizeof(a[]) = %lu\n",sizeof(a));
test1(a);
return 0;
}
void test1(int a[])
{
printf("函数中sizeof(a[]) = %lu\n",sizeof(a));
}
操作の結果は次のとおりです。
関数test1でsizeofによって渡された配列では、そのバイトサイズが8であることがわかります。配列自体のバイトサイズ20の代わりに!興味深いハハハハQAQ。これは、パラメーターとして渡された配列がポインターであるためです。つまり、前に述べた配列変数は特別なポインターです。配列名は、関数に渡されるときに常にポインターとして扱われます。
これは私たちにとって非常に重要です!:
(1)通常の変数を関数に渡す場合、変数の値がコピーされ、対応する仮パラメーターへの変更は変数に影響しません。配列を実際のパラメーターとして変更できます(constでない限り)!
(2)配列を関数に渡す時間と配列のサイズの間に関係はありません!(コンパイラ:「あなたの配列をまったくコピーしませんでした、私はそれを予期していませんでした!ハハハ」)
(3)必要に応じて、配列パラメーターをポインターとして宣言できます。(コンパイラーの配列とポインターの宣言は完全に同じです)
注:仮パラメーターの場合、配列として宣言することはポインターとして宣言することと同じですが、変数の場合、配列として宣言することはポインターとして宣言することとは異なります。
5.ポインタ名を配列名として使用します(次のコード)
#include<stdio.h>
int main()
{
int a[10],*p = a, i = 0;
for(i = 0;i < 10;i++)
{
*p++ = i;
printf("%d\n",a[i]);
}
return 0;
}
第四に、ポインタと多次元配列
int a[4][5] = {
{0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
これは、4つの行要素を含む配列として理解できます:a [0]、a [1]、a [2]、a [3]、a [0]を置くことができます
もう1つ覚えておくべきことは、配列名の最初の要素のアドレスです。aはa [0] [0]のアドレスではないということわざがありますが、試してみたところ、同じアドレスであるため、一文にまとめることができます。配列名はアドレスです。最初の要素の。
行ポインタ:2次元配列の各行は、1次元配列と見なされ、各行の1次元配列へのポインタと見なされます。
多次元配列の行を処理します。
#include<stdio.h>
int main()
{
int a[4][5] = {
{0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
int *p,i = 0,j = 4;
i = 3;
for (p = a[i];p < a[i] + j;p++)//p = a[i]给p初始化.p < a[i] + j 中a[i]+j表示的是a[i][j]
{
*p = 0;
}
printf("%d\n",a[i][2]);//输出验证第i行第2列是否为0
return 0;
}
p ++を1回実行すると、p +1と同等になります。これはa [i] +1と同等であり、a [i] [1]と同等です。
多次元配列の列の処理:
#include<stdio.h>
int main()
{
int a[4][5] = {
{0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
int (*p)[5],i = 2;//(*p)的括号不可省略![5]这个表示的是一维数组的长度,不可省略!定义了一个行指针,其宽度为5(即二维数组的列数为5)
for ( p = &a[0]; p < &a[4];p++)//p=&a[0]是把第0行那个一行的一维数组的地址交给p这个行指针 &a[4]相当于a+4. p=&a[0]相当于p=a
{
(*p)[i] = 0;//(*p)这里代表着a的一整行
}
printf("%d\n",a[2][i]);//输出验证第2行第2列是否为0
return 0;
}