当前位置:首页 » 《随便一记》 » 正文

C语言——数组超详细版总结

6 人参与  2024年11月30日 08:01  分类 : 《随便一记》  评论

点击全文阅读


目录

1 一维数组

1.1 一维数组的创建与初始化

1.2.1 一维数组的创建

1.2.2 一维数组的初始化

1.2 一维数组的访问

1.3 一维数组在内存中的存储

2 二维数组

2.1 二维数组的创建与初始化

2.1.1 二维数组的创建

2.2.2 二维数组的初始化

2.2 二维数组的访问

2.3 二维数组在内存中的存储

3 字符数组

3.1 字符数组的创建与初始化

3.2 字符数组在内存中的存储 

3.3 补充:字符串的两种定义方式

4 数组大小的计算

4.1 sizeof操作符

4.2 数组大小 & 元素个数 计算

5 指针和数组 & 数组名代表的意义

6 数组传参

7 指针数组

8 数组指针


【数组的定义】:一组相同类型元素的集合。

【数组的下标】:数组每个元素都有对应下标,下标从0开始。

1 一维数组

1.1 一维数组的创建与初始化

1.2.1 一维数组的创建

type_t arr_name [const_n]//即:元素类型 数组名 [数组大小]//示例:int arr[10];char ch[20];

【注意点】

const_n通常是常量表达式,即:

        int n = 10;

        int arr[n];  //这种方式不能正常创建

但C99标准中引入了变长数组(数组长度可以通过变量确定)的概念,创建时可以使用变量,但这样的数组不能初始化。

这种情况也可以使用宏定义的方式:

        #define N 10;

        int arr[N];

1.2.2 一维数组的初始化

(1)完全初始化:数组中的所有元素在定义时都被指定了具体的值。

① 元素个数确定,元素值确定

int arr1[5] = {1, 2, 3, 4, 5}; char ch1[5] = {'a', 'b', 'c', 'd', 'e'}; 

② 只指定元素值

int arr[] = {1, 2, 3};//数组大小为3char ch1[] = {'a', 'b', 'c', 'd', 'e'}; //数组大小为5char ch2[] = "abcde"//数组大小为6,包含:abcde和\0

此时:arr为一个包含3个整形元素的数组,数组元素分别是:1,2,3。

因此,省略数组大小时必须初始化数组内容,因为这种情况下数组大小根据初始化内容确定!!!

关于字符数组详细内容请看第3章~~~

③ 只指定元素个数

int arr[10] = {0};

此时:arr为一个包含10个整形元素的数组,数组元素都被初始化为0。 

(2)不完全初始化

① 只确定部分数组内容

int arr[5] = {1, 2, 3};

此时: arr前3个元素分别是:1,2,3,后面的2个元素为0。

【注意区分 int arr[5] = {1} 和 int arr[5] = {0}】

int arr[5] = {1}; 此时arr为一个包含5个整形元素,第一个元素为1,其余为0;

int arr[5] = {0}; 此时arr为一个包含5个整形元素,元素值全为0;

char ch1[5] = {'a', 'b', 'c'};char ch2[5] = "abc";

此时:ch1前3个元素分别是:a b c,后面2个元素为'\0';ch2前3个元素分别是a b c,后面2个元素为'\0'。

关于字符数组详细内容请看第3章~~~

小结:整型数组不完全初始化会将未定义位置值初始化为0;字符数组不完全初始化会将未定义位置值初始化为\0。

1.2 一维数组的访问

数组通过 下标引用操作符[] 来访问内容,注意下标从0开始!

int arr[5] = {1, 2, 3, 4, 5};printf("%d", arr[2]);   //打印3

1.3 一维数组在内存中的存储

一维数组在内存中是连续存放的,地址由低到高变化。

【数组越界访问】 

数组下标有范围限制,如果有那个元素,那么最后一个元素对应下表(n-1),如果访问下标超出0~(n-1)就产生越界访问。这种情况编译器不一定报错,但不意味着程序是对的。

2 二维数组

2.1 二维数组的创建与初始化

2.1.1 二维数组的创建

int arr[3][4];  //创建3行4列的整型数组char arr[3][4];double arr[3][4];

2.2.2 二维数组的初始化

(1)完全初始化:数组大小确定,元素值确定

int arr[4][5] = { {1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}, {4, 5, 6, 7, 8} };//创建4行5列整型数组

 (2)不完全初始化

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

二维数组不完全初始化时:未定义位置会初始化为0

注意:二维数组可以省略行数,不能省略列数!!!

(3)其他初始化方式

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

编译器会按照指定数组大小将已定义的内容填充进去,剩余位置填充为0;

所以此时arr,第一行元素为:1 2 3 4 5,第二行元素为:6 7 8 9 10,剩余两行元素全为0。

注意:这种初始化也是“可以省略行,不可以省略列”!

2.2 二维数组的访问

二维数组也通过 操作符[] 访问元素内容,注意:行列下标都从0开始!

2.3 二维数组在内存中的存储

二维数组在内存中也是连续存放的,地址由低到高变化。

二维数组可以理解为:存放 “一维数组” 的数组。 

3 字符数组

3.1 字符数组的创建与初始化

字符数组的创建
char ch[10];  //创建一个可以存储10个字符的字符数组
 字符数组的初始化

 (1)字符串值直接初始化

char ch1[] = "abc";//ch1中存放元素:a b c \0;char ch2[4] = "abc";//ch2中存放元素:a b c \0;char ch3[3] = "abc";//ch3中存放元素:a b c ;

在长度定义准确或未定义长度时,字符串末尾会加上'\0'。

(2) 逐个字符初始化

char ch1[] = {'a', 'b', 'c'};//ch1中存放元素:a b c;char ch2[] = {'a', 98, 'c'};//ch2中存放元素:a b c;//(ch3中将整数98用于初始化字符数组,此时98会被解释为字符值,而98对应ASCII为b,因此此处ch3[1]初始化为b。)//这种情况下虽然会发生转换,但不建议这么定义!char ch3[] = {'a', 'b', 'c', '\0'}

 小结:字符串值直接初始化,通常末尾会有'\0';逐个字符初始化,如果不特意添加则不会有'\0'。

【字符串的结尾】:C语言中,字符串以 '\0'(空字符)作为结束标志。 

C语言中很多库函数(如:printf、strlen......)在处理字符串时依赖 '\0' 来确定字符串长度。如果字符串缺少这个结束标志,使用这类函数会导致未定义行为!如下图所示

3.2 字符数组在内存中的存储 

3.3 补充:字符串的两种定义方式

(1)使用字符数组:直接定义字符数组储存字符,这种情况编译器会自动加上结束符'\0'

int main() {    // 定义字符数组,自动添加结束符 '\0'    char str1[] = "Hello, world!";    printf("%s\n", str1);  // 输出 "Hello, world!"    str1[0] = 'Y';    printf("%s\n", str1);  //输出 "Yello, world!"    return 0;}
 实际数组包含13个字符和1个结束符'\0';通过下标可以修改字符串内容。

(2)使用字符指针:通过字符指针指向一个字符串,字符串会在内存“代码段”存储,以'\0'结束

int main() {    // 使用字符指针指向字符串字面量    char *str2 = "Hello, world!";    printf("%s\n", str2);  // 输出 "Hello, world!"    return 0;}

 

 字符指针指向的字符串存储在静态区中,不能被修改,并且空间在程序结束才会被操作系统回收。

4 数组大小的计算

4.1 sizeof操作符

sizeof用于获取数据类型(如:int、char、float、double、结构体......)or对象所占用的内存大小以字节为单位)。

int main() {    printf("Size of int: %zu bytes\n", sizeof(int));       // 4    printf("Size of char: %zu bytes\n", sizeof(char));     // 1    printf("Size of float: %zu bytes\n", sizeof(float));   // 4    printf("Size of double: %zu bytes\n", sizeof(double)); //8    return 0;}

【关于sizeof需要注意的点】 

sizeof是操作符,不是函数!sizeof计算字符串大小时,不依赖于字符串的结束符'\0'。(有'\0'则计入,没有也不影响)

  

sizeof的计算发生在编译阶段
int main(){    int a = 5;    short s = 11;    printf("%d\n", sizeof(s = a + 2));    //2  【sizeof通过类型确定s大小是short类型,大小为2】    //从数学角度看,a+2的值为整型,但一定要赋值给short类型的s,会发生截断,并且short类型占2字节    //截断后s的值应该是7        printf("%d\n", s);    //11  【sizeof在编译期间就完成处理,而s的运算结果在可运行程序中计算】    return 0;}
sizeof并不会去访问变量的实际内容,而是根据类型信息确定变量在内存中需要占用的空间大小。

4.2 数组大小 & 元素个数 计算

int main() {int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);printf("%d\n", sz);  //输出:10}

sizeof(arr) :整个数组大小;

sizeof(arr[0]) :数组首元素大小,即每个元素的大小。 

5 指针和数组 & 数组名代表的意义

通常情况下,数组名表示首元素地址。

数组名各种操作访问到的内容:

因此,*(arr+i) 和 arr[i] 等价 。

 但是有以下两种特殊情况

 (1)sizeof(数组名)

数组名单独放在sizeof内部,此时 数组名 表示整个数组,计算出的是整个数组的大小。 

(2)&数组名

此时数组名也表示整个数组,取出的是整个数组的地址。 

这也代表着 &数组名 结合+-等操作访问到的是整个数组

上面提到:二维数组可以理解为 存放一维数组 的数组 。结合这个知识点加深理解:

6 数组传参

数组作为参数传递给函数时,实际上是将数组的指针传递给函数,即传递的时数组的地址。

数组名在参数列表中会被隐式转换为指向其第一个元素的指针。

(1)一维数组传参

//方式一void printArray(int arr[], int size) {    //函数内容略}//方式二void printArray(int* arr, int size) {    //函数内容略}int main() {    int arr[] = { 1, 2, 3, 4, 5 };    int sz = sizeof(arr) / sizeof(arr[0]); // 计算数组的元素个数    printArray(arr, sz); // 传递数组和大小    return 0;}

(2)二维数组传参

//方式一void printArray(int arr[3][4]) {    //函数内容略}//方式二void printArray(int arr[][4]) {//函数内容略}int main() {int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };printArray(arr);}

注意:二维数组传参时,形参列表中也是数组行信息可以省略,列信息不能省略! 

在传参过程中,如果粗要用到数组的元素个数,要在传参前计算出结果,将结果作为参数传递给函数。

如果在被调用函数内部计算元素个数,会出现错误。如下图所示

7 指针数组

即:存放指针的数组

char* arr[5];int* arr2[6];

 示例:

8 数组指针

即:指向数组的指针

int (*p)[10];
p是一个数组指针,指向一个大小为10的整型数组* :说明p是一个指针变量[10] : 说明数组有10个元素int :说明数组每个元素类型为int

点击全文阅读


本文链接:http://m.zhangshiyu.com/post/194251.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1