自学----深入探究数组

目录

 1. 一维数组的创建和初始化。

1.1 数组的创建

1.2 数组的初始化 

1.3 一维数组的使用

①. 数组是使用下标来访问的,下标是从0开始。

②. 数组的大小可以通过计算得到。

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

 2. 二维数组的创建和初始化

2.1 二维数组的创建

2.2 二维数组的初始化

 2.1 二维数组的储存方式(按行优先存储)

2.4 二维数组的使用

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

 3. 数组越界

 4. 数组作为函数参数

4.1 冒泡排序函数的错误设计

 4.2 数组名是什么?

 4.3 冒泡排序函数的正确设计


 

 

 1. 一维数组的创建和初始化。

1.1 数组的创建

数组是一组相同类型元素的集合,这和我们数学中的概念类似。

数组的创建方式很简单:

type_t  arr_name[const_n];
 //type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小

实例: 

//代码1
 int arr1[10];
 //代码2
 int count = 10;
 int arr2[count];
//代码3
 char arr3[10];
 float arr4[1];
 double arr5[20];

注意!:[ ]中要给一个常量才可以,不能使用变量。

 

如: int arr[ n ]就是错误的。

1.2 数组的初始化 

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)

也就是[  ] 这个里面的东西

如:

int arr1[10] = {1,2,3};
 int arr2[] = {1,2,3,4};
 int arr3[5] = {1,2,3,4,5};
char arr4[3] = {'a',98, 'c'};
 char arr5[] = {'a','b','c'};
 char arr6[] = "abcdef";

数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定 

也就是说[ ]和{ }里面至少有一个要有东西

 

像上面第一行的没有初始化的值一律都是‘\0’

1.3 一维数组的使用

①. 数组是使用下标来访问的,下标是从0开始。

#define _CRT_SECURE_NO_WARNINGS
#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++)
	{
		arr[i] = i;
	}
	//输出数组的内容
	for (i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

804a6b05845041e6bd0cd1603740b2af.png

②. 数组的大小可以通过计算得到。

int arr[10];
 int sz = sizeof(arr)/sizeof(arr[0]);

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

#include <stdio.h>
 int main()
 {
 int arr[10] = {0};
 int i = 0;
 int sz = sizeof(arr)/sizeof(arr[0]);
 }
 for(i=0; i<sz; ++i)
 {
 printf("&arr[%d] = %p\n", i, &arr[i]);
 }
 return 0;

输出的结果如下: 

9cebd1db6217454d9804ce607149a5ce.png

仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得出结论:数组在内存中是连续存放的。

d4cdb3bd3c714989b513b689281fa822.png

 2. 二维数组的创建和初始化

2.1 二维数组的创建

与一维数组一样的格式创建

//数组创建
int arr[3][4];
char arr[3][5];
double arr[2][4];

前面一个叫做行(表示有几个)

后面一个叫做列(表示一个一维数组里面有几个元素)

2.2 二维数组的初始化

//数组初始化
int arr[3][4] = {1,2,3,4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3},{4,5}};
//二维数组如果有初始化,行可以省略,列不能省略

  注:一个二维数组,在本质上是有多个一维数组构成。(每一个一维数的大小必须相同)

 例如:定义 int ar[ 3 ][ 4 ] 的二维数组,它是由 3 个一维数组组成,每个一维数组的大小是 4 个整 型元素。可以只对部分元素赋值,未赋值的元素自动取 0 值。 

 2.1 二维数组的储存方式(按行优先存储)

#include<stdio.h>
int main()
{
	int ar[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };		// 3 行 4 列
	int br[][4] = { {1,2},{3,4},{5,6} };				// 3 行 4 列 数字不足自动补 0
	int cr[][4] = { 1,2,3,4,5,6,7,8 };					// 2 行 4 列
	return 0;
}

1368e73a64454884822bcf4871ad9080.png 通过监视可以非常直观的看出二维数组的很多规律

如:1.自动将数组分为指定元素数量的一个个一维数组

       2.自动补齐一维数组中缺少的元素(0)

       3.按行优先存储

71c8e8c768684f7e83ee1bb668353600.png

2.4 二维数组的使用

二维数组的使用也是通过下标的方式。

#include <stdio.h>
int main()
{
	int arr[3][4] = { 0 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			arr[i][j] = i * 4 + j;
		}
	}


	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}

	}
	return 0;
}

对于行和列都是从0开始编号

  0 1 2 3
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11

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

像一维数组一样,这里我们尝试打印二维数组的每个元素以及它们的内存

#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;
 }

输出的结果是这样的: 

bccd7a141b9449e3aba689f52d098f74.png

通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。 

3863cb196ad5429aa77eb4027bf9b1d3.png

 

 3. 数组越界

数组的下标是有范围限制的。

数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。

所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就 是正确的 

所以我们写代码时,最好自己做越界的检查。

#include <stdio.h>
 int main()
 {
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 int i = 0;
 for(i=0; i<=10; i++)
    {
 printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
    }
 return 0;
 }

看看结果: 

2d5af03075304a988c37b86f65c5ad18.png

当数组越界时打印出来的就是《不知道啥了》 

ps:二维数组的行和列也可能存在越界。

 4. 数组作为函数参数

往往我们在写代码的时候,会将数组作为参数传个函数,

比如一个非常经典的例子:实现一个冒泡排序函数将一个整形数组排序。

4.1 冒泡排序函数的错误设计

相信大多数人第一次设计都会将数组和变量一样使用

然后发现怎么运行都不对

就像这样:

#include <stdio.h>
 void bubble_sort(int arr[])
 {
 int sz = sizeof(arr);
int i = 0;
 for(i=0; i<sz-1; i++)
    {
 int j = 0;
 for(j=0; j<sz-i-1; j++)
        {
 if(arr[j] > arr[j+1])
            {
 int tmp = arr[j];
 arr[j] = arr[j+1];
 arr[j+1] = tmp;
            }
        }
    }
 }
 int main()
 {
 int arr[] = {3,1,7,5,8,9,0,2,4,6};
 bubble_sort(arr);
for(i=0; i<sizeof(arr); i++)
    {
 printf("%d ", arr[i]);
    }
return 0;
}
 

然后发现一大堆错误

调试之后可以看到 bubble_sort 函数内部的sz 是1

所以得出结论数组作为函数参数的时候,不是把整个数组的传递过去

 4.2 数组名是什么?

首先的首先,我们要知道数组名在一些情况下不是代表整个数组

用这一段代码可以总结一些规律

#include <stdio.h>
 int main()
 {
 int arr[10] = {1,2,3,4,5};
 printf("%p\n", arr);
 printf("%p\n", &arr[0]);
 printf("%d\n", *arr);
return 0;
 }

结果如图 

1844116e406142f2a7837fd7ecaca66e.png

根据输出结果我们可以得出结论

数组名是数组首元素的地址。(有两个例外)

 

例外1:sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。

例外2:&数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

 4.3 冒泡排序函数的正确设计

知道了这些我们可以重新设计了

当数组传参的时候,实际上只是把数组的首元素的地址传递过去了。

所以即使在函数参数部分写成数组的形式: int arr[] 表示的依然是一个指针:

那么,函数内部的 sizeof(arr) 结果是4。

1.  在 bubble_sort 函数中,我们使用了 sizeof(arr) 来获取数组的大小。然而,对于函数参数来说,数组会被转换为指针,因此 sizeof(arr) 实际上只会返回指针的大小,而不是数组的大小。我们需要将数组的大小作为函数参数传递给 bubble_sort 函数。

 

2.  在主函数中,我们使用了 for(i=0; i<sizeof(arr); i++) 来遍历数组并输出排序结果。同样地,sizeof(arr) 不会返回数组的大小,而是返回指针的大小。我们需要将数组的大小保存在一个变量中,并在循环中使用该变量来控制遍历的次数。

这是修正后的:

#include <stdio.h>

void bubble_sort(int arr[], int size) {
    int i, j;
    for (i = 0; i < size - 1; i++) {
        for (j = 0; j < size - i - 1; j++) {
            if (arr[j] > arr[j+1]) {
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
            }
        }
    }
}

int main() {
    int arr[] = {3, 1, 7, 5, 8, 9, 0, 2, 4, 6};
    int size = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, size);
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

大功告成! 

 f7de91d800d54724812c6ae1396603f4.png

 

相关推荐

  1. 深入探索Spring Boot的自动配置机制

    2024-07-19 21:06:05       37 阅读
  2. Python数组存放变量:深入探索与实用技巧

    2024-07-19 21:06:05       34 阅读
  3. 深入探究TCP/IP协议

    2024-07-19 21:06:05       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-19 21:06:05       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-19 21:06:05       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-19 21:06:05       57 阅读
  4. Python语言-面向对象

    2024-07-19 21:06:05       68 阅读

热门阅读

  1. 单例模式~

    2024-07-19 21:06:05       21 阅读
  2. python的mixin设计模式

    2024-07-19 21:06:05       21 阅读
  3. vue中v-if和v-for

    2024-07-19 21:06:05       19 阅读
  4. 计算机视觉10 总结

    2024-07-19 21:06:05       16 阅读
  5. 什么是RPC

    2024-07-19 21:06:05       19 阅读
  6. 《Exploring Orthogonality in Open World Object Detection》

    2024-07-19 21:06:05       19 阅读
  7. 电商B2B2C模式详细介绍

    2024-07-19 21:06:05       19 阅读
  8. ubuntu 22.04安装Eigen

    2024-07-19 21:06:05       19 阅读
  9. 【手撕数据结构】把玩顺序表

    2024-07-19 21:06:05       20 阅读