微信网站建设合同,简单详细搭建网站教程视频教程,苏州无名网络科技有限公司,淘宝关键词指数查询目录 一、一维数组的创建和初始化1.1数组的创建1.2 变长数组1.3 数组的初始化1.4 全局数组默认初始化为01.5 区分两种字符数组1.6 用sizeof计算数组元素个数1.7 如何访问数组元素1.8 一维数组在内存中的存储(连续存储)1.9 访问数组元素的另一种方式:指针变量1.10 数组越界是运行… 目录 一、一维数组的创建和初始化1.1数组的创建1.2 变长数组1.3 数组的初始化1.4 全局数组默认初始化为01.5 区分两种字符数组1.6 用sizeof计算数组元素个数1.7 如何访问数组元素1.8 一维数组在内存中的存储(连续存储)1.9 访问数组元素的另一种方式:指针变量1.10 数组越界是运行时错误 二、二维数组的创建和初始化2.1 二维数组的创建2.2 二维数组的初始化2.3 行可以省略 列不可以省略2.4 二维数组在内存中的存储(连续存储)2.5 二维数组的遍历方式2.6 arr[行号]可以理解为:该行一维数组的数组名 三、数组名3.1 数组名是首元素地址 本质是指针变量3.2 数组名代表整个数组的两个例外:sizeof和3.3 sizeof(arr)和sizeof(arr0)的区别3.4 arr和arr类型的区别(指针1)3.5 arr 和*(arr) 数组指针解引用得到数组名3.6 **(arr) 解引用两次是什么?3.7 sizeof(*arr) 和 sizeof(arr)3.8 再理解一下 什么叫单独放在或sizeof(含总结)3.9 sizeof(数组名)和strlen(数组名) 四、数组(名)作为函数参数4.1 数组(名)作为函数参数 本质传的是什么?4.2 冒泡排序函数的错误设计4.3 理解形参int arr[ ] arr[j] arr[j]的本质4.4 思考:为什么数组传参 本质要传首元素的地址?4.5 二维数组传参 五、其他怎么看数组的类型是什么用整数初始化字符数组会怎么样arr和(arr1) 一、一维数组的创建和初始化
1.1数组的创建
数组的创建方式:type_t arr_name [const_n] type_t 是指数组的元素类型 const_n 是一个常量表达式 用来指定数组的大 比如int arr[56]
1.2 变长数组 int arr[5];int arr[56]都可以 可不可以是int arr[n]呢? 1.3 数组的初始化 1.不完全初始化 会根据指定的元素个数 把剩余部分初始化为0 2.char数组不完全初始化 剩余部分默认初始化为’\0’ \0的码值是0 3.如果不写元素个数 那就必须初始化 编译器会根据初始化的内容确定元素个数 所以下图的两个数组是不一样的 一个是arr[3] {1,2,3} 一个是arr[10] {1,2,3,0,0,0,0,0,0,0} 注意字符串自带’\0’ 一些离谱的写法:
1.4 全局数组默认初始化为0
在VS2022里 全局数组不初始化 默认都是0但是局部数组不初始化 整形数组是cccccccc char数组是问号
1.5 区分两种字符数组
abc自带’\0’%s是打印到第一个’\0’才停止的
1.6 用sizeof计算数组元素个数
这里sizeof(arr[0]) 也可以写成sizeof(int) 但是前者更合逻辑(一个元素的大小)
1.7 如何访问数组元素 1.8 一维数组在内存中的存储(连续存储) ● 内存单元的大小为1字节 而int是4个字节(则每个元素占4个内存单元) ● 一维数组在内存中是 连续存储 的 ● 随着数组下标增长 地址由低到高变化(从低地址用到高地址) 再结合之前画过的图 推测: 下标越高的元素 其实是越先入栈的 1.9 访问数组元素的另一种方式:指针变量 ● 所以 给我数组的首元素地址 根据连续存储特点 我就能顺藤摸瓜依次找到整个数组 ● p是个整型指针 1就跳过一个整型 ● *(pi) arr[i] ● pi arr[i] 1.10 数组越界是运行时错误
数组的下规定是从0开始的 如果数组有n个元素 最后一个元素的下标就是n-1所以数组的下标如果小于0 或者大于n-1 就是数组越界访问了C语言本身是不做数组下标的越界检查 编译器也不一定报错编译器不报错 并不意味着程序就是正确的 所以写代码时 做好越界的检查 打印随机值: 可能是没有初始化 也可能是数组越界访问 下图编译器虽然不报错 但是程序明显是错误的 假如这里给arr[i]赋值的话 就会报错 二、二维数组的创建和初始化
2.1 二维数组的创建 2.2 二维数组的初始化
不完全初始化 默认也是0和’\0’ 可以帮一维数组的每个元素看做一维数组
2.3 行可以省略 列不可以省略 如果下面这个不给行数3 定义成[ ][4] 它也是可以知道是1234 5678 9000的 因为反正知道一行要放几个元素(列数已知) 如果定义成[4][ ] 编译器就不知道怎么办 一上来要怎么放? 所以 列不可以省略 行可以通过每列放几个来确定 所以行可以省略(前提是 后面有具体的初始化内容了) 2.4 二维数组在内存中的存储(连续存储)
二维数组在内存中 其实也是连续存放的
2.5 二维数组的遍历方式 其实也一维数组类似 方式1 利用行号和列号 方式2 利用其连续存放的特性 把下图的二维数组直接看作一个12个元素的一维数组 方式3 利用2.6的理解 2.6说了:arr[i]是第i行一维数组的数组名 arr是二维数组的数组名 数组名 单独 放在sizeof里 求的是整个数组的大小! sizeof(arr[0][0])是一个元素的大小 等价于sizeof(int) 整个二维数组大小/每一行一维数组大小sizeof(arr)/sizeof(arr[0])行数 每一行一维数组大小/每个元素大小sizeof(arr[0])/sizeof(arr[0][0])列数 2.6 arr[行号]可以理解为:该行一维数组的数组名
arr[3][4] {1,2,3,4,5,6,7,8,7,7,7,7}: 三个一维数组 每个一维数组四个元素 1 2 3 4—数组名arr[0] arr[0][1]2 5 6 7 8—数组名arr[1] 7 7 7 7—数组名arr[2] 二维数组是一维数组的数组 二维数组的每个元素(每一行) 可以看做一行一维数组 且每一行的数组名就是arr[行号] 如果把1 2 0 0看成一个一维数组的话 类比: arr[i]:arr数组名 i下标 则arr[0][j]:arr[0]数组名 j下标 其中**arr[0]指的就是1 2 0 0这个一维数组的数组名** 以此类推 第二行的数组名就是arr[1] 三、数组名
3.1 数组名是首元素地址 本质是指针变量 3.2 数组名代表整个数组的两个例外:sizeof和
● sizeof(单独放一个数组名) 则这里的数组名表示整个数组 计算的是整个数组的大小 单位是字节 ● 单独跟一个数组名 则这里的数组名也表示整个数组 取出的是整个数组的地址 是个数组指针 ● 除了这两个例外 其他遇到的所有的数组名 都表示首元素地址
3.3 sizeof(arr)和sizeof(arr0)的区别 sizeof(arr0) 数组名不是单独放在sizeof里面 所以arr表示的还是首元素地址 arr如果参与运算 那肯定是个指针了 也就是看做首元素地址了 3.4 arr和arr类型的区别(指针1) arr和arr虽然值相同 但类型是不一样的!! arr是整型指针arr的类型是int* arr是数组指针arr的类型是int (*)[10] 这就是本质区别 p1跳过几个字节 取决于指针的类型 int* p是整型指针 p1跳过一个int大小的空间 4字节-类型是int* char* p是字符指针 p1跳过一个char大小的空间 1字节-类型是char* 数组名是数组指针 p1跳过一个数组大小的空间 元素个数*元素大小个字节-类型是int(*)[10] 下图B08-AE0 28 十进制的40 3.5 arr 和*(arr) 数组指针解引用得到数组名 所以都是求的整个数组的大小
3.6 **(arr) 解引用两次是什么? 再给p3解引用一次 发现就拿到了首元素1 但是p3可不是二级指针 传参的时候可不能写成二级指针 二级指针 一定是某个地址的地址 但是这里 p3是一整个数组的地址 p3应该是数组指针 而不是二级指针 其实我觉得 p3还真的可以理解成地址的地址 因为arr本身就是首元素地址 arr不就是把地址的地址拿到了 (只能这么理解理解 但是这种说法是错的 前面已经提到过 单独数组名拿的是整个数组的地址) 但是只能自己偷偷这么去理解 语法不是这样的 3.7 sizeof(*arr) 和 sizeof(arr)
求的都是整个数组的大小
3.8 再理解一下 什么叫单独放在或sizeof(含总结) 单独的情况下 arr[1]表示第二行数组的数组名 如果不是arr[1]两个单独的情况 那么数组名arr[1]表示首元素地址(就是第二行第一个元素的地址) 3.9 sizeof(数组名)和strlen(数组名)
strlen是专门针对字符串的函数char arr[10]“abc”; sizeof(arr)求出来就是10字节 放了什么内容没关系 而strlen(arr)求到的就是\0之前的 求到3
四、数组(名)作为函数参数
4.1 数组(名)作为函数参数 本质传的是什么? ● arr不符合前面提到的两个单独 则这里arr就是首元素地址 本质上是指针 ● 既然传过来的是地址 那么用指针接 才更规范 ● char ch[]本质就是char* ch ● ch是指针变量 大小恒为8/4 4.2 冒泡排序函数的错误设计 下图是冒泡排序的一种经典错误 形参的int arr[] 本质上就是整型指针int* arr 既然本质是指针 sizeof(arr)计算的就是指针的大小 永远是8字节or4字节 则sizeof(arr)/sizeof(arr[0])恒为2或者1 ● 把sz在main算好作为参数传进来 才是正确的做法 ● 因为在main里 单独 把数组名arr给sizeof( ) 求的就是整个数组的大小 参考代码:
void Sort(int arr[],int sz)
{int i 0;int j 0;for (i 0; i sz - 1; i){ 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[] { 10,9,8,7,6,100,5,4,3,2,1 };for (int i 0; i sizeof(arr) / sizeof(arr[0]); i)printf(%d , arr[i]);printf(\n);Sort(arr, sizeof(arr) / sizeof(int));for (int i 0; i sizeof(arr) / sizeof(int); i)printf(%d , arr[i]);return 0;
}其实主要看sizeof( )里放的本质是什么 如果在函数里再新定义一个数组 还是一样可以正确求出该数组的大小(字节)的 4.3 理解形参int arr[ ] arr[j] arr[j]的本质
● 把本质是int* arr的东西写成int arr[ ] 主要是为了用下标访问的时候可能更好理解 ● int arr[]从形式上好理解 但本质还是int* arr ● arr[j]本质上是*(arrj) 表示访问下标为j的元素 ● arr[j]本质上是arrj 表示下标为j的元素的地址
4.4 思考:为什么数组传参 本质要传首元素的地址?
思考为什么这么设计? ● 首先 前面提到 数组是连续存放在内存中的 所以只要知道起始地址 就可以顺藤摸瓜找到整个数组 只传一个首元素地址 可以代表/找到整个数组 ● 其次 假设数组传参传的不是传址 而是一份数组的临时拷贝 那么假如数组100000个元素? 浪费空间和时间!!!
4.5 二维数组传参
请回看3.6
五、其他
怎么看数组的类型是什么 int num 10; 去掉变量名 剩下的就是类型 那么 int num[10] {1,2,3}; 去掉num 剩下的int [10] 就是类型 即数组num的类型就是int [10] 而且这个10不能被省略 算大小也不会这么算 因为[ ]写几 还得自己去数一下 只能说 就借此理解一下 数组也是有类型的 就跟int a 10的a一样 用整数初始化字符数组会怎么样 arr和(arr1) 首先必须要明确:取地址符是把某个变量的地址取出来了 之前我们说过 arr就是一个指针 不是指针变量 arr的本质是常量(十六进制形式) 所以 arr就是一个特例(按道理arr应该报错的 因为arr根本不是变量) 但是 arr直接把整个数组的地址取出来了 而除了单独的数组名arr这个特殊情况 arr1 得到的其实是第二个元素的地址 arr1是个指针 不是指针变量 本质是个常量(和arr一样) (arr1)就不存在特殊情况咯 按照的要求 直接就报错了 其实前面也已经说了 ● arr[j]本质上是arrj 表示下标为j的元素的地址 那(arr1) 相当于 (arr[1]) 介四嘛呀