关于数组的基本要点

目录

一.一组数组的创建与初始化

1.1 数组的创建

1.2 数组的初始化

1.3 一维数组的使用

​编辑

1.4 一维数组在内存中的存储

二.二维数组的创建与初始化

2.1 二维数组的创建

2.2 二维数组的初始化

2.3 二维数组的使用

2.4 二维数组在内存中的储存

​编辑

三.数组越界

四.数组作为函数参数

4.1 冒泡排序函数的错误设计

4.2 数组名是什么?

4.3 冒泡排序函数的正确设计


一.一维数组的创建与初始化

1.1 数组的创建

数组是一组相同类型元素的集合。

数组的创建方式:

 type_t(是指数组的元素类型)  arr_name   [const_n]是一个常量表达式,用来指定数组的大小

#include
//C99之前数组只能是常量指定大小
//C99之后引用了变长数组概念,数组大小是可以用变量指定的。
int main()
{
	int arr[5];
	int arr2[3 + 2];

	char arr3[8];
	int n = 0;
	scanf("%d", &n);
	int arr4[n];
	return 0;
}

不过vs是不支持用变量来指定大小的。

1.2 数组的初始化

关于数组的基本要点_第1张图片

这里面有不完全初始化(剩余元素默认为0) 也有通过ascll码值代替字母  也可以不输入大小,通过内容自动判定。

不过关于字符数组需要注意一点:字符型不会自动放‘\0’,而字符串会。

1.3 一维数组的使用

数组通过下标来访问:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%2d ", arr[i]);
	}
	printf("\n");
	//如果想要倒序,也可以改变
	for (i = 0; i < sz; i++)
	{
		arr[i] = 10 - i;
		printf("%2d ", arr[i]);
	}
	return 0;
}
​

关于数组的基本要点_第2张图片

 关于数组的基本要点_第3张图片

1.4 一维数组在内存中的存储

我们可以通过地址来说明:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d]=%p\n", i, &arr[i]);
	}
	printf("\n");
	//如果想要倒序,也可以改变
	/*for (i = 0; i < sz; i++)
	{
		arr[i] = 10 - i;
		printf("%2d ", arr[i]);
	}*/
	return 0;
}

关于数组的基本要点_第4张图片

可以得出相邻地址之间都相差4个字节(整型元素是4个字节)是连续存放的并随下标增长,地址是低到高的。

二.二维数组的创建与初始化

2.1 二维数组的创建

关于数组的基本要点_第5张图片

2.2 二维数组的初始化

//对于二维数组,如果初始化了,对于行数是可以省略的,但是列不能省略

int main()
{
	int arr[3][5] = {0};//不完全初始化
	int arr1[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	int arr2[][10] = { {1,2},{2,3,4},{5,5,5} };


	return 0;
}

对于二维数组,如果初始化了,对于行数是可以省略的,但是列不能省略。

2.3 二维数组的使用

假想中的二维数组:

关于数组的基本要点_第6张图片

 通过下标遍历简单访问二维数组

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

 我们还可以改变数组:打印1-15

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

2.4 二维数组在内存中的储存

打印一下二维数组的地址:

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

关于数组的基本要点_第7张图片

我们会发现所有元素之间都差4个字节,这与我们想的行列图并不一样,而应该是这样:

 关于数组的基本要点_第8张图片

 二维数组在内存中也是连续存放的。

关于数组的基本要点_第9张图片

 二维数组其实是一维数组的数组。

可以把第一行的数组名看作arr[0],后面的[j]就是一维数组的大小。

三.数组越界

关于数组的基本要点_第10张图片

四.数组作为函数参数

冒泡排序基本思想:

关于数组的基本要点_第11张图片

int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
			else
			{
				break;
			}
		}
	}
	for (i = 0; i < sz ; i++)
	{
		printf("%d ", arr[i]);
	}
	
	return 0;
}

10个数趟数是9趟,每一趟需要对比交换的次数都会减少,这里用sz-1-i来表示。

4.1 冒泡排序函数的错误设计

void sort(int arr[])
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
			else
			{
				break;
			}
		}
	}
}

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

	return 0;
}

当我们把写好的代码封装到函数时发现出了问题。

关于数组的基本要点_第12张图片

没有排序了。

这里就涉及到了数组传参的问题了。 

4.2 数组名是什么?

关于数组的基本要点_第13张图片

 结论:数组名就是数组首元素的地址。

但是有两个意外:1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。

关于数组的基本要点_第14张图片

 通过地址可以发现,首个地址加1只是移动到下一个位,但&arr加1是直接跨越了整个数组的大小。

4.3 冒泡排序函数的正确设计

void sort(int arr[])
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
			else
			{
				break;
			}
		}
	}
}

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

	return 0;
}

sort(arr)不是特殊的两种情况,就是数组的首元素地址,本质上形参用指针接受。所以上述形参中arr[]其实是个指针(当然形参也可以用int *arr),sizeof(arr)(等于4)/sizeof(arr[0])=1,sz=1.

在这种情况下我们可以把sz的求法放在main函数上,因为传的就是地址,接收的就只能是指针,不管怎么算大小都只能是4,所以只能在主函数求出,经过计算再传回去。

void sort(int arr[],int sz)
{
	
	int i = 0;
	int j = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
			else
			{
				break;
			}
		}
	}
}

int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	sort(arr,sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

小疑惑:

也不用对首个元素地址感到奇怪,为什么不传整个数组呢?其实是因为后续有对数组进行遍历,只要知道首个元素的地址,就可以知道后面的地址了,进而遍历得到整个数组。

你可能感兴趣的:(c语言,c语言)