目录
[4. * ( ) 与 [ ] 的互换](#4. * ( ) 与 [ ] 的互换)
[1. 字符](#1. 字符)
一.相关知识点
1.数组名是什么?
一维数组数组名是首元素的地址。

二维数组数组名是首元素地址,是第一行的地址(一维数组的地址)。
两个例外:
-
sizeof(数组名),这里的数组名是表示整个数组,计算的是整个数组的大小,单位是字节
-
&数组名,这里的数组名是表示整个数组,& 数组名取出的是数组的地址
2.strlen
**库函数,**用来求字符串长度,统计的是\0之前出现的字符个数,一定要找到 ' \0 ' 才算结束,所以可能存在越界访问的。
头文件:#include <stdio.h>

注意:strlen 的函数参数是字符指针类型,我们要传给它开始统计字符长度位置的地址
3.sizeof
**操作符,**只关注变量占用内存空间的大小,单位是字节,不关心内存中存放的是什么
注意:1.sizeof 内部的表达式不计算
cpp
int main()
{
int a = 0;
short s = 5;
printf("%d\n", sizeof(s = a + 3));//2
printf("%d\n", s);//5
return 0;
}
原因:

2.sizeof 根据类型判断大小,不会访问对应空间(不存在越界访问数组的情况)
变量是有类型的,数组也是有类型的。去掉名字就是类型
cpp
int main()
{
int a = 0;
int arr[10];
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(int [10])); //数组 arr 的类型:int [10]
return 0;
}
4. * ( ) 与 [ ] 的互换

二.一维数组
cpp
int main()
{
int a[] = { 1,2,3,4 };
return 0;
}
易混例题:
cpp
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(a + 1));
- 这里是数组名的两个例外情况之一,计算的是整个数组的大小。答案:4 * 4 = 16
2.3. 注意:这里sizeof( ) 里面不止有数组名,不是两个例外情况之一。
a 是数组首元素的地址,a + 0 也是数组第一个元素的地址,a + 1是第二个元素的地址。是地址就是4/8字节。答案:4/8
cpp
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[1]));
不是两个例外,a 是数组首元素地址。
*a是数组首元素,a[1] 是第二个元素。计算的是数组首,第二个元素的大小,单位字节。答案:4
cpp
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
- &a是整个数组的地址,整个数组的地址也是地址,地址的大小就是4/8字节
**&a 的类型:int (*)[4]**数组指针
-
&a是数组的地址,*&a就是拿到了数组。*&a --> a,a就是数组名,sizeof(*&a)-->sizeof(a)。计算的是整个数组的大小,单位是字节-16。
-
&a是整个数组的地址。&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4/8字节。
**&a+1 的类型还是 int (*)[4]**数组指针
是否会越界访问?
不会。 &a 与 &a+1 类型相同。**sizeof 根据类型判断大小,不会访问对应空间。**所以大小也相同。
cpp
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
&a[0]是首元素的地址,&a[0] + 1是第二个元素的地址,计算的是首元素地址的大小,地址的大小就是4/8字节
三.字符数组
1. 字符
cpp
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
return 0;
}
(1)sizeof
cpp
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
-
arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,6
-
arr 是首元素的地址,arr + 0 还是数组首元素的地址,4/8
-
arr 是首元素的地址,*arr是数组的首元素,计算的是首元素的大小:1字节
-
arr[1]是第二个元素,大小1字节
cpp
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
-
取出的数组的地址,数组的地址也是地址,是地址大小就是4/8
-
&arr+1是跳过整个,指向数组后边空间的地址,4/8
-
&arr[0] + 1是数组第二个元素的地址,是地址4/8字节
(2)strlen
cpp
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
1.2. 两个传的都是首元素地址,让 strlen 从首元素位置开始统计。但没有**' \0 '** 不止何时停止,随机值。
- &arr虽然是数组的地址,但是也是从数组起始位置开始的,计算的还是随机值
**&arr 的类型:char (*)[6]**数组指针
-
&arr是数组的地址,&arr+1是跳过整个数组的地址,求字符串长度也是随机值
-
&arr[0] + 1是第二个元素的地址,是'b'的地址,求字符串长度也是随机值
cpp
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
*arr 和 arr[1] 分别是数组第一元素 'a' ASCII码值是97 ;第二元素**'b' ASCII码值是98**
strlen('a') 等价于 strlen(97)。直接让 strlen 从内存编号97的地址开始统计。非法访问,这样写是错的!
97作为地址访问内存,抱歉,97这个地址不能直接访问。只有把这片空间分配给你,你才有权限访问它。
2.字符串
cpp
int main()
{
char arr[] = "abcdef"; // 数组是7个元素
// [ a b c d e f \0 ]
return 0;
}
(1)sizeof
cpp
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
-
数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节:7
-
arr+0是首元素的地址,大小是4/8
-
*arr是数组首元素,大小是1字节
-
arr[1]是数组的第二个元素,大小是1字节
cpp
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
-
&arr是数组的地址,数组的地址也是地址,是4/8字节
-
&arr + 1是跳过整个数组的地址,是4/8字节
-
&arr[0] + 1是第二个元素的地址,是4/8字节
(2)strlen
cpp
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
-
arr是数组首元素的地址,strlen从首元素的地址开始统计\0之前出现的字符个数,是6
-
arr + 0是数组首元素的地址,同第一个,结果是6
-
&arr虽然是数组的地址,但是也是从数组起始位置开始的,直至 \0 。 6
-
&arr + 1是跳过数组后的地址,统计字符串的长度是随机值
-
&arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5
cpp
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
非法访问
3.字符指针
cpp
int main()
{
const char* p = "abcdef";
return 0;
}
错:把字符串 abcdef 放到指针 p 里 对:把首字符的地址放到 p 里
字符串里面的内容,地址是连续的
字符串打印只要告诉我起始位置,就可以打印,直到 \0
(1)sizeof
cpp
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
-
p是指针变量,大小就是4/8字节
-
p + 1是b的地址,是地址,就是4/8个字节
-
*p是'a',sizeof(*p)计算的是字符的大小,是1字节
-
p[0] --> *(p+0) --> *p 就同上一个,1字节
cpp
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
-
取出 p 的地址,p 是 char* 类型的指针,&p 取出 char* 的地址,是二级指针 char* *。是指针大小就是4/8
-
&p + 1是跳过p变量后的地址,4/8字节

- p[0] 就是'a' , &p[0]就是a的地址,+1,就是b的地址,是地址就是4/8
也可以这样理解:
(2)strlen
cpp
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
-
p 指向 a 的地址,从 a 开始统计长度。6
-
p+1 指向 b 的地址,从 b 开始统计长度。5
cpp
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
*p 和 p[0] 都是 ' a ' 非法访问
cpp
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));

-
&p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值
-
&p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值
-
&p[0] + 1是b的地址,从b的地址向后数字符串的长度是5
四.二维数组
cpp
int main()
{
int a[3][4] = { 0 };
return 0;
}
cpp
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
-
计算整个数组的大小 3*4 * 4 = 48
-
a[0][0] 的第一行第一个元素。4
-
a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的就是数组(第一行)的大小,16个字节
-
a[0]是第一行的数组名。没有单独放在sizeof内部;没有取地址。表示的就是数组首元素的地址,是a[0][0]的地址。
a[0]+1就是第一行第二个元素的地址,是地址就是4/8个字节
- *(a[0] + 1)是第一行第2个元素,计算的是元素的大小。4个字节
cpp
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
- a是二维数组的数组名,数组名表示首元素的地址,就是第一行的地址,a+1就是第二行的地址。
第二行的地址也是地址,是地址就是4/8
a - int (*)[4] a+1--> int(*)[4]
-
a+1是第二行的地址,*(a+1)表示的就是第二行。16 *(a+1)--a[1]
-
&a[0]是第一行的地址,&a[0]+1是第二行的地址,地址的大小就是4/8
-
*(&a[0] + 1) 是对第二行的地址解引用,得到的就是第二行,计算的就是第二行的大小。16
-
a表示首元素的地址,就是第一行的地址,*a就是第一行,计算的就是第一行的大小。 *a -- *(a+0)--a[0]
cpp
printf("%d\n", sizeof(a[3]));
类型:int [4] 大小:16
如果数组存在第四行,a[3]就是第四行的数组名,数组名单独放在sizeof内部,计算的是第四行的大小