概述
在程序设计中,为了方便处理数据把具有 相同类型 的若干变量按有序形式组织起来——称为数组。
数组是在内存中连续的相同类型的变量空间。同一个数组所有的数据都是相同数据类型的,同时所有的数据在内存中的地址是连续的。
数组定义格式
数据类型 数组名[元素个数] = { };
例如:int a[5] = {1,2,3,4,5};
数组下标
注意!数组的下标是从0开始到数组元素个数-1
也就是从0开始数起
我们来遍历上面的数组a试试
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
printf("%d\n", a[0]);
printf("%d\n", a[1]);
printf("%d\n", a[2]);
printf("%d\n", a[3]);
printf("%d\n", a[4]);
getchar();
return 0;
}
结果为
数组元素是可以参与运算的,且遵循运算的法则
举个例子
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
a[0] = a[1];
a[3] = a[0] * a[4];
for (int i = 0;i < 5;i++)
{
printf("%d\n", a[i]);
}
getchar();
return 0;
}
结果为
数组在内存中的存储方式和大小
存储地址:以数组a为例,看一下这个数组所有元素的存储地址
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
for (int i = 0;i < 5;i++)
{
printf("%p\n", &a[i]);
}
getchar();
return 0;
}
int类型占4个字节,我们可以看到,每个元素之间相差4,说明他们是连续的。
注意!数组名是一个常量
a = 100这种赋值操作是错误的
数组名的地址和数组中第一个元素的地址一致
例如
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
printf("%p\n", &a[0]);
printf("%p\n", &a);
getchar();
return 0;
}
说明了数组名是一个地址常量,即指向数组的首地址的常量。
求数组在内存中占的大小
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
printf("%d\n", sizeof(a));
getchar();
return 0;
}
于是我们就可以得到这条公式:
数组在内存中占的大小=数组类型 * 元素个数
数组的初始化
在上文中提到了数组的定义格式,其实并不是一定要将数组的元素个数或者数组里有什么元素都在定义时写清楚,那得多麻烦,所以这里将详细的说明其他的写法。
1、静态初始化
即数组定义格式那种方法 int a[5]={1,2,3,4,5}
2、动态初始化
先定义数组,后初始化
例如
#include<stdio.h>
int main()
{
int a[3]; //定义数组
a[0] = 4; //初始化a[0]
a[1] = 5; //初始化a[1]
a[2] = 6; //初始化a[2]
for (int i = 0; i < 3; i++)
{
printf("%d\n", a[i]);
}
getchar();
return 0;
}
3、数组部分初始化
数组部分初始化是指对数组一部分元素进行初始化,例如:
int a[5] = {1,2,3}
在 [ ] 中指定数组长度为5,但只对前3个元素初始化,系统会自动将剩下的元素初始化为0。
4、数组一次性赋值为0(推荐使用)
先全部初始化为0,后续在赋值
int a [5]={0}
a[0]=4
a[1]=3
5、定义数组,不指定长度(了解即可)
只要一路往下写,编译器会自动计算数组长度,如果自己想知道这个数组有多少个元素的话,可以通过sizeof函数进行运算:
int a[]={1,2,3,4,5}
sizeof(a)/sizeof(a[0])
注意!!!
1、数组的初始化是必不可少的,也就是说必须给数组元素赋值(静态赋值或动态赋值),不然就会造成内存混乱。
2、还有一点很重要的是:在定义数组时,不能使 [ ] 和 { } 同时为空,后面再赋值,这样的话会编译错误。
3、如若设定了数组长度,但是在初始化的时候超出了长度,那么数组会从左往右读所设定的数组长度的元素。例如:int a[3]={1,2,3,4,5},但是实际上只能显示1,2,3。输出时也不能超过数组最大下标,超出部分输出结果是未知的。
字符数组
在C语言中,没有定义字符串类型,为了解决这个问题,C语言中用字符数组来储存字符串。
C语言中,为区分普通字符数组和字符串,规定以字符’\0’作为字符串结束标志。例如:
char c[ ]={‘H’,‘e’,‘l’,‘l’,‘o’,‘w’,‘o’,‘l’,‘r’,‘d’,’\0’}
也可简化地写成 char c[ ]=“Hello word”(编译器会自动帮我们在后面加上’\0’
注意:
1、’\0’是一个字符,也会算作数组的一个元素个数的,所以设置数组长度时不要忘了把’\0’也计算在内。
2、只要读到 \0,就会自动认为读取已经结束,所以 \0 只能放在数组的末尾。
3、虽然遇到 \0 后数组不再往后读取,但是数组的长度是不会发生变化的。举个例子:
#include<stdio.h>
int main()
{
char c[] = "Hello world!";
char c1[] = "Hello \0world!";
printf("%s %d\n",c, sizeof(c) / sizeof(c[0]));
printf("%s %d\n",c1,sizeof(c1) / sizeof(c1[0]));
getchar();
return 0;
}
(注:数组c1末尾也有编译器自动加的 \0,所以比数组c多一个 \0,也就多一个字符)
计算字符数组长度的另一方法——strlen
可用于计算字符串有效长度(指字符串中 '\0’之前的字符个数,不包括 ‘\0’)。
注意要先引入头文件
#include<string.h>
举个例子实践一下
#include<stdio.h>
#include<string.h>
int main()
{
char c[] = "Hello world!";
char c1[] = "Hello \0world!";
printf("%s %d\n",c, strlen(c));
printf("%s %d\n",c1,strlen(c1));
getchar();
return 0;
}
数组案例1:计算两个等长数组元素和
已知2个等长数组 int nums1[3]={1,2,3}, int nums2[3]={4,5,6},求算两个数组中对应下标一致元素的加和。
#include<stdio.h>
int main()
{
int nums1[3] = { 1,2,3 };
int nums2[3] = { 4,5,6 };
int nums3[3] = { 0 }; //数组初始化
int len1 = sizeof(nums1) / sizeof(nums1[0]); //求算nums1的元素数
int len2 = sizeof(nums2) / sizeof(nums2[0]); //求算nums2的元素数
if (len1 = len2) //判断两数组是否等长,一定要等长才能相加
{
for (int i = 0; i < len1; i++)
{
nums3[i] = nums1[i] + nums2[i];
printf("%d\n", nums3[i]); //实现两数组相加并储存到nums3里然后打印出来
}
}
else
{
printf("两数组长度不相等\n");
return 0;
}
getchar();
return 0;
}
数组案例2:查找数组中的最大值
已知数组 int nums[ ]={3,5,999,2,12},编写程序找到数组中的最大值。
#include<stdio.h>
int main()
{
int nums[] = { 3,5,999,2,12 };
int size = sizeof(nums) / sizeof(nums[0]);
int i;
for (i = 0; i < size; i++)
{
if (nums[0] < nums[i + 1])
{
nums[0] = nums[i + 1];
}
}
printf("%d", nums[0]);
getchar();
return 0;
}```
//输出999,完成任务,于是整了个升级版的
```c
#include<stdio.h>
int main()
{
int nums[100];
int size = sizeof(nums) / sizeof(nums[0]);
int i;
nums[0] = 3;
nums[1] = 5;
nums[2] = 999;
nums[3] = 2;
nums[4] = 12;
nums[5] = 33*33;
for (i = 0; i < size; i++)
{
if (nums[0] < nums[i + 1])
{
nums[0] = nums[i + 1];
}
}
printf("%d", nums[0]);
getchar();
return 0;
}
这样就可以比较自己输入进去的数或者算式结果的最大值了。
补充小点——字符串函数
1、atoi字符串转整形
函数原型:int atoi(const char*str);
注意!要包含头文件#include<stdlib.h>,并且只能是数字字符串转整形,如“123”转123,"xyz"转成整形不可实现。
实践一下
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i = 123;
char s[] = "123";
int i1 = atoi(s); //将字符串123转成整型123
printf("%d\n", i1); //输出整型
printf("%d", i == i1); //判断整型i和字符串转整型i1是否相等
getchar();
return 0;
}
2、itoa函数整型转换为字符串
函数原型:charitoa(int value,charstring,int radix)
头文件:#include<stdlib.h>
稍微解释一下小括号里的东西:
value:要转换的整数
string:要写入转化结果的目标数组(提前申请好储存空间)
radix:转化进制,可以是10进制、16进制等。
了解即可
3、sprintf字符串格式化函数
函数原型:int sprintf( char *buffer,const char *format,[ argument ] )
头文件:#include<stdio.h>
稍微解释一下小括号里面的东西:
buffer:保存格式化字符串的目标字符缓冲区
format:格式化后的字符串
[ argument ]:参数列表
实践一下
#include<stdio.h>
int main()
{
char buffer[32] = { 0 };
sprintf(buffer, "name=%s,age=%d", "Su Zinao", 19);
printf("%s", buffer);
getchar();
return 0;
}
除此之外,sprintf还有其他用途
还可用于整数与整数字符串、浮点数与浮点字符串之间的转换。
例如
#include<stdio.h>
int main()
{
char buffer_int[10] = {0};
char buffer_float[10] = {0};
sprintf(buffer_int, "%d", 100);
sprintf(buffer_float, "%f", 3.14);
printf("%s\n", buffer_int);
printf("%s\n", buffer_float);
getchar();
return 0;
}
数组这里算是告一段落了,准备开始学习指针了。