c语言分层理解(c语言数组)

1. 一维数组的创建和初始化

首先,我们要知道数组是相同类型元素的集合。

1.1 一维数组的创建

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

在创建时我们所碰到的问题

1. 数组[]中能不能是一个变量

这是在visual studio 2022中的情况:

在visual studio 2022中我们看见它是不行的,实际上数组[变量]这种语法是c99标准中的,它叫变长数组。很明显,visual studio 2022不支持c99版本。
在支持c99标准的编译器下是可以运行的,并不会报错。

2. 数组创建时可不可以不给数组指定大小


这是不行的,创建的时候必须指定空间大小。,不然会报错。

3. 数组空间太大栈区会放满

4. 补充

int arr[2+3]//这种语法是对的,[]中可以是表达式

char arr1[2 + 3];
int arr2[2 + 3];
int arr3[3 + 2];//加法支持交换律
float arr4[4 + 3];
double arr5[5 + 3];
//以上都是正确的,不用质疑

注意:数组创建,在C99标准之前, [] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化

1.2 一维数组的初始化

首先了解初始化和赋值的意思:

int a = 0;//这叫初始化
int n;
n = 20;//这叫赋值

初始化是创建变量的同时给定一个数值。
赋值是创建变量之后对这个变量给定一个数值
重点放在初始化是同时进行,赋值是一前一后进行

一维数组初始化常见问题罗列

1. int arr[] = {1,2,3}写法可以吗?

这种写法是可以的。

arr数组中存放的是123,这里没有给定空间大小,数组就自动根据元素个数给定这个数组大小。这个数组的空间大小是12。

2. int arr[10] = {1,2,3,4,5}写法可以吗?

这种写法是没有问题的,这个叫做不完全初始化。

这个数组中存放的是1234500000,说明了初始化不完全,编译器会自动给其初始化为0,这里的数组空间大小是40,原因是我们规定了数组大小。

3. 看看char arr1[] = "abc"和char arr2[] = {‘a’,‘b’,‘c’}的区别


这里我们发现,arr1中有四个元素,arr2中有三个元素,说明arr1的空间大小是4,arr2的空间大小是3。
理解了这点再来看看char arr3[10] = "abc"和char arr4[10] = {‘a’,‘b’,‘c’}的区别:

这里我们看到的是一样的,其实并不是,上面我们已经验证了char arr1[] = “abc”,arr1中包含的是a,b,c,\0,arr2中包含a,b,c,这里虽然arr3和arr4看起来一样,但是不同,arr3中其实是a,b,c,\0,0,0,0,0,0,0,arr4中其实是a,b,c,0,0,0,0,0,0,0,这就能解释为什么不一样的原因了。

2. 一维数组的使用

对于数组的使用我们知道[]是一个下标引用操作符,其实就是数组访问的操作符。我们之前提到一个交换律的概念,如:2+3可以写成3+2,一个双目操作符的两个操作数是可以交换的,数组中的两个操作数在某些场景中也是可以交换的,如:

#include <stdio.h>
int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5 };
	int i = 0;
	for (i = 0; i < 5; i++)
	{
    
    
		printf("%d ", i[arr]);
		//printf("%d ",arr[i]);
	}
	return 0;
}

总结:

1.数组是使用下标来访问的,下标是从0开始的。
2.数组的大小可以通过计算得到

int arr[10];
int sz = sizeof(arr)/sizeof(arr[0]);

3. 一维数组在内存中的存储

还是先看现象再看实质;

通过这段代码我们发现地址都是隔4个字节的大小,说明一维数组在内存中是连续存放的。随着数组下标的增长,地址也是由低地址到高地址变化。

4. 二维数组的创建和初始化

4.1 二维数组的创建

int arr[3][4];//三行四列的数组
char arr[3][4];
double arr[2][4];

前一个[]中的数字代表行数,后一个[]中的数字代表列数。

4.2 二维数组的初始化

4.2.1 int arr[3][4] = { 1,2,3,4 }写法中的数字存储


解释:这个数组是个三行四列的数组,所以第一行存储1234,其他两行被默认初始化为0。

4.2.2 int arr[3][4] = { {1,2},{4,5}}写法中的数字存储


如图,发现{1,2}和{4,5}相当于一维数组,列数不够在其后默认初始化为0。

4.2.3 arr[][]和arr[][2]和arr[2][]的比较

int arr[][] = {
    
    0};//错误
int arr[][2] = {
    
    0};//正确
int arr[2][] = {
    
    0};//错误
int arr[2][2] = {
    
    0};//正确

arr[][]和arr[2][]都会报错,说明arr缺少下标。

注意:二维数组如果初始化,行可以省略,列不能省略。

5. 二维数组的使用

二维数组的使用也是通过下标的方式。

#include <stdio.h>
int main()
{
    
    
	int arr[3][4] = {
    
     {
    
    1,2,3,4},{
    
    5,6,7,8},{
    
    9,10,11,12} };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < 4; j++)
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

6. 二维数组在内存中的存储

通过现象看本质:

通过观察,其实二维数组也是在内存中连续存放的。

7. 数组越界问题

数组的下标是有范围限制的。
数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就
是正确的,所以程序员写代码时,最好自己做越界的检查

通过代码看现象:

这是一维数组中的越界访问,没有下标为10的这个元素,所以打印出来的不知道是那块内存的数据。
就像当于这样子;

8. 数组作为函数参数的情况

8.1 冒泡排序为例

这里以冒泡排序为例子

冒泡排序是什么?
听到冒泡就很容易联想到泡泡,在水中有水底浮上水面上,慢慢变大。这里的冒泡排序就是由小到大升序排列的意思
具体怎么实现?
核心就是两两相邻的元素进行比较

思路:

完成的趟数=总元素个数-1,完成一趟的次数=完成的趟数-i(i=0~(完成的趟数-1))

代码实现:

//错误的代码
#include <stdio.h>
void bubble_sort(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 temp = 0;
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
    
    
	//给出几个数字,以9 8 7 6 5 4 3 2 1 0为例
	int arr[10] = {
    
     9,8,7,6,5,4,3,2,1,0 };
	//实现一个函数进行排序
	bubble_sort(arr);
	//打印
	int z = 0;
	for (z = 0; z < 10; z++)
	{
    
    
		printf("%d ", arr[z]);
	}
	return 0;
}

输出结果:

那么哪里错了呢?
int sz = sizeof(arr)/sizeof(arr[0]);这里错了,不应该放在函数中,因为数组传参传的是首元素地址(也就是一个指针),在x86平台下,sizeof(arr)=4,在x64平台下sizeof(arr)=8,所以sz=1,只是交换了一次,所以打印出8 9 7 6 5 4 3 2 1 0的结果。

下面是正确的代码展示:

//正确的代码
#include <stdio.h>
void bubble_sort(int arr[], int sz)
{
    
    
	//完成一趟数字的排序
	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 temp = 0;
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
    
    
	//给出几个数字,以9 8 7 6 5 4 3 2 1 0为例
	int arr[10] = {
    
     9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//实现一个函数进行排序
	bubble_sort(arr,sz);
	//打印
	int z = 0;
	for (z = 0; z < 10; z++)
	{
    
    
		printf("%d ", arr[z]);
	}
	return 0;
}

8.2 数组名是什么?

一般请况下数组名是首元素地址。

这么说你肯定不理解,看图:

一下子你就明白了,首元素就是首元素地址这个关系。

这个还不能说明什么的话,那就再看一个例子:

用数组名指向的元素和每个元素取到的地址相同。


我们说数组名是个指针,下面来说明一下:

数组名存在两个例外(并不是所有的数组名都是首元素地址)

1.sizeof(数组名),这里的数组名是整个数组,计算的是整个数组的大小,单位是字节

证明:

2.&数组名中,这个数组名是整个数组的大小,取出整个数组的地址

证明:



见博主这么努力给博主关注关注,点点赞,支持支持吧! 看博主那么可怜!
写的还不错嘛,
哈哈开个玩笑呐,还望诸位多多支持,指点一二,感谢感谢!

猜你喜欢

转载自blog.csdn.net/m0_46343224/article/details/126003550