zl程序教程

您现在的位置是:首页 >  后端

当前栏目

指针和数组 【sizeof 、strlen与指针和数组的综合题、以及笔试题】

数组 以及 指针 笔试 sizeof strlen
2023-09-27 14:21:00 时间

一、一维数组

数组名:通常指的是首元素地址
两个例外:
1.sizeof(数组名) - 整个数组的所占空间大小
2.&数组名 - 整个数组的地址

int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	//sizeof是操作符,求内存空间所占的字节

	printf("%d\n", sizeof(a));//16       
 //size(数组名) - 整个个数组的大小 4*4=16字节
 	printf("%d\n", sizeof(a + 0));//4/8  
 //首元素地址 +0 - 还是首元素地址  4/8
	printf("%d\n", sizeof(*a));//4       
 //*a 首元素地址解引用 - 首元素(整型)4字节
	printf("%d\n", sizeof(a + 1));//4/8	 
 //首元素地址+1 - 第二个元素的地址 - 指针 4/8
	printf("%d\n", sizeof(a[1]));//4	 
 //a[1]是数组第二个元素,整型 - 4字节
	printf("%d\n", sizeof(&a));//4/8	 
 //&数组名 - 整个数组的地址 - 4/8
	printf("%d\n", sizeof(*&a));//16	 
 //*&a - a -sizeof(a) - 整个数组的大小 -16
	printf("%d\n", sizeof(&a + 1));//4/8 
 //&a + 1 - 数组指针 +1,跳过整个数组,仍然是指针 4/8 
	printf("%d\n", sizeof(&a[0]));//4/8	 
 //&a[0] - 首元素地址 4/8
	printf("%d\n", sizeof(&a[0] + 1));//4/8 
 //&a[0] + 1 首元素地址+1,第二个元素的地址 4/8

	return 0;
}

二、字符数组 - 数组里存的是单个字符

int main()
{
	//字符数组 - 数组里存的是单个字符
	char arr[] = { 'a','b','c','d','e','f' };

	//printf("%d\n", sizeof(arr));//6		
	整个数组的大小 - 字符数组 - 6*1=6 
	//printf("%d\n", sizeof(arr + 0));//4/8
	首元素地址+0 - 首元素地址 4/8
	//printf("%d\n", sizeof(*arr));//1
	*arr 首元素 - 字符型 - 1字节
	//printf("%d\n", sizeof(arr[1]));//1
	arr[1] - 数组第二个元素 - 字符型 - 1字节
	//printf("%d\n", sizeof(&arr));//4/8
	&数组名 - 整个数组的地址 - 4/8
	//printf("%d\n", sizeof(&arr + 1));//4/8
	&arr + 1 - 整个数组的地址 + 1 跳过整个数组 - 仍然是地址 4/8
	//printf("%d\n", sizeof(&arr[0] + 1));//4/8
	&arr[0] + 1  - 首元素地址+1 -第二个元素的地址 - 4/8

	//char arr[] = { 'a','b','c','d','e','f' };
	//strlen() - 字符串函数 - 计算字符串的个数,数到字符串结束标志\0前。
	printf("%d\n", strlen(arr));//随机值
	//字符串abcdef没有看到\0,strlen()会继续往后找,直到遇见\0结束,所以这里的值是未知的,随机值
	printf("%d\n", strlen(arr + 0));//随机值
	//首元素地址 +0 - 首元素地址 - 从首元素地址开始往后找,直到\0,同样也是随机值
	//printf("%d\n", strlen(*arr));//非法访问error
	//*arr 首元素 - strlen() 是通过指针来计算字符串的,所以这是错误的
	//printf("%d\n", strlen(arr[1]));//非法访问error
	//arr[1]数组第二个元素 - 同样错误
	printf("%d\n", strlen(&arr));//随机值
	//&arr - 整个数组的地址,随机值
	printf("%d\n", strlen(&arr+1));//随机值-6
	//整个数组的地址+1 - 跳过整个数组 - 随机值-6
	printf("%d\n", strlen(&arr[0] + 1));//随机值-1
	//首元素地址+1 - 跳过一个char - 第二个字符的地址 - 随机值-1
 
	return 0;
}

 三、字符数组 - 数组里存的是字符串

int main()
{
	//字符数组 - 数组里存的是字符串 - a b c d e f \0
	char arr[] = "abcdef";

	//printf("%d\n", sizeof(arr));//7
	字符的个数6个(abcdefg)+字符串的结束标志\0 = 7
	//printf("%d\n", sizeof(arr + 0));//4/8
	首元素地址+0 - 首元素地址 -4/8
	//printf("%d\n", sizeof(*arr));//1
	首元素 - 字符型 - 1
	//printf("%d\n", sizeof(arr[1]));//1
	第二个元素 - 字符型 -1
	//printf("%d\n", sizeof(&arr));//4/8
	整个数组的地址 - 4/8
	//printf("%d\n", sizeof(&arr + 1));//4/8
	整个数组的地址 +1 跳过整个数组 - 仍然是地址 - 4/8
	//printf("%d\n", sizeof(&arr[0] + 1));//4/8
	//首元素地址 +1 - 第二个元素的地址 -4/8

	//char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//6
	//首元素地址 - 直到\0 - 一共6个字符
	printf("%d\n", strlen(arr + 0));//6
	//首元素地址 - 直到\0 - 6
	//printf("%d\n", strlen(*arr));//非法访问error
	//首元素 - strlen()通过指针计算 - 非法访问
	//printf("%d\n", strlen(arr[1]));//非法访问error
	//第二个元素 - 同理 - 非法访问
	printf("%d\n", strlen(&arr));//6
	//整个数组的地址 - 相当于从首元素地址开始 - 直到\0 -6
	printf("%d\n", strlen(&arr + 1));//随机值
	//整个数组的地址 +1 - 跳过整个数组 -  此时已经错过了字符abcdef的\0了,只能往后一直找直到遇到\0
	printf("%d\n", strlen(&arr[0] + 1));//
	//首元素地址 +1 - 跳过一个元素到第二个元素的地址 - 6-1=5
	return 0;
}

 四、 指针 - 指向一个字符串的指针

int main()
{
	char* p = "abcdef";

	//printf("%d\n", sizeof(p));//4/8
	p 是指针 - 指向字符串起始a - 4/8
	//printf("%d\n", sizeof(p + 1));//4/8
	p + 1,指向第二个字符 -仍然是指针 - 4/8
	//printf("%d\n", sizeof(*p));//1
	*p得到第一个元素  - 字符型 - 1
	//printf("%d\n", sizeof(p[0]));//1
	p[0] 等价于 *(p+0) - 第一个元素 - 字符型 - 1
	//printf("%d\n", sizeof(&p));//4/8
	p本身是一个指向字符串"abcdef"的指针 - &p 对指针取地址 - 仍然是地址 -4/8
	//printf("%d\n", sizeof(&p + 1));//4/8
	对指针取地址 + 1 - 指针 - 4/8
	//printf("%d\n", sizeof(&p[0] + 1));//4/8
	//首元素地址 +1 - 地址 - 4/8


	//	char* p = "abcdef";

	printf("%d\n", strlen(p));//6
	//p 是指针 - 指向首元素a - 往后数直到\0 - 6
	printf("%d\n", strlen(p + 1));//5
	//指针p +1 - 指向第二个元素b的地址 - 6-1=5
	//printf("%d\n", strlen(*p));//非法访问error
	//*p 首元素 - 非法访问
	//printf("%d\n", strlen(p[0]));//非法访问error
	//首元素 - 非法访问
	printf("%d\n", strlen(&p));//随机值
	//p为指针 - &p对指针取地址 - 仍是地址 -此时是随机值,因为不知道p的地址的\0在哪
	printf("%d\n", strlen(&p + 1));//随机值
	//p的地址+1  - 随机值
	printf("%d\n", strlen(&p[0] + 1));//5
	//首元素取地址 +1 - 指向第二个元素b的地址 - 6-1=5

	return 0;
}

 五、二维数组

int main()
{
	//二维数组
	int a[3][4] = { 0 };

	printf("%d\n", sizeof(a));//48
	//整个数组的大小 - 3行*4列*4(int)=48
	printf("%d\n", sizeof(a[0][0]));//4
	//第一行第一列的元素 - 首元素 - int - 4

	printf("%d\n", sizeof(a[0]));//16
    //a[0]第一行数组名
    //第一行整个一维数组的大小4*4=16
	//二维数组第一行 - 第一个一维数组 的大小 - 4*4=16

	printf("%d\n", sizeof(a[0] + 1));//4/8
    //a[0]并没有单独放在sizeof里
    //此时表示首元素a[0][0],+1,a[0][1]
    //第一行第二个元素的地址,4/8

	printf("%d\n", sizeof(*(a[0] + 1)));//4
	//第一行第二个元素地址,解引用
    //元素int - 4

	printf("%d\n", sizeof(a + 1));//4/8
	//首元素地址 + 1 - 第一个一维数组地址 +1 - 第二个一维数组地址 -4/8

	printf("%d\n", sizeof(*(a + 1)));//16
	//第二个一维数组 -16

	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//首元素地址+1 - 第一个一维数组的地址 +1 -第二个一维数组的地址
	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	//第二个一维数组  - 16
	printf("%d\n", sizeof(*a));//16
	//首元素 - 第一个一维数组 - 4*4= 16
	printf("%d\n", sizeof(a[3]));//16
	//虽然不存在 arr[3],但是可以假设存在 - 第四个一维数组 - 16

	return 0;
}


六、指针笔试题

1.

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	//整个数组地址+1 - 跳过整个数组 -强制类型转换为int* 
	printf("%d,%d", *(a + 1), *(ptr - 1));//2,5
	//*(a+1) - *(首元素地址+1)- 2
	//指针ptr最开始移动到数组后面的第一个元素 ,此时指针类型还是数组指针
	//强制类型转换 - int* 
	//*(ptr - 1) - 往前移动一个整型 ,解引用 - 5
	return 0;
}

 2.

//2
//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	p = 0x100000;
	printf("%p\n", p + 0x1);//0x100014
	//0x1 - 十六进制的1 
	//p为指针 - 指针类型是结构体指针 - 那么移动1就是移动一个结构体的长度 - 这个结构体20字节
	// 结构体指针 + 1 = 步长为该结构体的大小: 20字节(014) 
	//0x100000 + 1 = 0x100014

	printf("%p\n", (unsigned long)p + 0x1);
	//p为指针 - 强制类型转换为unsigned long 这样的整型
	//此时 p = 0x100000 不是地址,而是具体的整型的数值了
	//0x100000 + 1 =0x100001

	printf("%p\n", (unsigned int*)p + 0x1);
	//p为结构体指针 - 强制类型转换为unsigned int* 整型指针
	// 整型指针+ 1 ,步长:4字节
	//0x100000 + 1 =0x100004
	return 0;
}

3.

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);//0x00000004 0x02000000
	//&a整个数组的地址+1,移动到数组最后一个元素后面的位置,数组指针
	//强制类型转换成int* 整形指针
	//ptr1[-1]可以理解为,*(ptr1-1),往前移动一个整型,解引用得到了4,
	//十六进制 0x00000004
	//%x 打印得到 4(前面的0x00000000省略了)

	//a为首元素地址,一个十六进制数,假设 0x 00 11 22 33
	//强制类型转换为整型,此时这个地址成为一个数值,+1,得到0x 00 11 22 34
	//此时再强制类型转换为 int* 此时变成指向这个 0x 00 11 22 34 地址的指针了
	// 如果为小端存储,地址由低到高,内存如下:
	// 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
	//相当于是首元素地址+1字节 ,指向了首元素01 后的第一个00
	//*ptr2 解引用这个地址,从这个地址开始往后取4字节得到 00 00 00 02
	//十六进制为 0x02000000
	//%x 打印得到 2000000(前面的0x0省略了)

	return 0;
}

 

4. 

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);//
	//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };逗号表达式
	//	int a[3][2] = { 1, 3, 5 };
	//p为首元素指针
	//打印p[0] => *(p+0) => 1
	return 0;
}

 

5.

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	//fffffffc,-4
	//画图理解:a[5][5],感叹号所示位置为两个符号相隔四个字节为 -4
	//|` _ _ _ `|_ _ _ ` _|_ _ ` _ _|_ ` _ ! _|_ _ ! _ _|
	//											   &a[4][2]
	// p[0]							        p[4][2]
	//-4 
	//10000000 00000000 00000000 00000100
	//11111111 11111111 11111111 11111011
	//11111111 11111111 11111111 11111100 - -4的补码
	//转换为十六机制 ff ff ff fc
	return 0;
}

 

6.

int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);
	int* ptr2 = (int*)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
	//1, 2, 3, 4, 5| 6, 7, 8, 9, 10
	//&aa+1,整个数组地址+1,跳过整个数组;转换为int*指针 - 1,得到10
	//1 2 3 4 5| 6 7 8 9 10
	//			arr+1(数组指针)
	//*(arr+1)得到整个数组,然后强制类型转换为int*,指向元素6
	//ptr2-1,往前移动一个整型,指针指向5
	return 0;
}

 

7.

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);//at
	//work at alibaba
	//pa指向a[0]w,pa++指向a
	//打印字符串得到at
	return 0;
}

8.

int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);//POINT
	
	printf("%s\n", *-- * ++cpp + 3);//ER
	
	printf("%s\n", *cpp[-2] + 3);//ST
	
	printf("%s\n", cpp[-1][-1] + 1);//EW
	return 0;
}