• C语言 数组


    一、一维数组

    1. 一维数组的创建方式

    程序清单1

    #include 
    
    int main() {
    
    	int arr1[10] = { 1,2,3,4,5 };
    	int arr2[] = { 1,2,3,4,5 };
    	int arr3[10];
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    数组 arr1 在定义时,长度给了 10,但初始化未完全。
    数组 arr2 在定义时,未明确数组大小,底层根据初始化后提供默认大小。
    数组 arr3 只被定义,未初始化,所以底层放的都是随机数字。

    1-1

    程序清单2

    下面的三个数组呈现了字符数组的区别。

    这里需要注意 sizeof 和 strlen 的区别,sizeof 求的是整个数组内所有元素占内存的大小( 包括 ’ \0 ’ ),strlen 求的是字符串长度( ’ \0 ’ 之前 )。也就是说,前者求的是数组元素的大小,后者求的是字符串的长度。

    #include 
    #include 
    
    int main() {
    
    	char arr4[] = "abcd";
    	char arr5[] = { 'a','b','c','d' };
    	char arr6[10] = { 'a','b','c','d' };
    
    	printf("%d %d\n", sizeof(arr4), strlen(arr4));
    	return 0;
    }
    
    // 输出结果:5 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1-2

    2. 一维数组在内存中的存储方式

    #include 
    
    int main() {
    
    	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    	int size = sizeof(arr) / sizeof(arr[0]);
    
    	for (int i = 0; i < size; i++) {
    		printf("&arr[%d] => %p\n", i, &arr[i]);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出结果:

    1-3

    从上面的十六进制的地址来看,我们可以得出结论:

    ① 一维数组在内存中是连续存放的。
    ② 随着数组下标的增长,地址由低到高变化。
    ③ 地址之间的差值,即数组元素类型的大小。( 例如:数组存放的元素是整型,那么每个元素的地址之间就相差 4. )

    3. 计算一维数组的元素个数

    在 C语言 中,sizeof 可以用来计算某个变量的所占内存的字节大小,所以利用【整个数组所占的内存大小】/ 【数组内某个元素所占的内存大小】,就能够得出数组长度。

    #include 
    
    int main() {
    
    	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    	printf("%d\n", sizeof(arr)); // 40
    	printf("%d\n", sizeof(arr[0])); // 4
    
    	int size = sizeof(arr) / sizeof(arr[0]); // 求数组长度的方法
    	printf("%d\n", size); // 10
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4. 一维数组打印

    #include 
    
    // 方法一
    void print(int arr[], int size) {
    
    	for (int i = 0; i < size; i++) {
    		printf("%d ", arr[i]);
    	}
    }
    
    // 方法二
    void print2(int* arr, int size) {
    
    	for (int i = 0; i < size; i++) {
    		printf("%d ", *(arr + i));
    	}
    }
    
    int main() {
    
    	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    	int size = sizeof(arr) / sizeof(arr[0]);
    
    	print2(arr, size);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    arr 为数组名,即首元素地址 &arr[0],其本质上是一个指针。所以我们可以写成方法二的整型指针方式来接收,每次访问数组的元素时,就往后跳一个元素。即跳跃四个字节。

    arr[i] <==> *(arr+i)
    
    • 1

    1-4

    二、二维数组

    1. 二维数组的创建方式

    #include 
    
    int main() {
    
    	int arr1[3][5] = { 0 };
    	int arr2[3][5] = { 1,2,3,4,5,6 };
    	int arr3[][5] = {1,2,3,4,5,6};
    	int arr4[3][5] = { {1,2}, {3,4}, {5,6} };
    
    	//int arr[3][] = { {1,2}, {3,4}, {5,6} }; // error
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1-5

    注意事项:

    ① 二维数组在创建时,行可以省略,列不可省略。

    ② 如果提前知道二维数组中存储什么元素,推荐上面的 arr4 (直接初始化);如果提前不确定二维数组的元素,推荐上面的 arr1. (初始化第一行第一列的元素,后面的自动初始化为 0.)

    2. 计算二维数组的行和列

    和计算一维数组的大小思想相同,这里依旧先采用 sizeof 计算内存所占大小,之后分别计算行和列。

    #include 
    
    int main() {
    
    	int arr[3][5] = { {1,2}, {3,4}, {5,6} };
    	
    	// 整个二维数组的大小 / 第一行一维数组大小
    	int row = sizeof(arr) / sizeof(arr[0]); // 60/20 = 3
    
    	// 第一行一维数组大小 / 第一行第一个数组元素的大小
    	int column = sizeof(arr[0]) / sizeof(arr[0][0]); // 20/4 = 5
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3. 二维数组在内存中的存储方式

    #include 
    
    int main() {
    
    	int arr[3][5] = { {1,2}, {3,4}, {5,6} };
    
    	for (int i = 0; i < 3; i++) {
    		for (int j = 0; j < 5; j++) {
    			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    输出结果:

    1-6

    从上面的十六进制地址的输出结果来看,我们可以得出结论:

    二维数组在内存中是连续存放的,即二维数组实际的内存是连续存放的,和我们想象中的几行几列不一样。

    1-7

    4. 二维数组打印

    #include 
    
    // 方法一
    void print(int arr[3][5], int row, int column) {
    
    	for (int i = 0; i < row; i++) {
    		for (int j = 0; j < column; j++) {
    			printf("%d ", arr[i][j]);
    		}
    		printf("\n");
    	}
    }
    
    // 方法二
    void print2(int (*arr)[5], int row, int column) {
    
    	for (int i = 0; i < row; i++) {
    		for (int j = 0; j < column; j++) {
    			printf("%d ", *(*(arr+i) + j ));
    		}
    		printf("\n");
    	}
    }
    
    int main() {
    
    	int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };
    	int row = sizeof(arr) / sizeof(arr[0]); // 行
    	int column = sizeof(arr[0]) / sizeof(arr[0][0]); // 列
    
    	print2(arr, row, column);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    arr 为数组名,本质上描述的是第一行一维数组的地址。此时 arr + i,表示每次跳过一行。所以当我们利用指针的方式作为形参时,这个指针为数组指针。此时数组指针指向数量为 5个元素的 数组。

    arr[i][j] <==> *(arr+i)[j] <==> *(*(arr+i)+j)
    // 先找行,再找此行的列
    
    • 1
    • 2

    1-8

    三、数组名的含义

    结论

    对于一维数组来说,数组名就是首元素的地址。
    对于二维数组来说,数组名就是第一行数组的地址。

    但有两个例外:

    ① sizeof(数组名),此时数组名表示整个数组,计算的是整个数组占用内存的大小。
    ② &数组名,此时数组名表示整个数组,取出的是整个数组的地址。

    程序清单

    #include 
    
    int main() {
    
    	int arr[] = {1,2,3,4,5,6,7,8,9,10};
    
    	printf("%p\n", arr);
    	printf("%p\n\n", arr + 1); // 往后跳 4 个字节
    
    	printf("%p\n", &arr[0]);
    	printf("%p\n\n", &arr[0] + 1); // 往后跳 4 个字节
    
    	printf("%p\n", &arr);
    	printf("%p\n\n", &arr + 1); // 往后跳 40个字节
    
    	printf("%d\n", sizeof(arr));
    	printf("%d\n", sizeof(arr[0])); 
    	//printf("%d", sizeof(&arr); // error
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    输出结果:

    1-9

    1-10

    注意事项:

    从上面的四组数据来看,数组名在不同的场景下起到不同的作用。

    2-1

  • 相关阅读:
    JVM Heap Memory
    大数据从入门到精通(超详细版)之BI工具的安装
    Guava Cache的使用方式
    MEMM最大熵模型
    pcl--第十一节 点云外接立方体和点云模板匹配
    利用Unity和OpenXR实现眼动追踪的基础指南
    go sync.Map Range 的同时进行 Store,Range 的遍历结果如何?(源码分析)
    记录一个 Hudi HBase 依赖冲突问题及解决方案
    【C语言】for循环
    bcc安装过程以及遇到的问题
  • 原文地址:https://blog.csdn.net/lfm1010123/article/details/127708633