文章目录
- 1.一维数组
- 1.1 整型数组
- 1.2 字符数组
- 2. 二维数组
- 3.指针笔试题
- 3.1 练习1
- 3.2 练习2
- 3.3 练习3
数组名的意义:
1.sizeof(数组名),这里的数组表示整个数组,计算的整个数组的大小
2.&数组名,这里的数组名表示整个数组的,取出的是整个数组的地址
3.除此之外所有的数组名都是表示首元素的地址。
1.一维数组
1.1 整型数组
int main()
{
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//16,sizeof单独加上数组名计算的是整个数组的大小
printf("%d\n",sizeof(a+0));//4或者8,这里数组名不是单独在sizeof内,所以会变成数组首元素的地址,而指针的大小根据选择的是32位还是64位而不同。
printf("%d\n",sizeof(*a));//4,a是首元素的地址,被解引用后就是首元素。整型为4个字节大小
printf("%d\n",sizeof(a+1));// 4/8,表示数组第二个元素的地址
printf("%d\n",sizeof(a[1]));//4,表示数组第一个元素是整型
printf("%d\n",sizeof(&a));// 4/8,&数组名拿到是整个数组的地址,而整个数组的地址也是指针,所以大小还是4或者8
printf("%d\n",sizeof(*&a));//16,取地址和解引用相互抵消,使得本质上是sizeof(a)
printf("%d\n",sizeof(&a[0]));//4/8,计算的数组首元素的地址,也就是指针
printf("%d\n",sizeof(&a[0]+1));//4/8,计算的是数组第二个元素的地址,也就是指针
return 0;
}
//打印结果
/*
16
8
4
8
4
8
16
8
8
*/
1.2 字符数组
#include <stdio.h>
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr+1));
printf("%d\n",sizeof(arr+0));
printf("%d\n",sizeof(*arr));
printf("%d\n",sizeof(arr[1]));
printf("%d\n",sizeof(&arr));
printf("%d\n",sizeof(&arr+1));
printf("%d\n",sizeof(&arr[0]+1));
return 0;
//与上面解释类似
}
//打印结果:
/*
6
8
8
1
1
8
8
8
*/
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(arr));//随机值,表示的是从数组的首元素开始计算直到碰到'\0'为止的长度
printf("%d\n",strlen(arr+0));//随机值,表示的是从数组的首元素开始计算直到碰到'\0'为止的长度
printf("%d\n",strlen(*arr));//错误写法,strlen函数参数要传地址
printf("%d\n",strlen(arr[1]));//错误写法,strlen函数参数要传地址
printf("%d\n",strlen(&arr));/*随机值,虽然&arr表示的是整个数组的地址,但是整个数组的地
址依旧是用数组首元素的地址代表。表示的是从数组的首元素开始计算直到碰到'\0'为止的长度*/
printf("%d\n",strlen(&arr+1));//随机值,表示的是从数组的最后一个元素后的地址开始计算直到碰到'\0'为止的长度。会比第一个随机值数少6个字节
printf("%d\n",strlen(&arr[0]+1));//随机值,表示从数组第二个元素地址开始计算直到碰到'\0'为止的长度。会比第一个随机值数少1个字节
return 0;
}
//打印结果:
/*(注释掉错误写法后)
42
42
42
36
41
*/
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr+1));
printf("%d\n",sizeof(arr+0));
printf("%d\n",sizeof(*arr));
printf("%d\n",sizeof(arr[1]));
printf("%d\n",sizeof(&arr));
printf("%d\n",sizeof(&arr+1));
printf("%d\n",sizeof(&arr[0]+1));
//整体解释和第一道题类型,不过要注意的是sizeof会计算隐藏的'\0'的大小。
return 0;
}
//打印结果:
/*
7
8
8
1
1
8
8
8
*/
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n",strlen(arr));//6,该数组arr最后隐藏了一个'\0',strlen计算到'\0'为止
printf("%d\n",strlen(arr+0));//6,该数组arr最后隐藏了一个'\0',strlen计算到'\0'为止
printf("%d\n",strlen(*arr));//错误写法,strlen函数参数要传地址
printf("%d\n",strlen(arr[1]));//错误写法,strlen函数参数要传地址
printf("%d\n",strlen(&arr));//6,&arr虽然表示整个数组的地址,但是地址是用数组首元素地址来代表的。
printf("%d\n",strlen(&arr+1));//随机值,&arr表示整个数组的地址,+1跳过整个数组,也跳过了'\0',直到找到后面的'\0'才会停止
printf("%d\n",strlen(&arr[0]+1));//5,表示从数组的第二的元素地址开始往后计算长度。
return 0;
}
//打印结果
/*(注释掉错误写法后)
6
6
6
26
5
*/
#include <stdio.h>
int main()
{
char* arr = "abcdef";
printf("%d\n",sizeof(arr));//4/8,这里的arr不能等同于数组,arr就是指针,这个指针指向了"abcdef"这个常量字符串
printf("%d\n",sizeof(arr+1));//4/8,arr+1就表示该常量字符串第二个元素的地址
printf("%d\n",sizeof(*arr));//1,对指针解引用得到的就是首元素'a',类型char大小为1字节。
printf("%d\n",sizeof(arr[0]));//1,arr[0]数组首元素'a'
printf("%d\n",sizeof(&arr));//4/8,&arr表示arr的地址也就是一个二级指针
printf("%d\n",sizeof(&arr+1));//4/8,&arr+1也是二级指针,
printf("%d\n",sizeof(&arr[0]+1));//4/8,表示第二个元素'b'的地址
return 0;
}
//打印结果:
/*
8
8
1
1
8
8
8
*/
#include <stdio.h>
#include <string.h>
int main()
{
char* arr = "abcdef";
printf("%d\n",strlen(arr));//6,arr存放的就是首元素的地址
printf("%d\n",strlen(arr+1));//5,传入第二个元素的地址
printf("%d\n",strlen(*arr));//错误写法,strlne必须传地址进去
printf("%d\n",strlen(arr[0]));//错误写法,strlne必须传地址进去
printf("%d\n",strlen(&arr));//随机值,&arr是首元素'a'地址的地址,是一个二级指针,会一直找到下一个'\0'为止。
printf("%d\n",strlen(&arr+1));//随机值,是一个二级指针(不一定在&arr后面),会一直找到下一个'\0'为止。
printf("%d\n",strlen(&arr[0]+1));//5,传入第二个元素的地址
return 0;
}
//打印结果:
/*(注释掉错误写法后)
6
5
3
11
5
*/
2. 二维数组
#include <stdio.h>
int main()
{
int a[3][4] = {0};
printf("%d\n",sizeof(a));//48,sizeof(数组名)计算的整个数组的大小
printf("%d\n",sizeof(a[0][0]));//4,a[0][0]就是首元素
printf("%d\n",sizeof(a[0]));//16,a[0]是第一行这个一维数组的数组名
//数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节
printf("%d\n",sizeof(a[0]+1));//4/8,a[0]是第一行数组名,+1就不算单独放到sizeof中了。
printf("%d\n",sizeof(*(a[0]+1)));//4,相当于a[0][1],拿到了数组第1行第2列的元素
printf("%d\n",sizeof(a+1));// 4/8,数组名除俩个的特殊情况外都是数组首元素的地址,
//这里加1拿到就是第二行的地址,是指针
printf("%d\n",sizeof(*(a+1)));//16,相当于a[1],计算的第二行的大小
printf("%d\n",sizeof(&a[0]+1));//4/8,&a[0]+1,a[0]相当于第一行的数组名,&a[0]就是第一行数组的地址,加1跳过第一行,就是第二行数组的地址,是指针。
printf("%d\n",sizeof(*(&a[0]+1)));//16,计算的是第二行的大小,&a[0]拿到第一行的地址,然后+1拿到第2行的地址,再解引用拿到就是第二行了。
printf("%d\n",sizeof(*a));//16,a表示的一行的地址,*a就是拿到第一行,
printf("%d\n",sizeof(a[3]));//16,虽然数组越界了但是,在sizeof的执行过程中是不会使用a[3]的,sizof(a[3])会把a[3]理解为第4行的数组名,
return 0;
}
//打印结果:
/*
48
4
16
8
4
8
16
8
16
16
16
*/
3.指针笔试题
3.1 练习1
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
int* ptr = (int* )(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
return 0;
}
//打印结果:2,5
/*
解释:&a拿到的是整个数组的地址,加1后跳过整个数组来到数组最后一个元素后面。也就说明了ptr的指向的地址再5的地址的后面,然后强制类型转换成整型指针,而整型指针-1只会前移动4个字节,ptr会指向5的地址。而a是数组名,表示数组首元素的地址,+1后就来到了第二个元素的地址。
*/
3.2 练习2
#include <stdio.h>
//这个结构体的大小是20个字节
struct test
{
int Num;
char* pcname;
short sdata;
char cha[2];
short sba[4];
}*p = (struct Test*)0x100000;
//假设p的值为0x100000.
//已知test结构体的大小是20个字节
int main()
{
printf("%p\n",p+0x1);
printf("%p\n",(unsigned long)p+0x1);
printf("%p\n",(unsigned long*)p+0x1);
return 0;
}
//打印结果:
/*
00100014
00100001
00100004
*/
/*
解释:这里p指向的地址是0x100000。0x1就是1的16进制表达。p加1,因为p指向类型是struct test,类型大小20个字节,加1后也会跳过20这个字节(转换成16进制就是14).
后面p指针被强制类型转换成了一个无符号长整形的变量,这个类型不是指针变量,加1就是整数加1.
最后一个强制类型转换成了一个无符号长整形指针变量,是指针,然后无符号长整形的大小是4个字节,加1也就是跳过4个字节。
*/
3.3 练习3
#include <stdio.h>
int main()
{
int a[4] = {1,2,3,4};
int* ptr1 = (int*)(&a+1);
int* ptr2 = (int*)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);//%x为16进制打印
return 0;
}
//打印结果:4,2000000
/*
解释放下面
*/
ptr1:&a+1表示的跳过这个数组后的地址,也就是4后面的地址,然后被强制类型转换为了int*
ptr2:a是数组首元素的地址,都是被强制类型转换为了整型,然后+1,因为是整型加1就是数字加1.然后又被强制类型转换成了int*。
此时的指向如图所示
因为元素在系统当中是小端存储的,
1会被存储为:01 00 00 00
此时ptr2指向的就是01后面00的位置。
我们又知道数组中1的后面是2。
小端存储就是 01 00 00 00 02 00 00 00
ptr2被强制类型转换为了int*,解引用会一次取出4个字节,取出的就是00 00 00 02,将顺序反转成正常顺序就是02000000,打印时省略掉了第一个0变成了200000
ptr1[-1]的意思就是*(prt1-1).就拿出来4.