Home 世界杯开幕战 C语言新手入门--数组

C语言新手入门--数组

文章目录

前言一、数组的概念二、一维数组的创建和初始化

1.数组创建2.数组的初始化3.数组的类型三、一维数组的使用

1.数组下标2.数组元素的打印和数组的输入四、一维数组在内存中的存储五、sizeof计算数组元素个数六、二维数组的创建

1.二维数组的概念2.二维数组的创建七、二维数组的初始化

1.不完全初始化2.完全初始化八、二维数组的使用九、二维数组在内存中的存储十、C99中的变长数组十一、数组练习

前言

我将带领大家学习数组,初次接触C语言大家肯定有很多疑惑,也有急迫的心情恨不得把所有知识直接灌进自己的小脑瓜里面,但是学习是一件循序渐进的事情,保持耐心坚持下去一定会有结果。话不多说,带入大家切入正题。

一、数组的概念

1.定义:数组是一组相同类型元素的集合。

2.特点:

• 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。

• 数组中存放的多个数据,类型是相同的。

3.种类:数组分为一维数组和多维数组,多维数组一般比较多见的是二维数组。

二、一维数组的创建和初始化

1.数组创建

一维数组创建的基本语法如下:

type arr_name[ 常量值 ];

type 指定的是数组中存放数据的类型,可以是: char 、 short 、 int 、 float 等,也可以自定义的类型。

arr_name 指的是数组名的名字,这个名字根据实际情况,起的有意义就行。

[ ] 中的常量值是用来指定数组的大小的,这个数组的大小是根据实际的需求指定就行。

注:存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。

如:李四想存储他所在班级同学们的成绩,我们就可以创建一个数组来存储

int math[ 30 ];

当然我们也可以根据需要创建其他类型和大小的数组:

char ch[ 10 ];

double score[ 15 ];

2.数组的初始化

在创建数组的时候,我们需要给数组进行初始化,数组的初始化⼀般使用大括号,将数据放在大括号中。

//完全初始化

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

//不完全初始化

int arr2[6] = {1};

//第⼀个元素初始化为1,剩余的元素默认初始化为0 //错误的初始化—初始化项太多

int arr3[3] = {1, 2, 3, 4};

3.数组的类型

数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组的类型。

int arr1[10];//arr1数组的类型是int [10]

int arr2[12];//arr2数组的类型是int [12]

char ch[5];//ch数组的类型是char [5]

三、一维数组的使用

1.数组下标

C语言规定数组是有下标的,下标是从0开始的,假设数组有n个元素,最后一个元素的下标 是 n-1,下标就相当于数组元素的编号,如下:

int arr[10] = {1,2,3,4,5,6,7,8,9,10};

在C语言中数组的访问提供了一个操作符 [ ] ,这个操作符叫:下标引用操作符。

有了下标访问操作符,我们就可以轻松的访问到数组的元素了。

如:李四想对数组中,下标为4的元素和7的元素分别进行访问

2.数组元素的打印和数组的输入

数组元素的打印

李四现在想对整个数组进行访问,他该如何操作呢?

我们可以想到只要我们产生数组所有元素的下标就可以了,那我们使用for循环产生0~9的下标,接下来使用下标访问就行了。

int main()

{

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

int i = 0;

for (i = 0; i < 10; i++)

{

printf("%d ", arr[i]);

}

return 0;

}

数组的输入

李四又想对整个数组进行输入,他该怎么操作呢?

我们可以使用for循环来对数组进行输入,再用for循环来对数组进行打印

int main()

{

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

int i = 0;

for (i = 0; i < 10; i++)

{

scanf("%d", &arr[i]);

}

for (i = 0; i < 10; i++)

{

printf("%d ", arr[i]);

}

return 0;

}

四、一维数组在内存中的存储

李四通过对前面的学习,使用数组基本上没有什么障碍了,但是他想对数组进行进一步的学习,就要认识并理解数组在内存中的存储。

int main()

{

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

int i = 0;

for (i = 0; i < 10; i++)

{

printf("&arr[%d]=%p\n", i, &arr[i]);//%p是用来打印地址的占位符

}

return 0;

}

这里的地址采用的是16进制,我们可以看出每一个元素地址之间隔着4个字节,而数组里存放的是整型,由此得出,数组在内存中是连续存放的,是由低到高的。着就为后期我们使⽤指针访问数组奠定了基础(在讲指针的时候我们在再讲,这⾥暂且记住就行)。

五、sizeof 计算数组元素个数

李四在遍历数组的时候,他就想知道数组的元素个数,可他却不知道该如何实现数组的元素个数。我们可以用数组总大小除以数组单个元素的大小就可以得到数组的元素个数,而要实现这个方法就要用 sizeof 操作符。下面用 sizeof 操作符计算数组总大小:

我们可以看出用sizeof操作符计算数组总大小为40个字节,而数组是整型,一个整型是4个字节,那么数组总大小为10*4==40

注:计算的是数组所占内存空间的总大小,单位是字节。

知道了如何求数组总大小,来求解数组的第一个元素大小就会很轻松,如:

接下来就能计算出数组的元素个数:

以后在代码中需要数组元素个数的地⽅就不用固定写死了,使用上面的计算,不管数组怎么变化,计算出的大小也就随着变化了。

六、二维数组的创建

1.二维数组的概念

前面学习的数组被称为一维数组,数组的元素都是内置类型的,如果我们把一维数组做为数组的元素,这时候就是二维数组,二维数组作为数组元素的数组被称为三维数组,二维数组以上的数组统称为多维数组。

整型、整型⼀维数组、整型⼆维数组

2.二维数组的创建

type arr_name[常量值1][常量值2];

int arr[3][5];

学习了一维数组,我们就不难理解二维数组的创建。如:3表示数组有3行, 5表示每一行有5个元素(5还可以表示数组有5列);int 表示数组的每个元素是整型类型 , arr 是数组名,可以根据自己的需要指定名字。

七、二维数组的初始化

1.不完全初始化

int arr1[3][5]={1,2};

//将第一行的前面两个元素初始化为1和2,其余都为0

int arr2[3][5]={0};

//把全部元素初始化为0

2.完全初始化

对二维数组进行完全初始化

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

按照行初始化:

按行对二维数组进行初始化,把每行进行初始化,分别用{ }大括号括起来,这样就可以实现每一行初始化完全,也可以初始化下一行,如:

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

//把每行的前两个元素进行初始化,其余元素为0

初始化时省略行,但是不能省略列:

int arr5[][5] = {1,2,3};

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

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

八、二维数组的使用

我们了解二维数组的创建和初始化,接下来对二维数组进行使用。在对二维数组中元素进行访问的时候,二维数组的下标分别表示行和列,锁定行和列就可以对二维数组中其中一个元素进行访问。在C语言中,规定二维数组的行是从0开始的,列也是从0开始的,如:

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

如,寻找第2行,第4列的元素,则快速就能定位出7。

二维数组的输入和输出

上面学习了数组的输入的例子我们可以了解到对数组的输入需要用循环语句来进行操作,因此对二维数组的输入和输出也将会用到同样的方法,借助循环实现生成所有的下标。

如:

int main()

{

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

int i = 0;

int j = 0;

//对二维数组进行输入

for (i = 0; i < 3; i++)

{

for (j = 0; j < 5; j++)

{

scanf("%d", &arr[i][j]);

}

}

//对二维数组打印

for (i = 0; i < 3; i++)

{

for (j = 0; j < 5; j++)

{

printf("%d ", arr[i][j]);

}

printf("\n");

}

return 0;

}

九、二维数组在内存中的存储

像一维数组一样,我们如果想研究二维数组在内存中的存储方式,我们也是可以打印出数组所有元素的地址的。

如:

int main()

{

int arr[3][5] = { 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]);//%p是取地址

}

}

return 0;

}

十、C99中的变长数组

在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组大小。

如:

int arr1[10];

int arr2[3+5];

int arr3[] = {1,2,3};

这样的语法限制,让我们创建数组就不够灵活,有时候数组大了浪费空间,有时候数组又小了不够用的。

C99中给一个变长数组(variable-length array,简称 VLA)的新特性,允许我们可以使用变量指定数组大小。如:

int n = a+b;

int arr[n];

上面示例中,数组 arr 就是变长数组,因为它的长度取决于变量 n 的值,编译器没法事先确定,只有运行时才能知道 n 是多少。 变长数组的根本特征,就是数组长度只有运行时才能确定,所以变长数组不能初始化。它的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。有⼀个比较迷惑的点,变长数组的意思是数组的大小是可以使用变量来指定的,在程序运行的时候,根据变量的大小来指定数组的元素个数,而不是说数组的大小是可变的。数组的大小一旦确定就不能再变化了。

十一、数组练习

练习1:多个字符从两端移动,向中间汇聚

解释:

编写代码,演示多个字符从两端移动,向中间汇聚,如: welcome to bit!!!!! ******************* w*****************! we***************!! wel*************!!!... welcome to bit!!!!!

#include

#include

#include

int main()

{

char arr1[] = "welcome to my world!!!!";

char arr2[] = "***********************";

int left = 0;

int right = strlen(arr1) - 1;

while (left <= right)

//当左右两边的数移动到中间时,可能会有一个数一样,然如果left大于right就会出现溢出现象程序进行不了

{

arr2[left] = arr1[left];

arr2[right] = arr1[right];

printf("%s\n", arr2);

Sleep(1000);//设置每次替换隔一秒

system("cls");//全部打印完后会清屏

left++;

right--;

}

printf("%s\n", arr2);//因为system会出现清屏的现象,则还需要再打印一次

return 0;

}

练习2:二分查找

在一个升序的数组中查找指定的数字n,很容易想到的方法就是遍历数组,但是这种方法效率比较低。比如我买了一双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,比如:150,然后看大了还是小了,这就是二分查找,也叫折半查找。

解释:

二分查找(折半查找):在有序的情况下,无序则不能 1 2 3 4 5 6 7 8 9 10

当k=7,则要查找数字7,按数组下标来看是0 1 2 3 4 5 6 7 8 9;

7对于的下标为6,(0+9)/2=4,(0+9)是下标0和9相加,4是下标;

前面下标0~4被砍去,则从下标5~9开始查找:(5+9)/2=7,(5+9)是下标5和9相加,7是下标

因为查找的数字对应下标是6,7>6,下标7~9被砍去,则从下标5~6开始查找

( 5+6 )/2=5,5是下标排除下标5,只剩下下标6,则(6+6)/2=6,因此就找到下标6的数字7

int main()

{

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

int k = 0;

scanf("%d", &k);

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

int left = 0;//表示left是从下标0开始

int right = sz - 1;//10-1=9,表示right是从下标9开始

int flag = 0;//判断为真假

while (left <= right)

{

int mid = (left + right) / 2;//核心方法

if (arr[mid] < k)//当下标小于k时,左边取掉,再从mid+1开始

{

left = mid + 1;

}

else if (arr[mid] > k)//当下标大于k时,右边取得,再从mid-1开始

{

right = mid - 1;

}

else

{

printf("找到了,下标是:%d\n",mid);

flag = 1;

break;//跳出执行的循环,否则会无限循环下去

}

}

if (flag == 0)

{

printf("找不到了\n");

}

return 0;

}

总结

非常感谢大家阅读完这篇博客,希望这篇博客可以给您带来启示和一些知识。在未来的日子里,我将继续探索更多技术知识并把精彩内容分享在博客上面,尽请期待。如果您有任何问题或建议,欢迎在评论区留言,我们一起交流学习。