7. 配列(1次元配列、2次元配列、C99の可変長配列、二分探索法)

1. 配列の概念

配列は、同じ型の要素の集合です。その特徴は次のとおりです。
1. 配列には 1 つ以上のデータが格納されますが、配列要素の数が 0 になることはできません。
2. 配列に格納される複数のデータは同じ型です
。それらには 1 次元配列と多次元配列があり、ほとんどの配列は一般に 2 次元配列です。

2. 1次元配列

2.1 1次元配列の作成

形式: データ型 配列名 [定数値];
例 int num[10];

2.2 1次元配列の種類

配列名を削除すると、残るのは配列タイプです (例: int num[10])。配列タイプは int [10] です。配列要素のデータ型は、char、
int、float などです。データ型配列内の要素の一部は同じです。

2.3 1次元配列の初期化

//完全初始化
int num[5] = {
    
    1,2,3,4,5};

//不完全初始化,除了1 2 3,剩下的其余元素都默认为0
int num[5] = {
    
    1,2,3};

//初始化1 2 3,长度也为3
int num[] = {
    
    1,2,3};

2.4 1 次元配列の添字


C言語では配列アクセスに演算子[ ]が用意されており、これを添字参照演算子と呼びます配列定義時と配列要素呼び出し時の[ ]内の定数の違いに注意してください 定義中の
定数要素を表します。内部の定数の数は、
呼び出されたときの配列の添字を表します。つまり、インデックス
ビットの配列の添字は 0 からカウントされます。
ここに画像の説明を挿入します

例:

//注意区分 定义数组时 和 访问数组元素时 []的区别
int num[5] = {
    
    1,2,3,4,5};//这里num[5]表示的是数组长度为5
printf("数组下标为4的值:%d", num[4]);//这里num[4]表示的是访问数组下标为4的数组元素

出力結果
ここに画像の説明を挿入します

2.5 1次元配列の入出力

出力

//输出
int main() {
    
    
	int arr[9] = {
    
    1,2,3,4,5,6,7,8,9};
	for (int i = 0; i < 9; i++)//这里小于9是因为长度为9的数组 下标范围为0~8
	{
    
    
		printf("arr[%d] = %d\n",i,arr[i]);
	}
	return 0;
}

出力結果
ここに画像の説明を挿入します


入力

//输入
int main() {
    
    
	int arr[9];
	for (int i = 0; i < 9; i++)
	{
    
    
		scanf("%d",&arr[i]);
	}

	for (int i = 0; i < 9; i++)//这里小于9是因为长度为9的数组 下标范围为0~8
	{
    
    
		printf("arr[%d] = %d\n",i,arr[i]);
	}
	return 0;
}

結果を入力してください
ここに画像の説明を挿入します

2.6 1次元配列のメモリへの格納

1 次元配列のメモリ内の格納アドレスは、添字が増加するにつれて小さい値から大きい値に増加します。配列は
メモリに連続的に格納されます。整数配列を例にとると、隣接する 2 つの配列要素間の差は 4 です (なぜなら、整数は 4 バイトです)

int main() {
    
    
	int arr[9] = {
    
    1,2,3,4,5,6,7,8,9};
	for (int i = 0; i < 9; i++)
	{
    
    
		printf("arr[%d] = %p\n",i,&arr[i]);
	}
	return 0;
}

出力結果(32ビット(x86)環境の場合)
ここに画像の説明を挿入します

メモリに格納されているアドレスを16進数で表しており、int型のデータ要素であるため、各データ要素の差は4になります。

2.7 sizeof() を使用して配列要素の数を計算する

sizeof() 関数は C 言語のキーワードで
、型または変数のサイズを計算する機能です。
単位はバイトです。

配列内のすべての要素は同じデータ型であるため、各データ要素は同じサイズになります
つまり、占有されるメモリ空間の合計サイズ / 対応する配列要素のデータ型 = 配列内の要素の数

int main() {
    
    
	int arr[10] = {
    
    0};//这里我们就非完全初始化数组,所以我们不知道数组有多少个元素个数
	printf("数组 int arr[10] 所占内存空间的总大小:%zd 字节\n",sizeof(arr));
	printf("数组 int arr[10] 其中一个数组元素所占内存空间的大小:%zd 字节\n",sizeof(arr[0]));
	
	//所占内存空间总大小 / 对应数组元素的数据类型 = 数组内元素的个数
	int sum = sizeof(arr) / sizeof(arr[0]);
	printf("数组中元素的个数:%d", sum);

	return 0;
}

出力結果
ここに画像の説明を挿入します

3. 2次元配列

3.1 2次元配列の概念

2 次元配列: 1 次元配列を配列要素として使用するのと同じです。この場合、それは 2 次元配列です。類推すると、3 次元配列は 2 次元配列を組み合わせた配列です
。は配列要素として使用され、
2 次元配列以上の配列を総称して多次元配列と呼びます。

3.2 2次元配列の作成

形式: データ型 配列名 [定数値 1] [定数値 2];
例:
int num[10][10];
最初の 10 は配列が 10 行あることを意味し、
2 番目の 10 は各行に 10 個の配列要素があることを意味します

3.3 2次元配列の初期化

// 不完全初始化
int arr1[3][3] = {
    
    1,2,3};
int arr2[3][3] = {
    
    0};

// 完全初始化
int arr3[3][3] = {
    
    1,2,3, 4,5,6, 7,8,9};

//按照行初始化
int arr4[3][3] = {
    
    {
    
    1,2,3},{
    
    4,5,6},{
    
    7,8,9}};

//初始化时可以省略行,但是不能省略列
int arr5[][3] = {
    
     1,2 };
int arr6[][3] = {
    
     1,2,3,4,5};
int arr7[][3] = {
    
     {
    
    1,2},{
    
    4,5},{
    
    7,8} };

3.4 2 次元配列の添字

2 次元配列の行の添字は 0 から始まり、列の座標も 0 から始まります。
初期化の際、行は省略できますが、列は省略できません。
つまり、int man[can be省略][省略できません];

3.5 2次元配列の入出力

入力

	//输入
	for (int i = 0; i < 3; i++)//行号
	{
    
    
		for (int j = 0; j < 3; j++)//列号
		{
    
    
			scanf("%d ", &arr[i][j]);//记得加&
		}
	}

出力

	//输出
	for (int i = 0; i < 3; i++)//行号
	{
    
    
		for (int j = 0; j < 3; j++)//列号
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}

3.6 メモリへの 2 次元配列の保存

2 次元配列の各行の各要素は隣接しています。
整数を例にとると、行をまたがる接続
では、隣接する 2 つの配列要素の差は 4 バイトになります (整数は 4 バイトであるため)。各要素は 1 つだけです。
4 バイト異なるため、2 次元配列もメモリに連続的に格納されます。

int main() {
    
    
	int arr[3][3] = {
    
     {
    
    1,2,3},{
    
    4,5,6},{
    
    7,8,9} };
	for (int i = 0; i < 3; i++)//行号
	{
    
    
		for (int j = 0; j < 3; j++)//列号
		{
    
    
			printf("arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

出力結果
ここに画像の説明を挿入します

3.C99の可変長配列

C99規格以前では、C言語で配列を作成する場合、配列サイズを定数または定数式で表現するか、配列の初期化時に配列サイズを省略して配列要素を直接入力する必要がありました。

1.用常量来表示数组大小
int arr[5];
2.省略数组大小,开始直接自己输入元素
int arr[] = {
    
    1,2,3,4,5};

この方法で配列を作成すると、非常に大きな制限が生じます。つまり、配列のサイズを柔軟に変更することができず、配列のサイズを最初にハードコーディングする必要があります。

C99 で提供されるすべての新機能は可変長配列 (VLA)であり、変数を使用して配列サイズを作成できるようになります。

//这样一来就可以根据输入的值来创建对应的大小的数组了
int n;
scanf("%d",&n)
int arr[n];

上の例では、arr は辺の長さの配列です。その配列サイズは入力値 n のサイズによって決まります。コンパイラは配列サイズを事前に決定できません。プログラムの実行時にのみ n が何であるかを知ることができます。(つまり、可変長配列のサイズは実行時にのみ決定できるため、可変長配列を初期化することはできません。) 利点: プログラムを開発するときに、配列のサイズ
範囲の定義を特に考慮する必要はありません。プログラムは実行時に配列のサイズを正確に決定でき、配列のサイズは変数への代入に基づいて割り当てられます。
知らせ:プログラム実行時に変数のサイズに応じて配列のサイズが割り当てられ、一度割り当てられた配列のサイズは変わらないと判断されます。(変数とは、配列を作成するときの変数が可変であり、一意の固定値を必要としないことを意味します。配列のサイズを自由に変更できることを意味するわけではありません) 残念ながら、ほとんどの C99 構文は V​​S2022 でサポートされていますが、C99


構文はVS ではサポートされていません。可変長配列

#include <stdio.h>
int main(){
    
    
	int n = 0;
	scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
	int arr[n];
	int i = 0;
	for (i = 0; i < n; i++){
    
    
		scanf("%d", &arr[i]);
	}
	for (i = 0; i < n; i++){
    
    
		printf("%d ", arr[i]);
	}
return 0;
}

入力:
5
1 2 3 4 5

出力:
1 2 3 4 5

4. 二分探索法(半探索法とも呼ばれます)

従来の検索方法と比較する

配列の添え字が0の要素から開始し、徐々に増やして求めたい数と比較します
デメリット:求めたい数が数万と大きい場合、何万回も検索する必要があります; 検索する数が大きくなるほど、検索が難しくなります

//传统查找方式(麻烦,什么年代了还在用传统香。。。方法)
int main() {
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int k = 0;//要查找的数
	int count = 1;//查找次数
	scanf("%d", &k);
	
	int sz = sizeof(arr) / sizeof(arr[0]);//数组内元素个数

	int find = 0;//假设找不到

	int i = 0;
	//循环递增数组下标作比较
	for (i = 0; i < sz; i++)
	{
    
    
		if (k == arr[i]) {
    
    
			printf("成功找到arr[%d]=%d,共查找了%d次", i,arr[i],count);
			find = 1;
			break;
		}
		count++;
	}
	if (find == 0)
	{
    
    
		printf("查找了%d次,找不到",count);
	}
	return 0;
}

ここに画像の説明を挿入します


二分探索法

开始:
将列表的起始索引 low 设置为 0
将列表的结束索引 high 设置为数组长度减1

循环条件为(low 小于等于 high):
    将中间索引 mid 设置为 (low + high) 的一半
    
   如果列表的mid下标对应的元素小于目标值:
        将 low 设置为 mid 加 1
   如果列表的mid下标对应的元素大于目标值:
        将 high 设置为 mid 减 1
   否则(也就是low 等于 high 时):
   		mid 下标对应的元素 等于 目标值
   		退出循环
//二分查找
int main() {
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int k = 0;//要查找的数
	scanf("%d", &k);
	int count = 1;//查找次数
	int find = 0;//假设找不到

	int sz = sizeof(arr) / sizeof(arr[0]);//数组内元素个数(组数长度)

	//low和high都是指下标位置
	int low = 0;
	int high = sz - 1;

	while (low <= high)
	{
    
    
		int mid = (low + high) / 2;

		//以下方法为 int mid = low + high 的优化方法:
		//之所以这么写是为了防止数据类型超出上限
		//int mid = low + (high - low)/2;

		if (arr[mid] < k)
		{
    
    
			low = mid + 1;
			count++;
		}
		else if (arr[mid] > k) {
    
    
			high = mid - 1;
			count++;
		}
		else
		{
    
    
			printf("成功找到arr[%d]=%d,共查找了%d次", mid, arr[mid], count);
			find = 1;
			break;
		}
	}
	if (find == 0)
	{
    
    
		printf("找不到");
	}
	return 0;
}

ここに画像の説明を挿入します

int arr[] = { 1,2,3,4,5,6,7,8,9,10}; を例にとると、
従来の探索法では 6 回、二分探索法では 3 回の差がありますが、二分探索のサイズが大きく
なるにつれて、二分探索の効率上の利点がますます明らかになります。

おすすめ

転載: blog.csdn.net/qq_45657848/article/details/132014201