目录
一.相关知识点
1.数组名是什么?
两个例外:
2.strlen
3.sizeof
4. * ( ) 与 [ ] 的互换
二.一维数组
三.字符数组
1. 字符
(1)sizeof
(2)strlen
2.字符串
(1)sizeof
(2)strlen
3.字符指针
(1)sizeof
(2)strlen
四.二维数组
一.相关知识点
1.数组名是什么?
一维数组数组名是首元素的地址。
二维数组数组名是首元素地址,是第一行的地址(一维数组的地址)。
两个例外:
1. sizeof(数组名),这里的数组名是表示整个数组,计算的是整个数组的大小,单位是字节
2. &数组名,这里的数组名是表示整个数组,& 数组名取出的是数组的地址
2.strlen
库函数,用来求字符串长度,统计的是\0之前出现的字符个数,一定要找到 ' \0 ' 才算结束,所以可能存在越界访问的。
头文件:#include <stdio.h>
注意:strlen 的函数参数是字符指针类型,我们要传给它开始统计字符长度位置的地址
3.sizeof
操作符,只关注变量占用内存空间的大小,单位是字节,不关心内存中存放的是什么
注意:1.sizeof 内部的表达式不计算
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 根据类型判断大小,不会访问对应空间(不存在越界访问数组的情况)
变量是有类型的,数组也是有类型的。去掉名字就是类型
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. * ( ) 与 [ ] 的互换
二.一维数组
int main()
{
int a[] = { 1,2,3,4 };
return 0;
}
易混例题:
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(a + 1));
1. 这里是数组名的两个例外情况之一,计算的是整个数组的大小。答案:4 * 4 = 16
2.3. 注意:这里sizeof( ) 里面不止有数组名,不是两个例外情况之一。
a 是数组首元素的地址,a + 0 也是数组第一个元素的地址,a + 1是第二个元素的地址。是地址就是4/8字节。答案:4/8
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[1]));
不是两个例外,a 是数组首元素地址。
*a是数组首元素,a[1] 是第二个元素。计算的是数组首,第二个元素的大小,单位字节。答案:4
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
1. &a是整个数组的地址,整个数组的地址也是地址,地址的大小就是4/8字节
&a 的类型:int (*)[4] 数组指针
2. &a是数组的地址,*&a就是拿到了数组。*&a --> a,a就是数组名,sizeof(*&a)-->sizeof(a)。计算的是整个数组的大小,单位是字节-16。
3. &a是整个数组的地址。&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4/8字节。
&a+1 的类型还是 int (*)[4] 数组指针
是否会越界访问?
不会。&a 与 &a+1 类型相同。sizeof 根据类型判断大小,不会访问对应空间。所以大小也相同。
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
&a[0]是首元素的地址,&a[0] + 1是第二个元素的地址,计算的是首元素地址的大小,地址的大小就是4/8字节
三.字符数组
1. 字符
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
return 0;
}
(1)sizeof
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
1. arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,6
2. arr 是首元素的地址,arr + 0 还是数组首元素的地址,4/8
3. arr 是首元素的地址,*arr是数组的首元素,计算的是首元素的大小:1字节
4. arr[1]是第二个元素,大小1字节
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
1. 取出的数组的地址,数组的地址也是地址,是地址大小就是4/8
2. &arr+1是跳过整个,指向数组后边空间的地址,4/8
3. &arr[0] + 1是数组第二个元素的地址,是地址4/8字节
(2)strlen
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 ' 不止何时停止,随机值。
3. &arr虽然是数组的地址,但是也是从数组起始位置开始的,计算的还是随机值
&arr 的类型:char (*)[6] 数组指针
4. &arr是数组的地址,&arr+1是跳过整个数组的地址,求字符串长度也是随机值
5. &arr[0] + 1是第二个元素的地址,是'b'的地址,求字符串长度也是随机值
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.字符串
int main()
{
char arr[] = "abcdef"; // 数组是7个元素
// [ a b c d e f \0 ]
return 0;
}
(1)sizeof
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
1. 数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节:7
2. arr+0是首元素的地址,大小是4/8
3. *arr是数组首元素,大小是1字节
4. arr[1]是数组的第二个元素,大小是1字节
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
1. &arr是数组的地址,数组的地址也是地址,是4/8字节
2. &arr + 1是跳过整个数组的地址,是4/8字节
3. &arr[0] + 1是第二个元素的地址,是4/8字节
(2)strlen
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. arr是数组首元素的地址,strlen从首元素的地址开始统计\0之前出现的字符个数,是6
2. arr + 0是数组首元素的地址,同第一个,结果是6
3. &arr虽然是数组的地址,但是也是从数组起始位置开始的,直至 \0 。 6
4. &arr + 1是跳过数组后的地址,统计字符串的长度是随机值
5. &arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
非法访问
3.字符指针
int main()
{
const char* p = "abcdef";
return 0;
}
错:把字符串 abcdef 放到指针 p 里 对:把首字符的地址放到 p 里
字符串里面的内容,地址是连续的
字符串打印只要告诉我起始位置,就可以打印,直到 \0
(1)sizeof
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
1. p是指针变量,大小就是4/8字节
2. p + 1是b的地址,是地址,就是4/8个字节
3. *p是'a',sizeof(*p)计算的是字符的大小,是1字节
4. p[0] --> *(p+0) --> *p 就同上一个,1字节
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
1. 取出 p 的地址,p 是 char* 类型的指针,&p 取出 char* 的地址,是二级指针 char* *。是指针大小就是4/8
2. &p + 1是跳过p变量后的地址,4/8字节
3. p[0] 就是‘a’ , &p[0]就是a的地址,+1,就是b的地址,是地址就是4/8
也可以这样理解:
(2)strlen
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
1. p 指向 a 的地址,从 a 开始统计长度。6
2. p+1 指向 b 的地址,从 b 开始统计长度。5
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
*p 和 p[0] 都是 ' a ' 非法访问
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
1. &p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值
2. &p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值
3. &p[0] + 1是b的地址,从b的地址向后数字符串的长度是5
四.二维数组
int main()
{
int a[3][4] = { 0 };
return 0;
}
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)));
1. 计算整个数组的大小 3*4 * 4 = 48
2. a[0][0] 的第一行第一个元素。4
3. a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的就是数组(第一行)的大小,16个字节
4. a[0]是第一行的数组名。没有单独放在sizeof内部;没有取地址。表示的就是数组首元素的地址,是a[0][0]的地址。
a[0]+1就是第一行第二个元素的地址,是地址就是4/8个字节
5. *(a[0] + 1)是第一行第2个元素,计算的是元素的大小。4个字节
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));
1. a是二维数组的数组名,数组名表示首元素的地址,就是第一行的地址,a+1就是第二行的地址。
第二行的地址也是地址,是地址就是4/8
a - int (*)[4] a+1--> int(*)[4]
2. a+1是第二行的地址,*(a+1)表示的就是第二行。16 *(a+1)--a[1]
3. &a[0]是第一行的地址,&a[0]+1是第二行的地址,地址的大小就是4/8
4. *(&a[0] + 1) 是对第二行的地址解引用,得到的就是第二行,计算的就是第二行的大小。16
5. a表示首元素的地址,就是第一行的地址,*a就是第一行,计算的就是第一行的大小。 *a -- *(a+0)--a[0]
printf("%d\n", sizeof(a[3]));
类型:int [4] 大小:16
如果数组存在第四行,a[3]就是第四行的数组名,数组名单独放在sizeof内部,计算的是第四行的大小