この章の内容
親切なヒント
皆さんこんにちは、Cbiltpsです 私のブログでは、わかりにくい文章や言葉で表現しにくい要点などがある場合は、画像を載せています。なので、写真付きのブログはとても重要です!!!
私に興味があれば、私の最初のブログをご覧ください。
この章の要点
- 1次元配列の作成と初期化
- 1次元配列の使用
- メモリ内への 1 次元配列の保存
- 2次元配列の作成と初期化
- 2次元配列の使用
- メモリ内への 2 次元配列の保存
- 配列が範囲外です
- 関数パラメータとしての配列
- 配列の応用例 1: 3 つのチェス
- アレイの応用例 2: マインスイーパー ゲーム
本文の始まり
1. 1次元配列の作成と初期化
1.1 配列の作成
配列は、同じ型の要素のコレクションです。
配列の作成方法:
type_t arr_name [const_n];
//type_t 是数组的元素类型
//arr_name 是数组名
//const_n 是一个常量表达式,用来指定数组的大小
配列作成のインスタンス:
//代码1
int arr1[10];
//代码2
int count = 10;
int arr2[count];//注意:C99之后允许数组大小使用变量,叫变常数组
//代码3
char arr3[10];
float arr4[1];
double arr5[20];
注: 配列を作成するには、[]
その中に定数を指定する必要があり、変数は使用できません (C99 以前)。
1.2 配列の初期化
配列の初期化とは、配列の作成時に、配列の内容に適切な初期値を与えること (初期化) を指します。
コードを見てください:
int arr1[10] = {
1,2,3};//不完全初始化,剩余的默认初始化为0
int arr2[] = {
1,2,3,4};//这里的[]是没有指定大小,是根据初始化的内容确定它的值
char arr3[3] = {
'a',98, 'c'};//对于字符数组,中间的元素依旧是b,因为对应的ASCII码值是98
char arr4[] = {
'a','b','c'};//里面没有\0
char arr5[] = "abc";//注意:这个数组里的元素是a,b,c和\0
注: 配列が作成時に初期化されていない場合、それがローカル変数の場合、その中には何もありません (つまり、ランダムに割り当てられた値); グローバル変数の場合、デフォルトで 0 になります。
配列の作成時に、配列のサイズを指定したくない場合は初期化を行う必要があり、初期化の内容に応じて配列の要素数が決まります。
1.3 1次元配列の使用
[]
配列を使用するために、配列アクセス用の演算子である添字参照演算子を前に導入しました。
コードを見てみましょう:
#include <stdio.h>
int main()
{
int arr[] = {
1,2,3,4,5,6,7,8,9,10,11,12,13 };
int i = 0;
//计算数组元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
理解できない場合は、画像を見てください。
概要:
- 配列には、0 から始まる添え字を使用してアクセスします。
- 配列のサイズは計算できます。
int arr[10];
int sz = sizeof(arr)/sizeof(arr[0]);//这样计算数组的大小
1.4 メモリ内への 1 次元配列の保存
次に、メモリ内の配列の保存について説明します。
コードを参照してください:
#include <stdio.h>
int main()
{
int arr[] = {
1,2,3,4,5,6,7,8,9,10 };
int i = 0;
//计算数组元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("%p\n", &arr[i]);
}
return 0;
}
動作図は以下の通りです。
出力結果を注意深く観察すると、配列の添え字が増加するにつれて、要素のアドレスも規則的に増加することがわかります。このことから、配列はメモリに継続的に格納されている
と結論付けることができます。
2. 2次元配列の作成と初期化
2.1 2次元配列の作成
int arr[3][4];//表示三行四列
char arr[3][5];
double arr[2][4];
描画理解力:
2.2 2次元配列の初期化
int arr[3][5] = {
1,2,3,4,5,6,7,8,9,10,11};
int arr[3][5] = {
{
1,2},{
3,4},{
5,6}};
int arr[][5] = {
{
1,2},{
3,4},{
5,6}};//可以省略行,不能省略列
//以下是错误的演示
//int arr[3][] = {
{1,2},{3,4},{5,6}}; 错误一
//int arr[][5]; 错误二
char ch1[4][6] = {
'a', 'b' };
char ch2[4][6] = {
{
'a'},{
'b'} };
char ch3[4][6] = {
"abc", "def", "qwe"};
描画理解力:
2.3 2次元配列の使用
2 次元配列は添字を使用して使用することもできます。
#include <stdio.h>
int main()
{
int arr[3][5] = {
{
1,2,3},{
4,5},{
6,7,8,9,0} };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
操作結果:
2.4 メモリへの 2 次元配列の保存
1D 配列と同様に、ここでは 2D 配列の各要素のアドレスを出力してみます。
#include <stdio.h>
int main()
{
int arr[3][5] = {
{
1,2,3},{
4,5},{
6,7,8,9,0} };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("&arr[%d][%d]=%p ",i, j, &arr[i][j]);
}
printf("\n");
}
return 0;
}
実行結果は次のとおりです。
この結果から、実際には 2 次元配列もメモリに継続的に格納されていることが分析できます。
2 次元配列の理解:
これも確認二维数组在内存中是连续存储的
できます。
3. 範囲外の配列
配列の添え字は範囲が制限されています。
配列の添字は 0 から始まります。入力に n 個の要素がある場合、最後の要素の添字は n-1 になります。
したがって、配列の添字が 0 より小さいか、n-1 より大きい場合は、配列が範囲外にアクセスされ、アクセスが配列の有効な領域を超えていることを意味します。
C 言語自体は配列添字の範囲外チェックを実行せず、コンパイラーは必ずしもエラーを報告しません。ただし、コンパイラがエラーを報告しない場合は、プログラムが正しいことを意味するわけではないため、プログラマがコードを作成するときは、自分で範囲外チェックを行うのが最善です。
#include <stdio.h>
int main()//错误演示
{
int arr[5] = {
1,2,3,4,5 };
int i = 0;
//越界
for (i = 0; i <10; i++)
{
arr[i] = 0;//在这里赋值就会报错
}
return 0;
}
ここでのエラーは配列が範囲外であることが原因です。
注意:二维数组的行和列也可能存在越界。
4. 関数の引数としての配列
コードを書くとき、配列をパラメータとして関数に渡すことがよくあります。たとえば、整数配列をソートするバブル ソート(ここではアルゴリズムのアイデアについて説明します)関数を実装したいと考えています。
4.1 バブルソート機能の設計が間違っていた
このように関数を設計すると、次のようになります。
void BubbleSort(int arr[])
{
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//冒泡排序的趟数
for (i = 0; i < sz - 1; i++)
{
//冒泡排序的过程
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
//交换
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[] = {
9,8,7,6,5,4,3,2,1,0 };
BubbleSort(arr);
return 0;
}
ここで問題が発生します。デバッグ後、BubbleSort 関数内で sz == 1 であることがわかります。
配列を関数のパラメータとして使用する場合、配列全体が渡されるのではありませんか?
4.2 配列の名前は何ですか?
int main()
{
int arr[10] = {
1,2,3,4,5 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%d\n", *arr);
printf("-----------------");
printf("%p\n", arr + 1);
printf("%p\n", &arr[0] + 1);
printf("%d\n", *arr + 1);
return 0;
}
Parse の実行:
結論:
数组名是数组首元素的地址。(有两个例外)
しかし:
int arr[10] = {
0};
printf("%d\n", sizeof(arr));//当你这样输出结果发现,结果是:40?
補足:
- sizeof (配列名)、配列全体のサイズを計算し、sizeof の中に配列名を入れます。配列名は配列全体を表します。
- &配列名、配列のアドレスを取り出します。&Array name、配列名は配列全体を表します。
1 と 2 の 2 つのケースを除き、すべての配列名は配列の最初の要素のアドレスを表します。
4.3 バブルソート機能の正しい設計
配列がパラメータとして渡される場合、実際には、配列の最初の要素のアドレスのみが渡されます。
したがって、関数のパラメータ部分: に配列の形式で記述されていてもint arr[]
、ポインタ: を表しますint *arr
。
したがって、関数内の sizeof(arr) の結果は 4 になります。
では、(コードが完全に最適化された後) 関数はどのように設計されるべきでしょうか?
void BubbleSort(int arr[], int sz)//其实这里的int arr[]已经是指针了,相当于(int *arr[], int sz)
{
int i = 0;
//冒泡排序的趟数
for (i = 0; i < sz - 1; i++)
{
//冒泡排序的过程
int j = 0;
int flag = 1;//假设已经有序
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
//交换
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (1 == flag)
{
break;
}
}
}
void Print(int p[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", p[i]);
}
}
int main()
{
int arr[] = {
9,8,7,6,5,4,3,2,1,0 };
//不是传参的情况下,数组名单独放在fizeof内部的时候,
//如:sizeof(arr),这里的arr表示整个数组,不是首元素的地址。
int sz = sizeof(arr) / sizeof(arr[0]);
//数组名在传递给函数的时候,会降级变成首元素的地址
//数组传参---实际上传过去的是首元素的地址
BubbleSort(arr, sz);//数组传参
Print(arr, sz);
return 0;
}
5. 応用例
- 配列の応用例 1: 3 つのチェス
- アレイの応用例 2: マインスイーパー ゲーム
この部分については、別のブログを書いてその方法を説明します。
あまり紹介はしませんので、後ほど直接リンクを貼りますので、お楽しみに!