数组的定义
/*
变量如何定义?
数据类型 变量名称
数组如何定义?
数据类型 数组名称[数据的个数] 这样
元素类型 数组名称[元素个数]
元素类型:就是数组中要存储的数据类型,一旦指定数组中就只能存储该类型的数据
元素个数:就是数组中能够存储的数据个数
*/
int scores[3]; // 定义了一个数据名称为 scores,数组中可以存储三个 int 类型的数据
// 如何在内存中存储呢?
// 先分配一个 12 个字节的空间给 scores,这个数组中n可以存放三个 int 类型的数据,那么就会等分成三个,四个字节的内存空间用来存储 int 类型的数据
// 那么如何存值呢?
// socres 中有三个小的空间,需要指定给哪个空间赋值
// 只要 C语言定义了数组,那么系统就会给每个小的空间存储一个编号,这个编号称之为索引
// 那么就只需要指定编号就可以赋值了
scores[0] = 12;
// 这个时候会将 12 的值赋值给 scores 存储空间中索引为 0 的空间中
printf("scores[0]=%i\n",scores[0]);
数组的初始化
// 数组的初始化
int scores[5];
scores[0] = 10;
scores[1] = 20;
scores[2] = 30;
scores[3] = 40;
scores[4] = 50;
// 这样写很 low 哇,是不是很累啊
// 完全初始化
int scores1[5] = {1,2,3,4,5};
// 部分初始化
// 在部分初始化中对应的内存没有被初始化,那么值默认为 0
int scores2[5] = {1,2}; // 默认从 0开始初始化
printf("scores2[0]=%i\n",scores2[0]);
printf("scores2[1]=%i\n",scores2[1]);
printf("scores2[2]=%i\n",scores2[2]); // 0
printf("-------\n");
int scores3[3];
printf("scores3[0]=%i\n",scores3[0]);
printf("scores3[1]=%i\n",scores3[1]);
printf("scores3[2]=%i\n",scores3[2]);
// 此时整个数组都没有初始化,只是定义了话,有时打印的不是 0,注意只有部分初始化的时候,没有初始化的值才为 0.同时也不要随意使用没有初始化的值,可能是一段垃圾数据
// 注意定义数组的时候,数组的个数不能使用变量,如果使用了变量,数组中的值会是一些垃圾的值
/*
int num = 10;
int scores[num];// 报错,变量是一个动态的值,不清楚要分配多少内存空间
*/
// 如果定义的同时进行初始化,那么元素的个数可以被省略
// 省略之后,初始化了几个数据,那么数组的长度就是几,也就是数据可以存储几个数据
int scores5[] = {1,3};
printf("scores5[0]=%i\n",scores5[0]);
printf("scores5[1]=%i\n",scores5[1]);
// 如果定义的同时没有进行初始化,那么元素的个数不能省略会直接报错
// int scores6[]; // 此时直接报错
// 指定位置初始化
int scores7[5] = {0,0,0,3,4};
int scores8[101] = {[99]=1,[100]=2};
printf("scores8[99] = %i\n",scores8[99]); // 1
printf("scores8[100] = %i\n",scores8[100]); // 2
// 大括号只能在定义的同时才可以使用,
// 先定义在初始化
int scores9[3];
scores9[0] = 1;
scores9[1] = 1;
scores9[2] = 1;
数组的遍历
// 数组的遍历
int nums[6] = {99,88,77,55,66,44};
for (int i = 0; i <= 6; i++) {
printf("nums[%i] = %i\n",i,nums[i]);
}
// 这么写可以但是,如果以后数组的长度发生了变化呢?还是需要修改,能否动态修改这个长度呢?
int leight = sizeof(nums) / sizeof(nums[0]);
printf("leight = %i\n",leight);
// 通过 sizeof 查出nums 这个数组的总内存空间的长度,再通过 sizeof 查出数组中第一个元素的长度(因为数组只能存储同一个类型的元素,所以每个元素所占的内存空间都是一样的),两个相除就是这个数组的长度
for (int i = 0; i <= leight; i++) {
printf("nums[%i] = %i\n",i,nums[i]);
}
数组的内存存储
- 变量存储数据是从高字节开始存储
- 数组存储数据是从低字节开始存储
// 数组的内存存储是从低字节开始存储,变量存储是从高字节开始存储
char charValue[4] = {'a','v','c','d'};
printf("charValue[0] = %p\n",&charValue[0] ); // 0x7ffeefbff20c
printf("charValue[1] = %p\n",&charValue[1] ); // 0x7ffeefbff20d
printf("charValue[2] = %p\n",&charValue[2] ); // 0x7ffeefbff20e
printf("charValue[3] = %p\n",&charValue[3] ); // 0x7ffeefbff20f
// 可以看出随着索引的变化,内存地址是变大的,所以数组的内存存储是从低字节开始存储的
char charValue[4] = {'a','v','c','d'};
printf("charValue 数据名的内存地址:%p\n",&charValue);
printf("charValue[0] = %p\n",&charValue[0] );
/*
charValue 数据名的内存地址:0x7ffeefbff20c
charValue[0] = 0x7ffeefbff20c
*/
&charValue = charValue[0] = charValue
- 数组的每一个元素是从低字节开始存储,但是每个元素中的值又是从高字节开始存储
数组注意点
- 在使用数组的时候一定不要访问不是属于自己的存储空间,这样会导致数据混乱
// 数组的注意点
char num[2] = {1,2};
char value[3] = {4,5,6};
value[3] = 44;
printf("num[0] = %i\n",num[0]);
// 控制台输出
// num[0] = 44
数组的练习
// 练习
// 从键盘输入三个数,计算总值和平均值
// 不使用变量接收,使用数组接收
int nums[3] = {-1};// 数组部分初始化
int leight = sizeof(nums) / sizeof(nums[0]);
for (int i = 0; i < leight; i++) {
printf("nums[%i] = %i\n",i,nums[i]);
}
printf("----------\n");
for (int i = 0; i < leight; i++) {
printf("请您输入一个数,回车结束\n");
scanf("%i",&nums[i]); // 赋值给每个索引的值
// 1printf("nums[%i] = %i\n",i,nums[i]);
}
printf("----------\n");
int sum = 0;
for (int i = 0; i < leight; i++) {
printf("nums[%i] = %i\n",i,nums[i]); // 打印每个索引的值
// sum = sum + nums[i];
sum += nums[i];
}
printf("求和的值:%i\n",sum);
printf("求平均值的值:%i\n",sum/leight);
数组和函数
// 数组和函数
// 基本数据类型是值传递
int num = 10;
test(num);
printf("num = %i\n",num); // 此时 num 的值还是 10,并不 50,因为基本数据类型是值传递
printf("main函数中的 num 内存地址:%p\n",&num);
// 此时看一看我们传递一个数组
int array[] = {1,2,3};
testArray(array);
printf("array[0] = %i\n",array[0]); // 100,因为数组是地址传递,内存地址在哪里修改了都会受到影响
printf("array[1] = %i\n",array[1]); // 2
printf("array[2] = %i\n",array[2]); // 3
printf("main函数中testArray[0]的内存地址:%p\n",&array[0]);
printf("main函数中testArray[1]的内存地址:%p\n",&array[1]);
printf("main函数中testArray[2]的内存地址:%p\n",&array[2]);
// 通过打印内存地址可以看到,基本数据类型在方法中都是新开辟的内存地址,数组并不是
return 0;
}
void test(int num){
num = 50;
printf("test 方法中的 num 内存地址:%p\n",&num);
}
void testArray(int array[]){
array[0] = 100;
printf("testArray方法中的 array[0]的内存地址:%p\n",&array[0]);
printf("testArray方法中的 array[0]的内存地址:%p\n",&array[1]);
printf("testArray方法中的 array[0]内存地址:%p\n",&array[2]);
}
// 注意只需要看函数的参数是传递的基本数据类型还是指针(地址)就可以
main(){
// 要求实现一个函数,只要传递的是一个数组,就返回数组中所有的值
int array1[5] ={1,2,3,4,5};
int leight = sizeof(array1)/sizeof(array1[0]);
getArrayNum(array1,leight);
return 0;
}
int getArrayNum(int array1[],int leight){
// int leight = sizeof(array1)/sizeof(array1[0]);
// 这里不能将 leight在这里计算,因为传递的是一个数组的地址,地址永远是占 8 个字节
for (int i = 0; i < leight; i++) {
printf("array1[%i] = %i\n",i,array1[i]);
}
return 0;
}
练习 2
main(){
// 设计一个函数 int arrayMax()找出数组元素的最大值
int array[] = {0,-5,3,8};
int leight = sizeof(array)/sizeof(array[0]);
int maxNum = arrayMax(array,leight);
printf("最大值是:%i\n",maxNum);
return 0;
}
// 错误的写法,用第一个元素跟第二个元素比较,这种比较会超出数组的长度.返回一个垃圾值
int arrayMax(int array[],int leight){
int temp = 0;
for (int i = 0; i < leight; i++) {
if(array[i] >= array[i+1]){
temp = array[i];
}
else{
temp = array[i+1];
}
}
return temp;
}
// 方法一 (设置一个临时值,用这个临时值跟数组的没一个值作比较,如果临时值小于,那就替换)
int arrayMax(int array[],int leight){
int temp = 0;
for (int i = 0; i < leight; i++) {
if(temp <= array[i]){
temp = array[i];
}
}
return temp;
}
// 但是方法一还存在问题,如果数组中的数都小于临时值的话那就出现了 bug
// 所以用数组中的一个数作为最大值
int arrayMax(int array[],int leight){
int temp = array[0];
for (int i = 0; i < leight; i++) {
if(temp <= array[i]){
temp = array[i];
}
}
return temp;
}
//方法二 定义一个temp 值为索引值,
int arrayMax2(int array[],int leight){
int temp = 0;
for (int i = 1; i < leight; i++) { // 此处 i 可以从 1 开始
if(array[temp] <= array[i]){
temp = i;
}
}
return array[temp];
}
练习 3
// 从键盘输入3 个 0-9 之间的数,然后输出 0-9 之间那些数没有出现过
int num1,num2,num3;
printf("输入\n");
// scanf("%i",&num1);
// scanf("%i",&num2);
// scanf("%i",&num3);
scanf("%i,%i,%i",&num1,&num2,&num3);
printf("输入结束\n");
int array[3] = {num1,num2,num3};
int leight = sizeof(array)/ sizeof(array[0]);
for (int i = 0; i <= 9; i++) {
if(array[0] != i &&
array[1] != i &&
array[2] != i){
printf("%i没出现过\n",i);
}
}
// 方法二,输入三个数,使这三个数作为下标,将次s复制为 1,那么值 为 0 的就是没有输入过的数
int array[10] = {0}; // 部分初始化,没有被初始化的都为 0,并不是垃圾值
int value = -1;
int leigth = sizeof(array) / sizeof(array[0]);
for (int i = 0; i < 3; i++) {
printf("请输入第%i个数,回车结束\n",i+1);
scanf("%i",&value);
array[value] = 1;// 将每次的 value 值复制给
}
for (int i = 0; i < leigth; i++) {
printf("数组第%i 个的值:%i\n",i,array[i]);
}
for (int i = 0; i < leigth; i++) {
if(array[i] != 1){//只要是 值为 0 的那么就是没有出现过的,巧妙的利用了 0-9 之间的数,先将输入的数当做下标,把数组的这个下标的值设置为 1,那么m不是1 的值,他的下标就是么有c输入过的
printf("0-9 之间没有出现过:%i\n",i);
}
}
练习 4
// 要求从键盘输入6 个 0-9 之间的数,排序后输出
// 分析:部分初始化一个数组,依次输入 6 个数字,循环将输入的 6 个数作为下标,将数组中的数赋值为 1,那么此数组中值为 1 的下标就是输入的数,再次循环输出值为 1 的下标,既从小到大输出
int array[10] = {0}; // 部分初始化
int value = -1;
int leight = sizeof(array) / sizeof(array[0]);
for (int i = 0; i < 6; i++) {
printf("请输入第%i个值:\n",i+1);
scanf("%i",&value);
array[value] = 1;
}
for (int i = 0; i <= 9; i++) {
if(array[i] == 1){
printf("从小到大排序:%i\n",i);
}
}
// 改进:
// 但是输入了相同的值时,不会依次输出.而是将之前的值进行了覆盖
int array[10] = {0}; // 部分初始化
int value = -1;
int leight = sizeof(array) / sizeof(array[0]);
for (int i = 0; i < 6; i++) {
printf("请输入第%i个值:\n",i+1);
scanf("%i",&value);
array[value] += 1; // 此处如果多次输入了d同一个下标,那么就进行加 1
}
for (int i = 0; i <= 9; i++) {
if(array[i] != 0){ // 如果所在角标的值不是 0,那么久开始循环,条件表达式是 j<=这个下标所对的值
for (int j = 1; j <= array[i]; j++) {
printf("从小到大排序:%i\n",i);
}
}