欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

C语言数组

时间:2023-04-30
C语言 数组

一、一维数组

1.1 一维数组的声明1.2 一维数组的初始化1.3 引用数组元素1.4 一维数组在内存中存储 二、二维数组

2.1 二维数组声明2.2 二维数组的初始化2.3 引用数组元素2.4 二维数组在内存中存储 三、多维数组

3.1 多维数组声明3.2 多维数组初始化 四、数组下标越界

4.1 下标越界访问4.2 下标越界修改 五、数组与指针

5.1 数组名

5.1.1数组名是什么5.1.2 数组名两个例外 5.2 下标引用与指针表达式5.3 数组与指针区别 六、数组与函数

6.1 一维数组传参的函数设计6.2 二维数组传参的函数设计
数组:一组相同类型元素的集合 一、一维数组 1.1 一维数组的声明

元素类型 数组名[元素个数]
说明:元素个数一般为常量表达式,c99标准支持可变长数组,即元素个数可以使用变量表示

int arr[10]; //声明一个整形数组,数组有10个元素,数组名为arr

1.2 一维数组的初始化

初始化:在数组声明时为数组赋值

int arr1[5] = {1,2,3};int arr2[5] = {1,2,3,4,5};int arr3[] = {1,2,3};char arr4[] = "abc" //等同于 arr4[] = {'a','b','c',''};

说明:
1.在数组声明时为数组赋值,可省略数组元素个数,此时元素个数为初始值个数

int arr3[] = {1,2,3}; //元素个数为:3

2.如果初始值个数小于元素个数时,剩余数组元素值被初始化为0

int arr1[5] = {1,2,3}; // 等同于 int arr1[5] = {1,2,3,0,0};

3.只能在数组声明时为数组赋值,其他时候只能为数组元素赋值,不能为数组赋值

int arr1[5];arr = {1,2,3,4,5}; //错误int arr2[] = {1,2,3};int arr3[3];arr3 = arr2;//错误

1.3 引用数组元素

数组名[下标]
说明:
1.数组元素通过下标来访问
2.数组下标从0开始,下标范围为[0,size-1]
3.size = sizeof(arr) / sizeof(arr[0]); 函数内此公式不适用

#include //打印数组每个元素值int main(){int arr[5] = { 0 };int size = sizeof(arr) / sizeof(arr[0]); //size为数组元素个数int i = 0;for (i = 0; i < size; i++){arr[i] = i; //对数组元素赋值}for (i = 0; i < size; i++){printf("%d ",arr[i]);//打印数组元素}return 0;}

输出

1 2 3 4 5

1.4 一维数组在内存中存储

一维数组在内存中是连续存放的,地址使用是从低地址到高地址

#include // 32位环境测试int main(){int arr[5] = { 1,2,3,4,5 };int size = sizeof(arr) / sizeof(arr[0]); //size为数组元素个数int i = 0;for (i = 0; i < size; i++){printf("%pn", &arr[i]); //打印对应元素在内存中地址 }return 0;}

输出

010FFD80010FFD84010FFD88010FFD8C010FFD90

二、二维数组 2.1 二维数组声明

元素类型 数组名[行数][列数]
数组元素个数=行数*列数,在声明时行数可以省略(但必须初始化)

int arr[3][2]; //声明一个二维数组,数组名为arr,数组有3行2列,元素个数为3*2,元素类型为int

2.2 二维数组的初始化

初始化:在数组声明的时候为其赋值

int arr1[3][3] = {1,2,3};int arr2[2][2] = { {1},{2,3} };int arr3[][2] = { {1,2},{3,4} };

说明:
1.初始值个数少于行数与列数乘积,剩余数组元素被初始化为0

int arr1[3][3] = {1,2,3}; // 等同于 int arr1[3][3] = { {1,2,3},{0,0,0},{0,0,0} };//或等同于 int arr1[3][3] = {1,2,3,0,0,0,0,0,0};

2 只能在数组声明时为数组赋值,其他时候只能为数组元素赋值

int arr1[2][3] = { {1,2,3},{4,5,6} };int arr2[2][3];arr2 = arr1;//错误arr2[0] = arr1[0] //错误arr2[0][0] = arr1[1][1];//正确

2.3 引用数组元素

数组名[行下标][列下标]
行下标:范围为 [0,行号-1]
列下标:范围为 [0,列号-1]

#include int main(){int arr[2][3] = { 0 };int i = 0;int j = 0;int flag = 0;for (i = 0; i < 2; i++) //控制行下标{for (j = 0; j < 3; j++) //控制列下标{arr[i][j] = flag; //对数组元素赋值flag++;}}for (i = 0; i < 2; i++) //控制行下标{for (j = 0; j < 3; j++) //控制列下标{printf("arr[%d][%d] = %d ", i, j, arr[i][j]); //打印对应数组元素值}printf("n");//打印完一行数组就换行}return 0;}

2.4 二维数组在内存中存储

二维数组在内存中是连续存放的,地址使用是从低地址到高地址

#include int main(){int arr[2][3] = { 0 };int i = 0;int j = 0;for (i = 0; i < 2; i++) //控制行下标{for (j = 0; j < 3; j++) //控制列下标{printf("&arr[%d][%d] = %pn",i,j,&arr[i][j]);}}return 0;}

输出

&arr[0][0] = 00B8FE6C&arr[0][1] = 00B8FE70&arr[0][2] = 00B8FE74&arr[1][0] = 00B8FE78&arr[1][1] = 00B8FE7C&arr[1][2] = 00B8FE80

三、多维数组

多维数组:维数大于1个称为多维数组,如:二维数组、三维数组、四位数组等

3.1 多维数组声明

int arr[3][4][5];//声明1个三维数组,数组名为arr,数组为3排、4行、5列,元素个数=3*4*5,元素类型为int

3.2 多维数组初始化

int arr1[2][2][2 = { { {1,2},{3,4} },{ {5,6},{7,8} } };

说明:多维数组中,只有第一维才能根据初始化列表缺省的提供,剩余的几维必修显式地写出

int arr1[][2][2 = { { {1,2},{3,4} },{ {5,6},{7,8} } }; //第一维度省略不写,通过计算子数组的个数,得到第一维度为2

四、数组下标越界

数组的下标是有范围的,下标范围为[0,元素个数-1],当下标不在此范围时就超出数组合法空间的访问,即数组下标越界。C语言标准并不规定数组下标越界检查,下标越界检查涉及开销比想象的多(涉及到指针指向空间是否在数组空间内),所以大部分编译器不做下标越界检查

4.1 下标越界访问

#include int main(){int arr[5] = { 1,2,3,4,5 };printf("arr[%d] = %dn", -1, arr[-1]); //访问数组之前内存空间printf("arr[%d] = %dn", 5, arr[5]); //访问数组之后内存空间return 0;}

输出

arr[-1] = -858993460arr[5] = -858993460

大部分编译器对越界访问只会报警告,程序仍旧可以运行

4.2 下标越界修改

#include int main(){int arr[5] = { 1,2,3,4,5 };arr[-1] = 2; //修改数组之前内存空间存放的值arr[5] = 3; //修改数组之后内存空间存放的值return 0;}

程序错误,Run-Time Check Failure #2 - Stack around the variable ‘arr’ was corrupted.

结论:我们要自己对数组下标是否越界做检查,不要指望编译器

五、数组与指针 5.1 数组名 5.1.1数组名是什么

在C中,几乎所有使用数组名的表达式,数组名是数组首元素地址,是一个指针常量

例1

#include int main(){int arr[5] = { 1,2,3,4,5 };printf("p = %pn", arr);printf("&arr[0] = %pn", &arr[0]);//arr++; 此代码错误,因为arr是数组首元素地址,是一个指针常量,常量不能更改return 0;}

输出

p = 008FFE64&arr[0] = 008FFE64

例2

#include int main(){int arr1[5] = { 1,2,3,4,5 };int arr2[5];arr2 = arr1;//此代码错误,因为arr2是arr2数组首元素地址,一个指针常量,不能被修改return 0;}

5.1.2 数组名两个例外

只有在两种情况下,数组名不是数组首元素地址
例外1:sizeof(数组名)

#include //32位环境测试int main(){int arr[5] = { 1,2,3,4,5 };printf("%dn", sizeof(arr));return 0;}

输出

20

例外2:&数组名

#include //32位环境测试int main(){int arr[5] = { 1,2,3,4,5 };printf("&arr = %pn", &arr); // &数组名,取出的是数组地址printf("&arr[0] = %pn", &arr[0]); // &arr[0],取出数组首元素地址printf("arr = %pn", arr); // 数组名表示首元素地址,取出数组首元素地址printf("---------------n");printf("&arr+1 = %pn", &arr+1);printf("&arr[0]+1 = %pn", &arr[0]+1);printf("arr+1 = %pn", arr+1);return 0;}

输出

&arr = 004FF924&arr[0] = 004FF924arr = 004FF924---------------&arr+1 = 004FF938&arr[0]+1 = 004FF928arr+1 = 004FF928

5.2 下标引用与指针表达式

我们之前访问(修改)数组元素时是使用下标引用,但我们知道数组名一般情况下就是数组首元素的地址,是一个指针常量,所以本质上下标引用是指针表达式的伪装。

*array[subscript ] 等同于 (array + subscript )

#include //32位环境测试int main(){int arr[5] = { 1,2,3,4,5 };int i = 0;printf("使用下标引用方式打印元素值n");for (i = 0; i < 5; i++){printf("%d ", arr[i]);}int* p = arr; //整形指针变量p存放arr数组首元素地址printf("n使用指针表达式方式打印元素值n");for (i = 0; i < 5; i++){printf("%d ", *(p+i)); // *(p+i) 等同于 *(arr+i)}return 0;}

输出

使用下标引用方式打印元素值1 2 3 4 5使用指针表达式方式打印元素值1 2 3 4 5

当指针在表达式左边时,修改指针指向空间存放的值
当指针在表达式右边时,访问指针指向空间存放的值

#include int main(){int arr[5] = { 1,2,3,4,5 };int* p = arr;*p = 10; //指针在表达式左边,修改p指向空间存放值,等同于 arr[0] = 10;int i = *p; //指针在表达式右边,访问p指向空间存放值,等同于 int i = arr[0]printf("*p = %dn", *p);printf("i = %dn", i);printf("arr[0] = %dn", arr[0]);return 0;}

输出

*p = 10i = 10arr[0] = 10

说明:
1.下标引用相对于指针表达式可读性更强
2.下标引用绝不会比指针更有效率,但指针有时会比下标引用更有效率

5.3 数组与指针区别

数组和指针并不是相等的

声明一个数组时,编译器根据声明所指定的元素个数为数组分配内存空间,然后再创建数组名,它的值是一个常量,指向这片空间的起始位置。声明一个指针变量时,编译器只为指针本身分配内存空间,如果指针变量是一个全局变量则默认初始化为NULL,如果是局部变量不会被初始化,存放的是一个随机地址值 六、数组与函数 6.1 一维数组传参的函数设计

一位数组数组名是数组首元素地址
当在一个函数内部使用外部某个一维数组时,需要将该一维数组传入函数内,我们之前一般设计为数组形式

例1:

#include //32位环境测试void print1(int arr[5]) //形式参数设计为数组形式{int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}}int main(){int arr[5] = { 1,2,3,4,5 };print1(arr);return 0;}

例2 :
我们发现例1设计时,函数写死了,数组元素个数只能为5,当外部数组元素个数不是5的时候,函数需要修改,有些人会想到在函数内部通过 sizeof(arr) / sizeof(arr[0])求元素个数,这是一种错误设计方法

#include //32位环境测试void print2(int arr[]) {int i = 0;int size = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < size; i++){printf("%d ", arr[i]);}}int main(){int arr[5] = { 1,2,3,4,5 };print2(arr);//传入实参return 0;}

例3:
通过例2我们知道,如果在函数内部需要知道外部数组元素个数,可通过一个显式的参数传递给函数,指明数组元素个数

#include //32位环境测试void print3(int arr[],int size) //形式参数设计为数组形式,size为数组元素个数{int i = 0;for (i = 0; i < size; i++){printf("%d ", arr[i]);}}int main(){int arr[5] = { 1,2,3,4,5 };int size = sizeof(arr) / sizeof(arr[0]);print3(arr,size);return 0;}

例4
我们知道一维数组的数组名为数组首元素地址,所以函数参数设计时应该用指针类型

#include //32位环境测试void print4(int* p,int size) //形式参数设计为指针形式{int i = 0;for (i = 0; i < size; i++){printf("%d ", *(p+i));}}int main(){int arr[5] = { 1,2,3,4,5 };int size = sizeof(arr) / sizeof(arr[0]);print4(arr,size);return 0;}

结论:
1.一维数组传参传递的是数组首元素地址,本质是指针
2.我们推荐使用例3、例4的方式进行函数设计,尤其是例4

6.2 二维数组传参的函数设计

二维数组的数组名是首元素地址,首元素是一个一维数组,即数组指针

int arr[3][4];int (*p)[4] = arr; //p存放数组arr首元素地址 // 下标引用运算符优先级高于间接访问运算符,但是由于小括号存在,p首先与*匹配,即p是指针。接下来与// 下标引用运算符匹配,表明p指向某种类型的数组,最后与int匹配,所以p是一个指向数组的指针,数组有10个// 元素,每个元素为int类型

当在一个函数内部使用外部某个二维数组时,需要将该二维数组传入函数内,我们之前一般设计为数组形式
例1:

#include //32位环境测试void print1(int arr[2][2]) //数组形式{int i = 0;int j = 0;for (i = 0; i < 2; i++){for (j = 0; j < 2; j++){printf("arr[%d][%d] = %d ", i, j, arr[i][j]);}printf("n");}}int main(){int arr[2][2] = { {1,2},{3,4} };print1(arr);return 0;}

例2:
我们发现例1设计时,函数写死了,数组的行和列只能为2,其他情况函数需要修改。可通过2个显式的参数传递给函数,指明行和列

#include //32位环境测试void print2(int arr[][2],int row,int col) //数组形式{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf("arr[%d][%d] = %d ", i, j, arr[i][j]);}printf("n");}}int main(){int arr[2][2] = { {1,2},{3,4} };int row = sizeof(arr) / sizeof(arr[0]); //算出行int col = sizeof(arr[0]) / sizeof(arr[0][0]); //算出列print2(arr,row,col);return 0;}

例3
我们知道二维数组的数组名为数组首元素地址,即1个一维数组的地址,所以函数参数设计时应该用指针类型

#include //32位环境测试void print2(int (*p)[2], int row, int col) //指针形式{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf("arr[%d][%d] = %d ", i, j, *(*(p+i)+j)); }printf("n");}}int main(){int arr[2][2] = { {1,2},{3,4} };int row = sizeof(arr) / sizeof(arr[0]); //算出行int col = sizeof(arr[0]) / sizeof(arr[0][0]); //算出列print2(arr,row,col);return 0;}

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。