数组的基本概念
-数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的
-在C语言
1.什么是数组?
数组是一组相同类型的数据的有序合集
2.如何定义一个数组
数据类型 变量名称;
元素类型 数组名称[元素个数];
元素个数:告诉操作系统,将来数组中需要存储多少条数据
元素类型: 告诉操作系统,将来数组中存储的每一条数据都是什么类型的
只有告诉操作系统总共需要存储多少条数据,每一条数据是什么类型的,操作系统才知道需要开辟多大的存储空间
数组名称:和变量名称一样,可以通过数组名称找到数组对应的存储空间,然后操作这块存储空间
int age[5];
20个字节的存储空间
0 | 1 | 2 | 3 | 4 |
4个字节 4个字节 4个字节 4个字节 4个字节
3.如何操作数组?
3.1如何往数组中存储数据
数组名称[索引号]=值
3.2如何从数组中获取数据
数组名称[索引号]
需求:要求定义变量保存用户的年龄
需求:要求定义变量保存一般班级所有用户的年龄
1.什么是数组的遍历?
数组的遍历就是取出数组中的所有的元素
1.sizeof(数组名)得到的是数组占用的总大小
2.sizeof(数组名[索引])得到的是数组中每一个元素大小
数组的存储细节
1.数组的存储细节
1.1和变量一样,会从内存地址大的开始分配存储空间
1.2和变量一样,数组的地址就是数组占用内存空间最小的地址
1.3和变量不一样,给数组每一个元素分配存储空间,是从数组占用存储空间最小的地址开始分配
1.4和变量一样,存储数据也会从每个元素内存地址大的开始存储
变量名称 | 元素索引 | 地址 | 内存 |
0FFFFF | 0000 0000 | ||
0FFFFE | 0000 0000 | ||
0FFFFD | 0000 0000 | ||
num | 0FFFFC | 0000 1001 | |
0FFFFB | |||
0FFFFA | |||
0FFFF9 | |||
age | 0FFFF8 | ||
0FFFF7 |
int age[1];
数据从高位存储
2.变量的存储细节
数组的注意点
1.在老版本中的C语言标准中,数组的元素个数只能是常量,不能是变量
在新版本的C语言标准中,数组的元素个数可以是常量,也可以是变量
在企业开发中,但凡需要定义数组,数组的元素个数清一色使用常量
2.在使用数组的时候,一定不要超出数组的索引的范围
如果在企业开发中访问了不属于自己的索引对应的存储空间
程序可能会奔溃或者访问到不属于自己的数据
数组作为函数参数
1.数组作为函数的参数
数组名作为函数的参数,在函数内修改形参,会影响到外界的实参
如果函数的形参是一个数组,当传入数组名的时候,相当于把地址传进去了,变量的地址等于数组的地址
2.基本数据类型作为函数的参数
int char float double
在函数内修改形参,不会影响到外界的实参
函数执行完了对应的存储空间就释放了
需求:要求定义一个函数,用于遍历传入的数组
由于数组名称保存的是数组的地址,所以传递给函数的就是数组的地址
由于在C语言中地址也是一种数据类型,这个种类我们称之为指针类型
指针类型在32位编译器下占用4个字节,在64位编译器下占用8个字节
所以在函数中通过sizeof计算出来的是指针类型的大小,而不是数组的大小
结论:不能在函数中计算传入数组的长度
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ages[5]={1,3,5,7,9};
int len = sizeof(ages)/sizeof(ages[0]);
printArray(ages,len);
printf("ages size = %i\n",sizeof(ages));
return 0;
}
void printArray(int value[5],int len)
{
printf("value size = %i\n",sizeof(value));
for(int i=0;i<len;i++)
{
printf("value[%i]= %i\n",i,value[i]);
}
}
因为数组名在做形参的时候转化成了指向这个数组第一个元素的指针
数组练习1:定义一个函数,获取数组中的最大值。
#include <stdio.h>
#include <stdlib.h>
int main()
{
//需求:定义一个函数,获取数组中的最大值
int nums[5]={1,2,3,6,4};
//1.定义变量保存最大值
int max = nums[0];//假设零是最大值
//2.遍历数组取出元素
int len = sizeof(nums) / sizeof(nums[0]);
for(int i=1;i<len;i++)
{
//3.利用当前遍历到的元素和最大值进行比较
if(nums[i]>max)
{
// 4.将最大值修改为当前的元素
max = nums[i];
}
}
printf("max = %i\n",max);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
//需求:定义一个函数,获取数组中的最大值
int nums[5]={1,2,3,6,4};
//1.定义变量保存最大值
//2.遍历数组取出元素
int len = sizeof(nums) / sizeof(nums[0]);
getMax(nums,len);
return 0;
}
int getMax(int value[5],int len){
int max = value[0];//假设零是最大值
for(int i=1;i<len;i++)
{
//3.利用当前遍历到的元素和最大值进行比较
if(value[i]>max)
{
// 4.将最大值修改为当前的元素
max = value[i];
}
}
printf("max = %i\n",max);
}
数组元素默认值
1.如果只定义了变量没有赋值,没有对变量进行初始化,那么变量中保存的就是垃圾数据
2.如果只定义数组,没对数组进行初始化,那么数组中的每一个元素保存的都是垃圾数据
3.如果先定义后初始化,那么被初始化的元素会变成初始化的数据,没有被初始化的元素还是垃圾数据
4.如果定义的同时初始化,那么被初始化的元素会变成初始化的数据,没有被初始化的元素变成0
需求:从键盘输入3个0~9的数字,然后输出0~9中哪些数字没有出现过
输入:1,3,5
输出:0,2,4,6,7,8,9
1.提示用户如何输入数据
2.定义变量保存用户输入的数据
3.接收用户输入的数据
4.通过循环获得0~9中所有数
5.判断当前拿到的数是否出现过,如果没有出现过就输出
方法一:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// 1.提示用户如何输入数据
printf("请输入3个0~9的整数,以逗号隔开,以回车结束\n");
//2.定义变量保存用户输入的数据
int a,b,c;
//3.接收用户输入的数据
scanf("%i %i %i",&a,&b,&c);
//4.通过循环获得0~9中所有数
for(int i=0;i<10;i++)
{
//5.判断当前拿到的数是否出现过,如果没有出现过就输出
if(i!=a && i!=b && i!=c)
printf("%i ",i);
}
return 0;
}
方法二:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
//1.提示用户如何输入数据
printf("请输入三个0~9的整数,以回车结束\n");
//2.定义变量保存用户输入的数据
int value;
int nums[10]={0};
//{0,0,0,0,0,0,0,0,0,0}
//3.接收用户输入的数据
//{0,666,666,666,0,0,0,0,0,0,0}
for(int i=0;i<3;i++)
{
scanf("%i",&value);
//4.利用用户输入的数据作为数组的索引去操作数组
nums[value] = 666;
}
//5.遍历数组
for(int i=0;i<10;i++)
{
//取出当前元素,判断元素中存储的时候是666
//如果存储的是666就不输出,如果存储的不是666就输出数组对应的索引
if(nums[i] == 666)
{
continue;
}
printf("%i ",i);
}
return 0;
}
for(int i=0;i<5;i++)
{
scanf("%i",&value);
nums[value] = 666;
}
nums[10]={666,0,0,0,666,0,0,0,666,666};
数组计数排序
需求:要求从键盘输入5个0~9的数字,排序后输出
输入:3,1,5,8,2
输出:1,2,3,5,8
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
//需求:要求从键盘输入5个0~9的数字,排序后输出
//索引 0 1 2 3 4 5 6 7 8 9
// {0,6,6,6,0,6,0,0,6,0}
// 输入:3,1,5,8,2
//输出:1,2,3,5,8
//1.提示用户输入数据
printf("请输入5个整数,以回车结束\n");
//2.定义变量保存用户输入的数据
int value;
int nums[10]={0};
//3。接收用户输入的数据
for(int i=0;i<5;i++)
{
scanf("%i",&value);
//4.将用户输入的数据,作为数组的索引去操作数据
nums[value]=6;
}
//5.遍历数组,取出所有元素
for(int i=0;i<10;i++)
{
//6.判断当前元素有没有存储数据,如果存储了数据,输出索引
if(nums[i]==6)
{
printf("i = %i\n",i);
}
}
return 0;
}
当输入数据重复的时候
例如:3 2 3 8 5
防止输入重复的解决方法
数组选择排序
0 | 1 | 2 | 3 |
4 | 3 | 5 | 1 |
输出***的两种方法:
**
*
数组冒泡排序
思路是相邻的第一个跟第二个比,第二个跟第三个比,第三个跟第四个比............
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nums[4]={4,3,5,1};
int len = sizeof(nums)/sizeof(nums[0]);
printarray(nums,len);
for(int i=0;i<3;i++)
{
for(int j=0;j<3-i;j++)
{
if(nums[j]>nums[j+1])
{
int temp;
temp = nums[j];
nums[j] = nums[j+1];
nums[j+1]= temp;
}
}
}
printf("------------------\n");
printarray(nums,len);
return 0;
}
void printarray(int nums[4],int len)
{
for(int i=0;i<len;i++)
{
printf("nums[%i]=%i\n",i,nums[i]);
}
}
数组折半查找
需求:从有序数组中找出指定值的位置
找到指定的值对应的索引
mid=(min+max)/2
1.每次都取出mid对应的值和要查找的值比较
2.如果取出的值小于我们要找的值,就让min变成mid+1,然后重新计算mid值
3.如果取出的值大于我们要找的值,就让max变为mid-1,然后重新计算mid值
4.如果min都大于max还没找到,那么就不用找了
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nums[5]={1,3,5,7,9};
int key=5;
/*
1.每次都取出mid对应的值和要查找的值比较
2.如果取出的mid值小于我们要找的值(key),就让min变成mid+1,然后重新计算mid值
3.如果取出的mid值大于我们要找的值(key),就让max变为mid-1,然后重新计算mid值
4.如果min都大于max还没找到,那么就不用找了
*/
int min=0;
int len = sizeof(nums)/sizeof(nums[0]);
int max=len-1;
int mid=(min+max)/2;
while(min<=max)
{
if(nums[mid]>key)
{
max = mid-1;
mid = ( max+min )/2;
}
else if(nums[mid] < key)
{
min = mid+1;
mid = ( max+min )/2;
}
else
{
printf("index = %i\n",mid);
break;
}
printf("没有找到");
}
return 0;
}