初级C语言数组

本文详细介绍了C语言中的一维和二维数组,包括数组的创建、初始化、使用和内存存储。强调了数组越界的问题,指出C语言不检查数组越界,程序员需要自行检查。最后讨论了数组作为函数参数的情况,指出数组名通常代表首元素地址。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一维数组

一维数组的创建

什么是数组?

数组是一组相同类型元素的集合。
数组的创建方式:

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

代码1:

int	arr1[10];

代码2:

int a=10;
int arr2[a];
//注意:创建数组时,数组的常量表达式不能是变量
//这里 a 虽然被赋值,但是它的 本质 还是一个 变量 
//所以,这里是一个 错误示范,这样创建数组的时候,是不会被语法允许的

代码3:

#define count 100
int main()
{
	int arr3[count];
}
//这里的 count 是全局变量
//虽然它也是叫做变量
//但是它在被代码块引用的时候,通常被当作常量来引用。

代码4:

int arr4[]={1,2,3,4};
//数组在创建的时候如果想不指定数组的确定的大小就得初始化。
//数组的元素个数根据初始化的内容来确定。

//一定不能这样创建:
int arr4[];
//这样创建编译器会报错
//因为它不知道该分配给 arr4[] 数组多少空间

代码5:

char arr5[10];
float arr6[10];
double arr7[10];

一维数组的初始化:

数组的初始化是指,在创建数组的同时给数组的内容一些合理的初始值(初始化)。

 int arr1[10]={1,2,3,4,5,6,7,8,9,10};
 int arr2[10]={1,2,3,4};
 
 char arr3[5]={'a','98','c'};
 char arr4[]={'a','b','c'};
 char arr5[]="abc";

这里有个值得小小注意的地方,就是arr4和arr5这两个数组的大小
width=0.8,height=0/8

arr4是字符串,arr5是字符。
字符数组在你创建的时候没有规定大小,而是由初始化来规定大小的时候,你初始化的大小是多少,就是多少
字符串数组在你创建的时候没有规定大小,而是由初始化来规定大小的时候,你初始化的大小是多少,就在你初始化的大小上+1,因为在字符串里面是默认最后面跟上了一个 '\0'

一维数组的使用

对于数组的使用,我们之前介绍了一个操作符:[]——下标引用操作符。
它其实就是数组的访问操作符。

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 //数组的不完全初始化
 //计算数组的元素个数
 int sz = sizeof(arr)/sizeof(arr[0]);
 //对数组内容赋值
 //数组是使用下标来访问的,下标从0开始。
 //所以:
 int i = 0;
 //做下标
 for(i=0; i<sz; i++)
 //这里的条件判断在知道数组大小的时候
 //可以直接用数组大小也可以用sz
 //但是不知道数组大小的时候,你只能用sz
 {
	 arr[i] = i;
 } 
 //输出数组的内容
 for(i=0; i<10; ++i)
 {
 	printf("%d ", arr[i]);
 }
 return 0; 
 }

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

计算数组大小的用操作符sizeof计算

sizeof(数组名)计算的是数组的大小,
sizeof(数组名[0])计算的是数组单个元素的大小

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

一维数组在内存中的存储

数组在内存中的存储,是连续存放的,并且数组中元素的地址也是随着数组下标的增长而增长
下面让我们来直观感受下:

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

代码输出结果:
Alt
注:在内存中,地址一般是用十六进制表示

因为一个int型的数据大小是4个字节,所以这里int型的数组,每个元素的之间的地址相差4

二维数组

二维数组的创建

什么是二维数组?
二维数组实际上是一种平面的二维结构,本质上是数组的数组。
创建实例:

int arr[2][3]={{1,2,3},{4,5,6}};

二维数组的初始化

二维数组的大多数注意事项同一维数组的注意事项一样
下面介绍不同于一维数组的地方
不同的:

int arr[][3]={1,2,3,4,5,6};
//二位数组在创建的时候行可以省略,但是列不能省
//省略了行可以在初始化的时候根据列的数量来进行分行
//但是如果省略了列,那就没有办法进行分行的操作
int arr1[3][4]={{1,2},{3,4,5},{9,8,7,6}}
//在限定了二位数组的大小的前提下,二维数组每一行的元素可以不用写满,会自动补0
int arr2[2][3]={1,2,3,4,5};
//在没有{}将数组的数据分好的情况下,数组会自动默认排序
//在第一行排完之后排第二行,如果数据不够,自动补0
//
//对于二维数组的字符串输入、输出,代码如下:
#include<stdio.h>
int main()
{
	//存储3个字符串,每个不超10
	char arr[3][10] = { 0 };
	//输入数据(字符串)
	for (int i = 0; i < 3; i++)
	{
		printf("请输入字符串:\n");
		scanf("%s", arr[i]);
		//每一行输入数据,故而只需要显示行的常量
		//但是要注意,输入的数据不能超过列的限制,不然就会造成数据溢出
	}

	//打印数据
	for (int j = 0; j < 3; j++)
	{
		printf("打印数据为:%s\n", arr[j]);
	}
	return 0;
}

二维数组的使用

#include<stdio.h>
int main()//打印一个九宫格的*
{
	char arr[3][3];
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			arr[i][j] = '*';
		}
	}
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("%c ",arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

效果图:
在这里插入图片描述

二维数组在内存中的存储

二位数组和一维数组的存储方式一样,是连续存放的,并且数组中元素的地址也是随着数组下标的增长而增长
让我们感受一下:

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

Alt

数组越界

讨论完了数组创建,初始化,使用和存储之后,就要来讲解到一个非常重要的知识点——数组越界

数组的下标是有范围限制的。

数组的下规定是从0开始的,如果输入有n个元素,最后一个元素的下标就是n-1。

所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

C语言本身是不做数组下标的越界检查,编译器也不一定报错

但是编译器不报错,并不意味着程序就是正确的

所以程序员写代码时,最好自己做越界的检查。

例如:

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

	return 0;
}

在这里插入图片描述

这里的代码访问就越界了,但是作者用的VS2019并没有报错,但是它却死循环了,死循环的原因是为什么呢?

局部变量的存储是存放在栈区的
栈的使用规则是先进后出,即先用高地址,再用低地址,调用栈的时候,是先低地址出去,然后高地址出去
元素的地址是:随着下标的增长由低到高变化的

在这里插入图片描述
编译器的差异会导致缓冲区的大小不同

例如:
vc6.0中 arr和i 是连着的,没有缓冲区
vs2013–vs2019(除了vs2017),缓冲区有两个空间
gcc中则只有一个

所以说千万别忽视了数组越界,这个示例还是曾经的一道经典面试题!

数组作为函数参数

在数组作为函数参数时,通常是作为首元素地址
结论
数组名除了两种情况以外,都是作为首元素地址

  • 1.sizeof(数组名),计算的是整个数组的大小,此时的数组名代表 的是整个数组
  • 2.&数组名,取出的是整个数组的地址,此时的数组名代表的是整个数组
    例如(冒泡排序):
#include<stdio.h>
void Sort(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)//数组不需要和自己比较
	{
		for (j = 0; j < sz - i - 1; 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};
	int sz = sizeof(arr) / sizeof(arr[0]);//这里计算的是数组元素的个数
	Sort(arr, sz);//这里的数组名作为函数参数时,是代表数组首元素地址
	for (int i = 0; i < 10; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
	return 0;
}

效果图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值