勤勉であり、誰も待たないように何年も費やすことを奨励してください
C/C++ ゲーム開発
こんにちは、Jun Xi_ です。今日は、C 言語の基礎 0 から入門レベルの内容を更新していきます。今回の主な更新は、引き続き初級ポインタの基礎知識です。
- さっそく、直接始めてみましょう。!
ポインタの基本
1. ワイルドポインタ
概念: ワイルド ポインターは、ポインターが指す場所が不明であることを意味します (ランダム、不正確、明確な制限がない)。
1. ワイルドポインタの原因
-
- ポインタが初期化されていません
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
-
- ポインタの範囲外アクセス
#include <stdio.h>
int main()
{
int arr[10] = {
0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
-
- ポインタが指すスペースが解放されます
- ここではポインタ上級編で動的メモリを開放する場合について説明します。
2. ワイルドポインタを回避する方法
1. ポインタの初期化
2. ポインタが範囲外であることに注意してください
3. ポインタが指すスペースを解放し、時間内に NULL を設定します
4. ローカル変数のアドレスを返さないようにします
5. ポインタを使用する前に有効性を確認してください
第三种情况的使用例子
#include <stdio.h>
int main()
{
int *p = NULL;//在使用前先把指针置空防止为释放指针之前指向的空间
//....
int a = 10;
p = &a;
if(p != NULL)
{
*p = 20;
}
return 0;
}
2. ポインタ演算
1. ポインタ ± 整数
#define m 5
float values[m];
float* vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[m];)
{
*vp++ = 0;//把values数组中每个元素都初始化为0,这里指针++表示地址后移
}
2. ポインタ-ポインタ
//计算字符串的长度
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;//当p中读取到\0时说明该字符串总长度为此时的地址p-首元素地址s
}
3. ポインタの関係演算
for(vp = &values[m]; vp > &values[0];)
{
*--vp = 0;//由于是前置--,最后会与第一元素之前的元素比较
}
- 上記のコードには明らかな欠点があるため、単純化してみましょう。
for(vp = &values[m-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
- 実際、このタスクはほとんどのコンパイラで正常に完了できますが、標準では動作が保証されていないため、この方法で記述することは避けるべきです。
- 標準規制:
- 配列要素へのポインタは、配列の最後の要素の後のメモリ位置へのポインタと比較できますが、最初の要素より前のメモリ位置へのポインタとは比較できません。
3. ポインタと配列
- まず例を使用して配列とポインター間の接続を確立しましょう
#include <stdio.h>
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);//打印地址
printf("%p\n", &arr[0]);
return 0;
- 両方のアドレスが同じであることがわかります
- 配列名が配列の最初の要素のアドレスと同じであることがわかります。
- 結論は:
- 配列名は、配列の最初の要素のアドレスを表します。(前回のブログで紹介した2件を除き、リンクは以下の通りです: 【C言語初級】C言語で配列をいじって、バブルソート、バックギャモン、マインスイーピングを徐々に実現していきます)
- 次に、次のようなコードを書くことができます。
int arr[10] = {
1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
- 配列名はポインターのアドレスとして保存できるため、ポインターを使用して配列にアクセスできます。
- 例は次のとおりです。
#include <stdio.h>
int main()
{
int arr[] = {
1,2,3,4,5,6,7,8,9,0};
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr)/sizeof(arr[0]);
int i;
for(i=0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
}
return 0;
}
- したがって、p+i は実際に配列 arr の添字 i のアドレスを計算します。
その後、ポインタを介して配列に直接アクセスできます。 - 例は次のとおりです。
int main()
{
int arr[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
4. セカンダリポインタ
- ポインタ変数も変数であり、変数にはアドレスがありますが、ポインタ変数のアドレスはどこに格納されているのでしょうか?
- 答えは自明です - 二次ポインターです。
int main()
{
int a = 10;
int* p = &a;
int** pa = &p;
printf("%d\n", a);
printf("%d\n", *p);
printf("%d\n", **pa);
return 0;
}
-
3 つの値が同じであることがわかります。!
-
セカンダリ ポインターの操作は次のとおりです。
//*pa通过对pa中的地址进行解引用,这样找到的是p ,*pa 其实访问的就是p .
int b = 20;
*pa = &b;//等价于 p = &b;
//**pa 先通过* pa 找到 p, 然后对 p 进行解引用操作:*p ,那找到的是 a .
**pa = 30;
//等价于*p = 30;
//等价于a = 30;
5. ポインタの配列
- ポインタの配列はポインタですか、それとも配列ですか?
- は配列です。ポインタの配列です。
数组我们已经知道整形数组,字符数组。
int arr1[5];
char arr2[6];
- ポインターの配列についてはどうでしょうか?
int* arr3[5];//是什么?
- arr3 は 5 つの要素を持つ配列で、各要素は整数ポインターです。
- ポインタには配列ポインタと呼ばれるポインタ型もありますが、この2つのケースについてはポインタの上級編で紹介します。
要約する
-
今日の内容はここまでです。ワイルド ポインターの定義とその回避方法、ポインター演算のいくつかの形式、ポインターと配列の関係、二次ポインターなど、ポインターの基本的な部分をすべて紹介しました。皆さんがこのブログのコードを理解できれば幸いです。
-
質問がございましたら、コメント欄またはプライベート メッセージでお問い合わせください。また次回お会いしましょう。
新しいブロガーを作成するのは簡単ではありません。記事の内容が役立つと思われる場合は、離れる前にこの新しいブロガーをクリックするとよいでしょう。皆様の応援が更新の励みになります!!!
**(Ke Li はブロガーを 3 回連続でサポートするようお願いしています!!! 以下のコメントをクリックして「いいね」を押し、Ke Li を支援するために集めてください)**