前言
以下均使用visual Stdio 2022集成开发环境,测试环境为windows 11 ,debug版本64位操作数,内容仅供初学者参考。
目录
一、数组
Ⅰ、数组的创建
数组的出现是为了更好的存放可视化的一组数据。所以数组的功能就是存放一组数据,在C语言中数组是用来存放相同类型数据的集合。
数组的创建方式:
#define SIZE 4
int main() {
int arr1[5] = { 0 };
int arr2[] = { 1,2,3,4,5 };
char arr3[SIZE] = { '1', '2', '3', '4' };
char arr4[4] = { '1 ', 97 , '5' };
char arr[10] = "abcdef";
return 0;
}
数组的创建规则:
数组类型 数组名[ 数组大小 ]
①、给数组初始化的时候使用大括号,数组元素用 ‘ , ’ 隔开。
②、数组的不完全初始化:如果初始化的数量小于数组容量,则初始化元素从左到右依次排列,剩下的空位默认补0(注意在C99标准中的加长数组是不能不完全初始化的,因为变量大小不确定),如果初始化是{ 0 } 则数组所有元素全部初始化为0。
③、数组自适应大小:当我们给数组初始化,并且没有给确定的数组大小的时候,比如初始化中有7个数据,编译器就会自适应该数组大小为7。
④、初始化数据类型尽量与数组类型相匹配,否则会出现数据截断导致数据流失,或者导致代码编译不通过。
⑤、初始化数组大小有分化:在C99标准之后,数组的初始化大小是可以使用变量的,这种数组叫做加长数组。但是Visual stdio 2022支持的不是C99以后的标准,所以这里数组初始化变量只能用常量
定义数组大小可以使用的常量类型包括:
Ⅰ、字面常量(比如 5, 6,2这种)
Ⅱ、define定义的标识符常量(定义形式:#define+ 空格 + 常量名+ 空格 + 大小)
Ⅲ、枚举常量(enum)
C语言中有哪些常量?————<常量>
使用字符串初始化数组
char arr5[] = "abcdef";
char arr6[] = { 'a','b','c','d','e','f' };
使用调试窗口可以清楚地看到:
字符串的特殊地方在于:字符串的末尾总是会追加一个 '\0' ,因为字符串存放在内存条中,如果想要取出这个字符串,我们不知道这个字符串从那里结束,所以就引入了这个 字符串结束标志 :'\0',它的ASCLL码为数字0。
Ⅱ、数组的使用
①、基本使用
既然是一组元素,那么肯定有顺序,有引用方式,比如:arr[ 0 ]
0是数组的下标,数组默认是从0开始逐渐递增的。
比如想取出 'c' 那么就是arr[2]
②、数组在内存中的存放
#include <stdio.h>a
int main() {
int arr[] = { 1,2,3,4,5 };
for (int i = 0; i < 5; i++) {
printf("%X\n", &arr[i]);
}
return 0;
}
%x是打印16进制,&arr[ i ]取到的是每一个元素的地址。可以看到每个元素之间的差值都是4,并且数组类型是整型,整型也是4字节。由此可以得知数组的内存分布如下:
为什么数据倒着放?————<大小端字节序>
③、如何玩转数组?
数组的基本使用和结构都懂了,但是还是有很多骚操作。
比如数组其实就是一个地址,但是相同的地址,却有不同的涵义!
#include <stdio.h>
int main() {
int arr[3] = { 1,2,3 };
printf("%X\n", &arr);
printf("%X\n", &arr[0]);
printf("\n");
printf("%X\n", &arr + 1);
printf("%X\n", &arr[0] + 1);
return 0;
}
两个表达式的结果都为500FFAD8,但是加一之后结果明显不相等!
原因:
arr表示的是整个数组,所以&arr取出的是整个数组的地址,这个地址有隐式包含整个数组,所以 加一就会加到整个数组后面!
&arr[ 0 ] 表示的是第一个元素 的地址,该地址隐式包含第一个元素,所以加一就是加到这个元素后面。
注意:地址是具有维护范围的,地址加一并不是普通加一,而是以这个维护范围为单位相加!
关于数组其他的使用:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() { int arr[3] = { 1,2,3 }; //获取数组的大小 printf("数组的大小:%d\n", sizeof(arr) / sizeof(int)); int str[10] = { 0 }; //循环赋值 for (int i = 0; i < 10; i++) { str[i] = i; } //循环打印 for (int i = 0; i < 10; i++) { printf("%d ", str[i]); } printf("\n"); return 0; }
注:sizeof操作符可以获得指定变量的大小,单位是字节。
数组的越界操作:
#include <stdio.h> int main() { int arr[3] = { 1,1,1 }; for (int i = 0; i < 5; i++) { printf("%d\n", arr[i]); } return 0; }
数组可用下标一定是0~数组大小 - 1,数组外的数据可能被别的变量初始化了,也可能没被初始化,没被初始化的就是随机值,但是在visual Stdio 2022中main函数的维护空间内的内存全部被修改为了cc,比如4个字节 的修改就是 0xcc cc cc cc = - 858993460,所以会输出-858993460!
深入理解vs的工作原理———— <函数栈帧的创建与销毁(创作中)>
Ⅲ、 二维数组
二维数组的几种创建方式:
int arr1[][3] = { { 1,2,3},{2,3,4},{3,4,5} }; int arr2[2][3] = { 0 };
二维数组的创建方式:
数组类型 数组名[ 列大小 ] [ 行大小 ]
①、二维数组行和列下标都是从0开始。
②、创建二维数组的时候,列可以不明确,但是行一定要明确。
③、二维数组中每一列都是一个一维数组,可以套用一维数组的技巧
二维数组的本质其实是一个二级指针,我们同样可以使用二级指针的方式调用它!
#include <stdio.h> int main() { int arr1[][3] = { { 1,23,31},{22,33,45},{34,41,54} }; printf("%d\n", *(*(arr1))); printf("%d\n", *( * (arr1 + 1))); printf("%d\n", *(*(arr1 + 1) + 1)); return 0; }
二级指针入口———— <二级指针(创作中)>