【C语言初阶】数组详解

目录

一.什么是数组?

二.一维数组

1.一维数组的创建

2.一维数组的初始化

3.一维数组的使用

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

三.二维数组

1.二维数组的创建

2.二维数组的初始化

3.二维数组的使用

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

四.数组越界

五.数组作为函数的参数

数组(Array)是有序的元素序列。 若将有限个类型相同的变量集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。

数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。

二.一维数组:

1.一维数组的创建:

一维数组如何创建呢?数组由三部分组成:元素类型数组名数组大小

数组的大小:在c99标准前,数组的大小必须时常量表达式指定。

在c99中,引入变长数组的概念,变长数组允许数组大小使用变量来表示。

可能有小伙伴好奇,什么是变长数组呢?

数组的大小是可以用变量来指定的。

int n = 10;
	int arr[n];

我用的是VS2022,不支持变长数组,也就是说数组大小只能用常量或常量表达式来表示。

​
type_t arr_name[const_n];
//type_t 是指数组的元素类型
// arr_name 是指数组的名称,由创建者自定义
//const_n 是常量或常量表达式,用于指定数组的大小
//如:char arr[10]
//int arr[10]
//double arr[5]​

2.一维数组的初始化:

数组的初始化有两种:一种是完全初始化,另一种是不完全初始化。

#include<stdio.h>
int main()
{
	int arr1[10] = { 1,2,4,6,7,8,5,3,9,0 };//完全初始化
	int arr2[10] = { 4,5,7,3,9,8 };//不完全初始化
	return 0;
}

 由调试可以看出,当大括号不足十个元素时,也就是不完全初始化,剩下的值会默认初始化为0

还有就是当数组初始化了之后,我们可以不指定数组的大小,数组的大小由后面初始化的内容来确定:

int main()
{
	int arr[] = { 1,4,6,7 };//大小是4
	return 0;
}

注意:

int main()
{
	char arr1[] = "abcdef";
    //字符串类型,最后应该还有'\0',所以数组的大小应该为7
	char arr2[] = { 'a','b','c' };
   //数组大小为3
	return 0;
}

 当我们想把两个数组的内容分别打印出来,会看到什么样的效果呢?

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = { 'a','b','c' };
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	return 0;
}

 为什么数组arr2后面会打印一推烫烫烫呢?因为啊,我们在打印字符串时,遇到'\0'时,就会停止打印,就数组arr1后面,即字符串后面有'\0'存在,所以就打印了abcdef,而数组arr2后面没有'\0',所以计算机就会打印一推随机的东西出来,也就是看到的这样。

当我们在arr2后面加上'\0',就会达到我们想要的效果。

3.一维数组的使用:

提到一维数组的使用,我们必须知道下标引用操作符 [ ],数组的第一个元素的小标是从0开始的,如果我设定数组的大小为10,那数组元素对应的下标就是0-9

 我们怎么通过下标引用操作符 [ ],来访问数组中的元素呢?

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//sizeof求字节长度  sz=40/4=10;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("arr[%d]=%d\n", i, arr[i]);
		//这里的arr[i]是下标引用操作符
		//和上面数组的大小是完全不同的,所以arr[i]不是变长数组
	}
	return 0;
}

 这里我们都知道这里是十个元素了,为什么还要用sizeof来求呢?因为当我们初始化了数组,但是没有设定数组的大小。这时候就可以用sizeof来求数组的大小。

4.一维数组在内存中的存储:

一维数组在内存中的存储时怎么样的呢?要想知道这个问题,我们必须知道数组元素的地址时怎么样的:

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d]=%p\n", i, &arr[i]);//求每一个元素的地址
	}
	return 0;
}

 在十六进制中C表示12,8-12相差4个字节,以此类推,两两元素之间都是相差4个字节,而一个int类型就是4个字节,这里我们就可以得出一个结论:一维数组在内存中是连续存储的(低地址往高地址)

三.二维数组:

1.二维数组的创建:

三子棋大家玩过吧,它有行有列,这就是二维数组。一维数组就连续的一排,像一条蛇一样,而二维数组就像一个棋盘,你还可以在上面下棋。

#include<stdio.h>
int main()
{
	int arr[3][4];//行在前,也就是3,列在后,也就是4
	int arr[5][6];

	return 0;
}

2.二维数组的初始化:

如果把二维数组的每一行看作一个一维数组,那么每一行的一维数组也有数组名。arr[0]就是第一行的数组名,arr[1]就是第二行的数组名,以此类推。

二维数组和一维数组一样都有完全初始化和不完全初始化。

完全初始化:初始化二维数组时,行时可以省略的,列不可以省略,行可以在初始化时自动分配好行数。

大括号里面有几个大括号就有几行。

#include<stdio.h>
int main()
{
	int arr1[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int arr2[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
	//也可以写成int arr[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	return 0;
}

 不完全初始化:一样行可以省略,而列不可以省略。

 二维数组的不完全初始化和一维数组时一样的,未被初始化的都默认维初始化为0

3.二维数组的使用:

二维数组和一维数组一样都是通过,下标引用操作符 [ ]来访问数组中的元素。稍稍有一点不一样的是,二维数组是两个下标引用操作符 [ ][ ] 来访问二维数组中的元素。

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

 4.二维数组在内存中的存储:

二维数组在内存中存储会不会也和一维数组一样呢?也是连续存储的呢?我们不妨验证一下。

#include<stdio.h>
int main()
{
	int arr[3][4] = { 0 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
		}
	}
	return 0;
}

 很明显,我们验证对了,二维数组虽然看起来不是连续的,更像是棋盘一样,但是二维数组和一维数组一样都是连续存储的(低地址到高地址)。

四.数组越界:

数组越界比较好理解,也就是数组访问到外界去了,不在数组初始化的范围内。

C语言本身是不做数组下标的越界检查,编译器也不一定报错,但编译器不报错,并不意味着程序就是正确的。所以在写数组的时候,一定要检查好,不要数组越界了。

#include<stdio.h>
int main()
{
	int arr[3][4] = { 0 };
	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;
}

像这样就是数组越界了,列是不能访问到第4列的,但是编译器没有报错,甚至运行出了 正确的结果。但本身这样就是错的,所以希望大家能够认真对待。

五.数组作为函数的参数:

数组作为函数的参数:我们写一个冒泡函数来验证一下数组作为函数的参数。之前写了一个冒泡排序,在这里我就不说它的原理了,我们直接上代码。

void bubble_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 ret = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = ret;
			}
		}
	}
}
#include<stdio.h>
int main()
{
	int arr[10] = { 3,5,1,2,9,0,7,8,4,6 };
	bubble_sort(arr);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 为什么没有达到我们的目的呢?将他们该成升序,我们只有通过调试来看看到底哪里出错了。

我们原本是让sz求出来为10的,但是为什么算出来是1呢?sizeof(arr[0])为四个字节是没有问题 

那么sizeof(arr)只能是4了,我们就来探讨一下数组名是什么了?

数组名其实是数组首元素的地址,这个是毋庸置疑的。

但是有两个例外:

1.sizeof(数组名),数组名如果单独放在sizeof内部,这里的数组名表示整个数组,计算的是整个数组的大小。

2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址

  {关于理解第2点,可能有些小伙伴有点疑惑,当你验证打印arr和&arr的地址居然是一样的?

 那为什么还说&数组名是整个数组的地址呢?我们用代码来理解一下

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", arr+1);

	printf("%p\n", &arr[0]);
	printf("%p\n", &arr[0] + 1);

	printf("%p\n", &arr);
	printf("%p\n", &arr + 1);
	return 0;
}

这里可以看出arr和&arr[0]的地址是一样的,分别加1的地址也是一样的,这就可以说明数组名是首元素的地址是完全没问题的。

但是当&arr+1的地址就完全不一样了。 

printf("%p\n", &arr);
	         //地址0133FB1C
	printf("%p\n", &arr + 1);
	         //地址0133FB44

地址:01333FB1C和0133FB044总共差16进制的28,28转换为十进制是40,由此得出&arr+1跳过的是整个数组40个字节。

但&arr和arr的地址是一样的呢?因为它们都是从首地址开始的,虽然它们的值是一样的,但是他们所表达的含义是不同的。}

那为什么上面代码sizeof(arr)求出来的是4个字节呢?因为当数组名作为函数的参数的时候,应当用指针接收。

void bubble_sort(int arr[])
//也可以这样写,看起来更加好理解,数组传参,数组接收
//也可写成void bulle_sort(int* pa)

指针的大小就是4个字节,这样就可以说的请了。

我们应该在主函数里面把sz求出来,然后作为参数传给冒泡函数,这样就可以达到我们的目的了。

改正:

void bubble_sort(int arr[],int sz)
//也可以这样写,看起来更加好理解,数组传参,数组接收
//也可写成void bulle_sort(int* pa)
{
	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 ret = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = ret;
			}
		}
	}
}
#include<stdio.h>
int main()
{
	int arr[10] = { 3,5,1,2,9,0,7,8,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr,sz);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 这就是全部的内容了,创作不易,还望各位老铁赏个赞,感谢。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值