一维数组
什么是数组呢?
我们之前学过数组是一组数据,方便记录数据,那到底什么才是数组呢,今天我们就来详细介绍一下!
数组的定义
数组是一组相同类型元素的集合。
相同类型元素的集合
我们回忆一下学过那些类型的数据
整型,浮点型,字符型
所以应该这些相同类型的元素的的集合就是数组
int short long long char double float
一维数组的创建和初始化
数组的创建
//数组的创建 int arr[2]; char arr1[5]; double arr2[5];
总结:数据类型+数组名[常量表达式];
数据类型:指定数组类型
数组名:就像我们的变量名一样
常量表达式:指定元素个数,必须是常量表达式
数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。 看代码:
//数组的创建和初始化 int arr1[2]={1,3}; int arr2[] = {1,2,3,4}; //未定义数组个数由初始化元素个数确定 int arr3[5] = {1,2,3,4,5}; char arr4[3] = {'a',98, 'c'}; char arr5[5]={'a','c','d','e','f'}; float arr5[3]={3.14,1.3,6.7};
总结:
数组在创建的时候如果想不指定数组的确定的大小就得初始化。
数组的元素个数根据初始化的内容来确定。
但是对于下面的代码要区分,内存中如何分配?
//字符数组 char arr1[]="abcdef"; //字符串含'\0'; char arr2[]={'a','b','c','d','e','f'};
可以看到数字初始化成字符串的形式,数组长度比,字符数组的形式多了一个\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<10; i++)//这里写10,好不好? { arr[i] = i; } //输出数组的内容 for(i=0; i<10; ++i) { printf("%d ", arr[i]); } return 0; }
注:
数组的第一个元素的下标并不是arr[1],而是arr[0],数组的下标是从0开始访问的,如果有n个元素,那么最后一个元素的下标应该是arr[n-1]
初始化的[]代表元素个数,而访问时[]代表的是下标。
一维数组在内存中的存储
int arr[10]={0,1,2,3,4,5,6,7,8,9};
可以看到数组arr在内存中的存储如下:
总结:
数组元素之间的地址是连续的且相差数组类型个字节(int 类型相差4个字节,char类型1个字节)
数组的第一个元素的地址就是数组的地址
数组在内存中是连续存放的
二维数组
二维数组本质上是以数组作为数组元素的数组,即“数组的数组”,类型说明符 数组名[常量表达式][常量表达式]。
二维数组的创建和初始化
二维数组的创建
int arr1[5][5]; char arr2[3][5]; double arr[2][3];
二维数组的初始化
//从第一个元素开始初始化,未初始化的元素默认初始为0 int arr1[2][3]={1,2,3,4}; //按照每行初始化,每行未初始化的元素默认初始为0, int arr2[2][3]={{1,2},{3,4}}; //根据初始化的行数确定数组的行数 int arr3[][3]={{1,2},{3,4}};
注:初始化时,行号可以省略,列号不可省略
二维数组的使用
#include<stdio.h> int main(void) { int i = 0, j = 0; //初始化 int arr[4][4] = { {1,2,3},{4,5,6},{7,8,9} }; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { printf("%d ", arr[i][j]); } //换行 printf("\n"); } return 0; }
二维数组在内存中的储存
二维数组像一维数组一样,这里我们尝试打印二维数组的每个元素!
#include <stdio.h> int main() { int arr[3][4]; int i = 0; for(i=0; i<3; i++) { int j = 0; for(j=0; j<4; j++) { printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]); } } return 0; }
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。
数组传参
一维数组作为函数参数
往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序函数,将一个整形数组排序
//方法一 #include<stdio.h> bubble_sort(int arr[]) { int i=0,j=0; int sz=sizeof(arr)/sizeof(arr[0]); int flag=0; for(i=0;i<sz-1;i++) { for(j=0;j<sz-1-i;j++) { if(arr[j]<arr[j+1])//降序 { flag=1; int tmp=0; tmp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp; } if(flag==0) break; } } } int main() { int arr[]={1,3,5,7,2,6,4,8,10,9}; bubble_sort(arr);//是否可以正常排序? int i=0; for(i=0;i<10;i++) { printf("%d ",arr[i]); } }
方法1,出问题,那我们找一下问题,调试之后可以看到bubble_sort 函数内部的sz ,是1。
难道数组作为函数参数的时候,不是把整个数组的传递过去?
可以看到形参arr并不是数组,而是只有一个元素,sz=1,难道arr是地址?
可以看到在64位平台,sz=2验证了我们的猜测,arr就是地址,虽然形参是以arr[]数组的形式接收的,但还是地址,地址就只有4/8个字节。
所以数组长度只能在函数外部计算好传参进去!
数组名是什么
数组名是数组首元素的地址。(有两个例外)
如果数组名是首元素地址,那么:为什么输出的结果是:40?
补充:
sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。
除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。
//改进后 #include<stdio.h> void bubble_sort(int arr[],int sz) { int i=0,j=0; int flag=0; for(i=0;i<sz-1;i++) { for(j=0;j<sz-1-i;j++) { if(arr[j]<arr[j+1])//降序 { flag=1; int tmp=0; tmp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp; } if(flag==0) break; } } } int main() { int arr[]={1,3,5,7,2,6,4,8,10,9}; int sz=sizeof(arr)/sizeof(arr[0]); bubble_sort(ar,sz);//是否可以正常排序? int i=0; for(i=0;i<sz;i++) { printf("%d ",arr[i]); } }
我们已经知道,数组传参,数组名就是数组地址也是首元素地址,而我们用数组名接收或者数组接收得到的都是数组的地址;
既然我们用指针接收,那么我们就可以用指针的形式解引用!
void bubble_sort(int* arr,int sz) { int i=0,j=0; int flag=0; for(i=0;i<sz-1;i++) { for(j=0;j<sz-1-i;j++) { // if(arr[j]<arr[j+1])//降序 if(*(arr+j)<*(arr+j+1)) { flag=1; int tmp=0; tmp=*(arr+j); *(arr+j)=*(arr+j+1); *(arr+j+1)=tmp; } if(flag==0) break; } } }
我们可以知道arr[1]等价于*(arr+1)!
二维数组传参
二维数组,传参的方式和一维数组一样,但是数组名就不是,首元素地址了,而是首行地址,我们来验证一下。
arr+1后地址向后走了16个字节,所以当我们二维数组以数组名传参后得到的是行指针。像一维数组一样,而我们肯定还要将二维数组的行列数传参才能控制二维数组。
//实现二维数组的打印 print(int arr[][3],int x,int y) { int i=0,j=0; for(i=0;i<x;i++) { for(j=0;j<y;j++) { printf("%d ",arr[i][j]); //printf("%d ",*(*(arr+i)+j)); //地址的形式 } printf("\n"); } } int main() { int arr[4][3]={1,3,4,5,6,7,5,7,2,7,1,0}; print(arr,4,3); }
总结
像二维数组的初始化一样,二维数组的形参行数不能省略。
二维数组的数组名是第一行的行指针。
arr[i][j]等价于*( *(arr+i)+j),*(arr+i)解引用找到行指针存放的一行元素(一维数组)的地址,*( *(arr+i)+j)解引用找到该元素!