数组概念
- 存储相同数据类型的多个元素的复合的数据类型
- 将逻辑上的一组数据存储在一段连续的内存中
- 方便数据的管理
- 将逻辑上的一组数据存储在一段连续的内存中
int score[5]中,表示声明数组变量score,长度为5,每个元素的类型为int- score自身的数据类型为
int [5]类型
- score自身的数据类型为
- 判断变量的自身类型
- 去掉变量名后 剩余的就是自身类型
数组的初始化
- 数组的初始化只有在声明(定义)时可以初始化,声明后不可以初始化
- 原因是数组声明后不支持整体赋值 ,只能在声明时进行整体赋值
int arr1[5] = {1,2,3,4,5};
int arr2[5];
arr2 = {1,2,3,4,5}; //error 声明后不允许初始化
数组的特点
- 数组中所有元素的数据类型都是一致的
- 数组的内存是连续的,从低地址到高地址依次连续存放数组中的每一个元素
数组的赋值
- 数组只有在声明的时候支持整体赋值
- 数组如果初始化,可以在声明时省略数组长度,此时数组的长度将由编译器隐式指定
- 数组的初始化可以部分赋值,没有赋值的元素会自动赋值0
- 数组整体赋值,值长度不能超过数组的长度(不会报错,但是会产生段错误:非法访问内存)
- 数组清零
int arr[4] = {0}; - 数组若没有初始化,不能省略数组长度,其内部的元素为随机数
- 数组声明完毕后,只能通过下标逐个对元素进行赋值
- 下标地址偏移
- 下标就是地址偏移量,基于数组内存连续切元素大小相同的性质,偏移下标个元素自身大小的字节
- 语法:数组名[下标]
- 下标地址偏移
- 数组的长度计算
- 数组的总大小 / 数组中首个元素的大小 = 数组内元素的个数
int arrLen = sizeof(arr) / sizeof(arr[0])
变长数组
- 变长数组在定义时 使用变量作为数组的长度(长度可以是运行期变量)
- 普通数组的长度必须是编译期常量
- 变长数组不支持初始化
- 变长数组不能是全局变量
- 普通数组可以是全局变量,也可以是静态/局部变量
- 变长数组部分编译器不支持
- 普通数组所有C编译器都会支持
- 一经定义,变长数组的长度无法改变,不是可以动态扩容的数组
- 变长数组使用较少,推荐使用malloc分配内存(跨编译器兼容),代替变长数组
字符数组
数组元素是char(字符型)的数组,它可以是一维数组,也可以是二维数组
- 以双引号括起来的称为字符串类型,可以将其看作char类型的字符集合,在结尾会又以给“\0”(表示空)
- ‘\0' ASCII码为0
- 作用是表示一串字符串的结束
- 操作字符串时带入字符串的首地址,所以需要结束符来结束操作
- 作用是表示一串字符串的结束
- ‘\0' ASCII码为0
- <string.h>官方提供的字符串操作库
- strcpy()函数
- char *strcpy(char *dest, const char *src);
- dest 目标字符数组
- src 原字符串(const表示不改变源字符串)
- char *strcpy(char *dest, const char *src);
- strcpy()函数
- 字符串长度 不一定等于 字符数组长度
- 字符串长度: 字符起始位置到 \0 之间间隔的字符数量
char c1[2] = {'a','b','c'};//这不是一个字符串,右边全部被赋值,只能是一个字符数组
char c2[] = {"abc"};
//c3等价于c2数组
char c3[] = {'a','b'.'c','\0'};
char c4[3] = {'a','b','c'};//这是一个字符串 部分赋值后补0 相当于给结尾补了\0
数组名的含义
- 在C语言程序中,数组的出现有两种的可能的含义
- 代表整个数组
- 声明时 int arr 此时数组可以整体赋值
- 与sizeof使用时 sizeof(arr)
- 取地址时 &arr
- 代表首元素的地址
- 其他情况一律表示首元素的地址
- 代表整个数组
//数组的声明arr表示整个数组
int arr[] = {1,2,3,4};
//此处arr与sizeof结合,arr表示整个数组
printf("%ld \n", sizeof(arr));
//此处arr与&取地址符结合,aee表示整个数组
printf("%p \n", &arr);
//arr除了以上三种情况,都表示首元素的地址
printf("%p \n", arr);
等价于
printf("%p \n", &(arr[0]));
printf("%d \n", &arr);
printf("%d \n", arr[0]);
数组的下标运算符
arr[下标] 是 *(arr + 下标)的简写
- 地址的(整数)加法运算
- 本质上是地址指向的那段内存的偏移
int a;
char b;
double c;
//a是一个int类型的内存,大小为4,地址+1等于地址偏移一个(自身)内存(4)的大小
printf("地址 %p \n",&a);
printf("地址 %p \n",&a + 1);
//b c 同理
int arr[5] = {1,2,3,4,5};
printf("地址 %p \n",arr);// 0xffffcbd0 首元素的地址
printf("地址 %p \n",&arr);// 0xffffcbd0 整个数组的地址
printf("地址 %p \n",arr + 1);// 首元素的地址 + 1,偏移1个首元素大小字节(+4) 0xffffcbd4
printf("地址 %p \n",&arr + 1); //整个数组的地址+1,偏移1个数组自身大小字节(+20) 0xffffcbe4
- 地址与地址不能相加,但是地址可以和地址相减
- 表示两个地址之间间隔相同元素大小的偏移量
- 只有相同类型可以相减,不同类型不能相减
- 表示两个地址之间间隔相同元素大小的偏移量
int d, e, f;
printf("d:%p \n e:%p \n f:%p \n", &d, &e, &f);
printf("%d \n", &d - &f );
//d:0xffffcbcc
//e:0xffffcbc8
//f:0xffffcbc4
//偏移量 2
解引用符
- ’ * ‘ 解引用符
- 根据内存地址找到某段内存获取其值
- (缩小范围,范围缩到不能缩时取值)
- ’ & ‘取地址符
- 返回指定(变量)内存的地址
- (地址向上扩大其范围)
int arr[5] = {1,2,3,4,5};
printf("%d \n", *arr); // arr表示首元素地址,* 根据首元素的地址找到首元素获取它的值
//arr == &(arr[0])
//*arr == *&(arr[0]) == arr[0]
printf("%d \n", *&arr); // arr首元素地址
int arr[5];
scanf("%c", arr); // 等价于scanf("%c", &(arr[0]));
scanf("%c", arr + 1);// 等价于scanf("%c", &(arr[1]));
a[b] 语法是一个简写 C语言中展开为 *(a + b)
array[i] 是代码 *(array + i)
%S 本质上是接受一个地址,向后读取字符直到\0 截止
字符串操作
- 字符串常量
- 在内存中存储,实质上是一个匿名数组(没有变量名)
- 匿名数组
- 满足数组两种涵义的规定
- 匿名数组是只读的,字符串常量不可改变(编译不报错,运行会报错)
- 程序运行时,内存分为栈、堆、数据段
- 常量存储在数据段里
- 匿名数组
- 在内存中存储,实质上是一个匿名数组(没有变量名)
printf("%d\n", sizeof("abcd")); // 此处 "abcd" 代表整个数组
printf("%p\n", &"abcd"); // 此处 "abcd" 代表整个数组
printf("%c\n", "abcd"[1]); // 此处 "abcd" 代表匿名数组的首元素地址
char *p1 = "abcd"; // 此处 "abcd" 代表匿名数组的首元素地址
char *p2 = "abcd" + 1; // 此处 "abcd" 代表匿名数组的首元素地址
- 字符串的拷贝
- 作用:将src字符串 拷贝到dest
- char *strcpy(char *dest, const char *src);
- dest 目标字符串 src:源字符串
- 作用:将src字符串 拷贝到dest
- 字符串的比较
- 作用:比较两个字符串的是否相同
- int strcmp(const char *s1, const char *s2);
- 如果相同返回0,如果不同返回第一个不同字符的差值
- 作用:比较两个字符串的是否相同
- 字符串的长度测量
- int length = strlen(str1);
- 长度不包括'\0'
- int length = strlen(str1);
字符串常量数组
char *arr["hello","world","aaa"];
| hello | world | aaa | |
| 首元素地址 | 0x123 | 0x456 | 0x789 |
- 上面的arr是一个数组
- 里面的子元素起始只是字符串常量首元素的地址
- arr长度为3 子元素类型为 char * (字符地址)类型
printf("%s", arr[0]); //本质上是把hello字符串的首地址传给%s,找到这段内存后顺序读取,直到\0结束,读取到hello并打印
printf("%s", arr[0] + 1); //本质上是0x123+1 等于0x124,等同于'e'的地址,然后向后输出
*(arr[0] + 1) 地址先进行加法运算(偏移),再解引用(根据地址(arr[0] + 1 == 0x124)取值)
*(arr[0] + 1) 地址先进行加法运算(偏移),再解引用(根据地址(arr[0] + 1 == 0x124)取值)
对于上述代码,可以有万能公式的转换
*(a + b) == a[b] == arr[0][1]
arr[0][1] == 'E' 不能修改,因为引用的hello是一个常量
Comments NOTHING