1、初始化
1.1 整体初始化
(1)代码1
#include <stdio.h>
void main(){
int arr[12];
for(int i=0;i<12;++i){
printf("%d ",arr[i]);
}
}
(2)代码2
#include <stdio.h>
void main(){
int arr[12] = {0};
for(int i=0;i<12;++i){
printf("%d ",arr[i]);
}
}
(3)代码3
#include <stdio.h>
void main(){
int arr[12] = {2};
for(int i=0;i<12;++i){
printf("%d ",arr[i]);
}
}
(4)输出结果分析
1)代码1:输出全为不规则的数字 2)代码2:输出全为0 3)代码3:输出一个2,其他全为0
(5)结论
1)数组未初始化,数组里面的值都是随机值。
2)数组初始化为{0},数组里面的值都是0。
3)数组初始化为{非零值},数组里面第一个值是非零值,其他的值都是0。
1.2 部分初始化
#include <stdio.h>
void main(){
int arr[12] = {[2]=2,[5]=5};
for(int i=0;i<12;++i){
printf("%d ",arr[i]);
}
}
指定下标的值被赋值,其他为0
1.3 大小
#include <stdio.h>
void main(){
char carr[12];
int iarr[12];
double farr[12];
printf("carr = %d\n",sizeof(carr));
printf("iarr = %d\n",sizeof(iarr));
printf("farr = %d\n",sizeof(farr));
}
输出结果为: sizeof给出整个数组所占据的内容的大小。数组大小=元素大小*数组个数。
问题9:已知数组arr,如何求出数组元素个数? sizeof(arr)/数组类型大小 char =1 int=4 float=8
1.4 赋值
int days[]={31,28,31,30,31,30,31,31,30,31,30,31};
int arr = days;
这个时候的赋值是错误的,因为int只是在int一个类型,这个时候days代表的是数组days[]的首个元素或者首元素的地址
2、数组与指针
2.1 数组名是地址
数组名是数组第一个元素的地址
#include <stdio.h>
void main(){
int arr[] = {1,2,3,4,5,6,7,8};
printf("&arr=%p\n",&arr);
printf("arr=%p\n",arr);
printf("&arr[0]=%p\n",&arr[0]);
}
输出为:
&arr=000000000061FE00
arr=000000000061FE00
&arr[0]=000000000061FE00
数组下标实现的操作指针也可以实现。数组名+下标表示下标i元素的地址 所以,遍历数组可以是:
#include <stdio.h>
void main(){
int arr[] = {1,2,3,4,5,6,7,8};
for(int i=0;i<8;++i){
printf("%d\n",*(arr+i));
}
}
数组名是不可以改变的! i
nt arr1[] = {1,2,3,4,5,6,7,8};
int arr2[] = {1,2,3,4,5,6,7,8};
arr2 = arr1;
数组下标比较易于理解,数组指针更灵活更高效。 要点:
1)数组名是数组第一个元素的地址。
2)数组名+下标表示下标i元素的地址。
3)数组名是不可改变的。
2.2 数组名放入指针
地址存储在指针中。可以用指针操作地址。
#include <stdio.h>
void main(){
int arr[] = {1,2,3,4,5,6,7,8};
int* p = arr;
for(int i=0;i<8;++i){
printf("%d\n",*(p+i));
}
}
3、函数与数组
3.1 传递数组给函数
数组作为函数参数时,通常必须再用一个参数传入数组大小。
返回值类型 函数名(类型 参数名[],int size){
}
或者
返回值类型 函数名(类型* 参数名,int size){
}
3.1.1 实践1
#include <stdio.h>
void PrintArr1(int arr[],int n){
for(int i=0;i<n;++i){
printf("%d ",arr[i]);
}
printf("\n");
}
void PrintArr2(int* arr,int n){
for(int i=0;i<n;++i){
printf("%d ",arr[i]);
}
printf("\n");
}
int main(){
int arr[] = {1,2,3,4,5,6,7,8,9};
PrintArr1(arr,9);
PrintArr1(arr,3);
PrintArr1(arr+6,3);
PrintArr1(arr+3,3);
}
输出为: 1 2 3 4 5 6 7 8 9 1 2 3 7 8 9 4 5 6
3.1.2 实践2
#include <stdio.h>
void Test1(int a[]){
printf("sizeof(a):%d\n",sizeof(a));
printf("a:%p\t&a:%p\n",a,&a);
}
void Test2(int* p){
printf("sizeof(p):%d\n",sizeof(p));
printf("p:%p\t&p:%p\n",p,&p);
}
int main(){
int arr[10];
printf("sizeof(arr):%d\n",sizeof(arr));
printf("arr:%p\t&arr:%p\n",arr,&arr);
Test1(arr);
Test2(arr);
}
输出为:
sizeof(arr):40
arr:000000000061FDF0 &arr:000000000061FDF0
sizeof(a):8
a:000000000061FDF0 &a:000000000061FDD0
sizeof(p):8
p:000000000061FDF0 &p:000000000061FDD0
3.1.3 练习
(1)两个有序数组的归并
输入一个整数n(n <= 10000)和n个整数a[i],保证这n个整数已按照从小到大进行排序。然后输入一个整数m(m <= 10000),和m个整数b[j],保证这m个整数已按照从小到大进行排序。 将两组数归并后输出。 代码:
#include <stdio.h>
void GetArry(int arry[],int n){
for(int i=0;i<n;i++){
scanf("%d",&arry[i]);
}
}
void PrintArry(int arry[],int size){
for(int i=0;i<size;i++){
printf("%d\n",arry[i]);
}
printf("\n");
}
int main(){
int n,m;
scanf("%d",&n);
int a[n];
GetArry(a,n);
scanf("%d",&m);
int b[m];
GetArry(b,m);
int c[m+n];
int lengtha=sizeof(a)/sizeof(int);
int lengthb=sizeof(b)/sizeof(int);
int i=0,j=0,k=0;
while (i<lengtha && j<lengthb)
{
if(a[i]<=b[j]){
c[k++]=a[i++];
}else{
c[k++]=b[j++];
}
}
while(i<lengtha){
c[k++]=a[i++];
}
while (j<lengthb)
{
c[k++]=b[j++];
}
PrintArry(c,m+n);
}
3.2 从函数返回数组
C 语言不允许返回一个完整的数组作为函数的参数。通过指定不带索引的数组名来返回一个指向数组的指针。
类型* 函数名() {
return 数组名;
}
3.2.1 练习
(1)给定数组随机填充指定范围的数据。使用stdlib.h中的srand(time(NULL))和rand()。
#include <stdio.h>
#include <stdlib.h>
void PrintArry(int arry[],int n){
for(int i=0;i<n;i++){
printf("%d ",arry[i]);
}
printf("\n");
}
void main(){
int n;
scanf("%d",&n);
int a[n];
srand((int)(time(NULL)));
for(int i=0;i<n;i++){
a[i]=rand()%100;
}
PrintArry(a,n);
}
(2)将一维数组的查找FindArr()、替换Replace()封装成函数。
#include <stdio.h>
#include <stdbool.h>
void PrintArry(int arry[],int n){
for(int i=0;i<n;i++){
printf("%d ",arry[i]);
}
printf("\n");
}
int FindArry(int arry[],int n,int num){
for(int i =0;i<n;i++){
if(arry[i]==num){
return i;
}
}
return -1;
}
void ReplaceNum(int arry[],int n,int num,int repnum){
int index = FindArry(arry,n,num);
if(index!=-1){
arry[index]=repnum;
}
}
void main(){
int n;
scanf("%d",&n);
int a[n];
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
PrintArry(a,n);
int num;
printf("请输入要查询的数字:");
scanf("%d",&num);
int index=FindArry(a,n,num);
if(index!=-1){
printf("Found %d:[%d]\n",num,index);
int repnum;
printf("请输入替换的数字:");
scanf("%d",&repnum);
ReplaceNum(a,n,num,repnum);
PrintArry(a,n);
}else{
printf("Not Found %d\n",num);
}
}
3.2.2 重点
int arr[] = {1,2,3,4,5,6};
printf("sizeof(arr) = %ld\n",sizeof(arr));
printf("arr=%p\n&arr[0]=%p\n",arr,&arr[0]);
输出为:
sizeof(arr) = 24
arr=000000000061FE00
&arr[0]=000000000061FE00
数组名是地址,是常量。
1、可以使用指针操作:解引用
2、数组作为函数参数和返回值时,传指针/地址。
数组下标与数组长度的关系
1)arr长度为n,最后一个元素的下标为n-1。
2)下标为i是第i+1个元素,前面有i个元素(不包含i),后面有n-(i+1)个元素(不包含i)。
3)下标i和j之间有j-i个元素(包含i,不包含j)
数组地址与数组名的关系
1)数组arr的首地址为arr,下标为i的地址为arr+i。
2)令p=arr+i,那么下标对应为p-arr。
3)p前面有p-arr个元素(不包含p),后面有n-(p-arr+1)个元素(不包含p)。
4、多维数组
4.1 声明
4.1.1 语法
类型 数组名[元素个数1][元素个数2]...[元素个数N];
多维数组最常用形式是二维数组。二维数组相当于一个行列组成的表。
类型 二维数组名[行数][列数];
例如下面是一个4行3列元素类型为int的表。
int days[4][3];
4.2 初始化二维数组
多维数组可以通过在括号内为每行指定值来进行初始化。
int days[4][3]={
{31,28,31},
{30,31,30},
{31,31,30},
{31,30,31}
};
4.3 访问二维数组元素
二维数组中的元素是通过使用下标(即数组的行索引和列索引)来访问的。
int n = days[0][0];
days[0][1] = 29;
printf("%d",days[0][0]);
4.4 二维数组元素遍历
通常使用嵌套循环来处理二维数组。
for (int i = 0; i < 4; i++ ) {
for (int j = 0; j < 3; j++ ) {
printf("a[%d][%d] = %d\n",i,j,a[i][j]);
}
}
4.5 二维数组输入
int n,m;
scanf("%d%d",&n,&m);
int arr[n][m];
for (int i=0;i<n;++i){
for (int j=0;j<m;++j){
scanf("%d",&arr[i][j]);
}
}
4.5.1 练习
(1)输入m个学生的n门课程成绩,输出各门课程成绩以及总成绩和平均值。
#include <stdio.h>
void main(){
int n,m;
printf("请输入学生数(n)和科目数(m):\n");
scanf("%d%d",&n,&m);
int grades[n][m];
for(int i=0;i<n;i++){
for (int j = 0; j < m; j++)
{
scanf("%d",&grades[i][j]);
}
}
for (int i = 0; i < n; i++)
{
int sum=0;
for (int j = 0; j < m; j++)
{
printf("%d\t",grades[i][j]);
sum+=grades[i][j];
}
printf("%d\t%.2f\n",sum,(float)sum/m);
}
}
4.6 简化
初始化二维数组可以有如下简化写法:
(1)省略内部嵌套括号。
int days[4][3]={31,28,31,30,31,30,31,31,30,31,30,31};
(2)省略第一维的大小,但是不能省略第二维的大小
int days[][3]={31,28,31,30,31,30,31,31,30,31,30,31};
4.7 二维数组作为函数的参数
void PrintMatrix(int m[4][3],int r,int c)
for (int i = 0; i < r; i++ ) {
for (int j = 0; j < c; j++ ) {
printf("%d\n",m[i][j]);
}
}
4.8 多维数组
大于二维的数组的用法与二维数组一样,只是使用比较少。
int days[][4][3]={
{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31}
};
printf("平年二月天数为%d\n",days[0][0][1]);
printf("闰年二月天数为%d\n",days[1][0][1]);
多维数组初始化只能第一个维度可以省略。
5、const数组
5.1 const数组是什么?
const int arr[]={1,2,3,4,5,};
数组变量已经是const指针,表示数组中的每一个元素都是const int,即每个元素不能通过arr改变。 例如:
const int arr[]={1,2,3,4,5,};
arr[0] = 0;
这个时候编译执行就会出错
6、变量指针 vs 数组指针
变量指针:指向单个变量的指针。 数组指针:指向数组的指针。
#include <stdio.h>
int main () {
int n = 10;
int *p;
p = &n;
printf("*p = %d\n",*p);
int arr[] = {1,2,3,4,5,};
p = arr;
printf("*p = %d\n",*p);
printf("*(p+1) = %d\n",*(p+1));
printf("*(p+2) = %d\n",*(p+2));
printf("*(p+3) = %d\n",*(p+3));
printf("*(p+4) = %d\n",*(p+4));
return 0;
}
指针既可以指向一个基本类型变量又可以指向一个数组。所以在使用时要注意分辨。
|