指针与数组练习题

文章详细探讨了C语言中数组和指针在sizeof运算符及strlen函数下的行为。通过各种例子解释了sizeof计算数组、指针及其偏移量的内存占用,以及strlen函数在有无终止符字符串中的应用。内容涉及整型数组、字符数组、字符串字面量和二维数组等场景。
摘要由CSDN通过智能技术生成

这篇文章是关于数组与指针的练习题,可以加深我们对指针与数组结合的理解

 int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16   sizeof表达式里面a,代表着整个数组,不在是首元素的地址,
printf("%d\n", sizeof(a + 0));//  4/8   由于a不是单独放在sizeof表达式里面,所以a+0代表首元素的地址
printf("%d\n", sizeof(*a));//4        *a等同于a[0] ,表示首元素,因此得出第一个元素的大小
printf("%d\n", sizeof(a + 1));// 4/8   由于a不是单独放在sizeof表达式里面,所以a+1代表2元素的地址
printf("%d\n", sizeof(a[0]));// 4 表示元素2的大小
printf("%d\n", sizeof(&a));//4/8  &a 这里的a代表整个数组,但取出的地址是首元素的地址
printf("%d\n", sizeof(*&a));//16  先取出整个数组的地址,然后对整个数组解引用,因此代表着整个数组
printf("%d\n", sizeof(&a + 1));// 4/8   &a代表整个数组,加1就跳过了整个数组但依然是地址
printf("%d\n", sizeof(&a[2]));// 4/8
printf("%d\n", sizeof(&a[0] + 1));//4/8 取出的是元素2的地址

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));// 6 arr表示整个数组
	printf("%d\n", sizeof(arr + 0));// 4/8  代表着数组首元素的地址
	printf("%d\n", sizeof(*arr));//1  *arr代表着数组首元素
	printf("%d\n", sizeof(arr[1]));//1  代表着元素b的大小
	printf("%d\n", sizeof(&arr));//  4/8   取出的是整个数组, 但地址是先从首元素开始的               printf  ("%d\n", sizeof(&arr + 1));//4/8   arr代表着整个数组,但是加1后跨过整个数组,所以取出的是最后一个元素之后的地址 
	printf("%d\n", sizeof(&arr[0] + 1));//4/8 ,取出的是元素b的地址

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//    strlen遇到'/0'才会停止读,但是这里没有'/0',所以是个随机值
	printf("%d\n", strlen(arr + 0));//依旧是随机值
	printf("%d\n", strlen(*arr));//strlen接收的是地址,出现错误
	printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr));//&arr取出的是整个数组,从首元素开始,但是没有'/0'  依旧是随机值
	printf("%d\n", strlen(&arr + 1));//&arr+1 跳过整个数组,但依旧是随机值
	printf("%d\n", strlen(&arr[0] + 1));//从元素b开始计数,但依旧是随机值



	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//7  注意'f'后面有一个'/0'
	printf("%d\n", sizeof(arr + 0));//4 计算的是arr[0]的大小
	printf("%d\n", sizeof(*arr));//1 计算的是arr[0]的大小
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//&arr  取出的是整个数组   但它依然是地址,所以是4/8
	printf("%d\n", sizeof(&arr + 1));//4/8   表达式表示跨过一整个数组
	printf("%d\n", sizeof(&arr[0] + 1));//4/8  表示元素b的地址



	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0));//6
	//printf("%d\n", strlen(*arr));//错误
	//printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr));//6    &arr 取出的是整个数组,但是它依旧是从首元素开始的,
	printf("%d\n", strlen(&arr + 1));//随机值   跨过真个数组,直到遇见/0
	printf("%d\n", strlen(&arr[0] + 1));//5




	char* p = "abcdef"; //p是个指针,指向的是首元素地址
	printf("%d\n", sizeof(p));//4/8 p是个指针,指向的是首元素地址
	printf("%d\n", sizeof(p + 1));//4/8 指向元素b的地址
	printf("%d\n", sizeof(*p));//1     元素a的大小
	printf("%d\n", sizeof(p[0]));//1  元素a的大小
	printf("%d\n", sizeof(&p));//4/8
	printf("%d\n", sizeof(&p + 1));// 4/8
	printf("%d\n", sizeof(&p[0] + 1));//  4/8





char* p = "abcdef"; //p是个指针,指向的是首元素地址
	printf("%d\n", strlen(p));//6,p指向首元素的地址,
	printf("%d\n", strlen(p + 1));//5 p+1指向的是b的地址,往后开始计数,一直到/0
	//printf("%d\n", strlen(*p));//错误
	//printf("%d\n", strlen(p[0]));//错误
	printf("%d\n", strlen(&p));//随机值  p是指针,不是数组名,&p,取出的是p本身的地址
	printf("%d\n", strlen(&p + 1));//随机值    跨国一个数组直到遇见新的'/0'
	printf("%d\n", strlen(&p[0] + 1));//5


	int a[3][4] = { 23 };

	printf("%d\n", sizeof(a));//48  二维数组的数组名表示数组首元素的地址,但是它单独放在sizeof里面,所以表示整个数组

	printf("%d\n", sizeof(a[0][0]));//4

	printf("%d\n", sizeof(a[0]));//16   a[0]表示第一行一维数组的数组名,但是sizeof的数组名表示整个数组
	printf("%d\n", sizeof(a[0] + 1));//4/8      表示第1行的第二个元素的地址

	printf("%d\n", sizeof(*(a[0] + 1)));//4    表示第1行第2个元素的大小

	printf("%d\n", sizeof(a + 1));//4/8,  表示的是第二行首元素的地址,(a+1)表示第二行的数组名

	printf("%d\n", sizeof(*(a + 1)));//16  表示第二行整个元素的地址

	printf("%d\n", sizeof(&a[0] + 1));//4/8表示第二行一维数组的地址

	printf("%d\n", sizeof(*(&a[0] + 1)));//16  解引用,解出来的是第二行整个一维数组的大小

	printf("%d\n", sizeof(*a));//16 是第一行所有元素的大小,a是数组名,
	//不是单独放在sizeof里面,所以表示的是第一行一维数组的数组名

	printf("%d\n", sizeof(a[3]));//16 sizeof是表达式,不会判断括号里的结果是否正确

笔试题

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)跨过去整个数组,来到5后面的一个地址,再减去1,正好指向5的地址
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//由于还没学习结构体,这里告知结构体的大小是20个字节

	//假设p 的值为0x100000。 如下表表达式的值分别为多少?
	//已知,结构体Test类型的变量大小是20个字节
	int main()
	{
		printf("%p\n", p + 0x1);
        
        //p是个struct Test* 型,大小为20字节,p+1相当于地址加上20,由于地址是由16进制表示,20的16进制0x000014,0x100000+0x000014=0x100014
		printf("%p\n", (unsigned long)p + 0x1);
        //此时p被强制转化为unsigned long   无符号长整型,可以直接加0x1  ,所以为000001
		printf("%p\n", (unsigned int*)p + 0x1);
        //此时p被强制转换为(int *),大小为4个字节,加1 ,相当于加4,0000004
		return 0;
	}




int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1);//(&a+1)本来是int(*)[4]类型,被强制转换成(int*),4后面那块未知的地址就赋值给了ptr1
//ptr[-1]相当于ptr-1,最终指向4
			int* ptr2 = (int*)((int)a + 1);//假设a数组首元素地址为0x11223300,此时被强制转为int,那么地址可以直接加1变为0x11223301,指针相当于往前走了1个字节,又因为再次被强制换为(int*) 需要访问4个字节,ptr2往后找四个字节一直到02,最终指向00 00 00 02,由于是小端存储,输出时变为200 00 00 
			printf("%x,%x", ptr1[-1], *ptr2);
			return 0;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7UWZiwxM-1689065763112)(C:\Users\22724\AppData\Roaming\Typora\typora-user-images\image-20230708184118739.png)]

#include <stdio.h>
int main()
{
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0;
    
}//本题看似是二维数组,其是逗号表达式,只要看最右边即可

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]);
 return 0;
}//由下面的简图可以看出两者相差4个元素也就是4个字节,两个地址相减得到的之间元素的个数,以字节为单位.所以第二个输出的为-4,%p是以16进制输出,所以-4的16进制   fffffffc
//补充:计算机中通常使用补码来表示负数。补码表示法将负数转换为其对应的补码形式,使得负数的加法、减法等运算可以与正数一起使用相同的规则进行计算,简化了计算机的逻辑设计和运算过程。因此,负数在计算机中常用补码表示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zIvn7CzG-1689065763112)(C:\Users\22724\AppData\Roaming\Typora\typora-user-images\image-20230708212313755.png)]


		
			int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
			int* ptr1 = (int*)(&aa + 1);//&aa表示整个二维数组,+1会跨过整个二维数组
			int* ptr2 = (int*)(*(aa + 1));//数组名aa表示第一行的整个一维数组,加1,相当于aa[1]
			printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
			return 0;
		
		
		

		char* a[] = { "work","at","alibaba" };//3个字符串,char* p1 ="work";char* p2 = 			"at";//指针数组的空间不是连续的,无法用二维数组表示,两者不一样的概念
		char** pa = a;//pa存放着p1的地址
		pa++;//指向了p2
		printf("%s \n",*pa);
		return 0;

char* c[] = { "ENTER","NEW","POINT","FIRST" };
		char** cp[] = { c + 3,c + 2,c + 1,c };//++ 的优先于*,*优先于+ ,-
		char*** cpp = cp;
		printf("%s\n", **++cpp);//cpp先自增变为cpp+1,再*(cpp+1)取出cp+1,再*(cp+1),取出c+2	==c[2]

printf("%s\n", *-- * ++cpp + 3);//此时的cpp指向cp+1,前置++,变为cp+2,*(c+1),取出c+1,然后--,变为c,再*,取出ENTER的首元素地址E,加3,地址变为E的地址

printf("%s\n", *cpp[-2] + 3);//先取出cp+3的内容c+3
//(表示的是FIRST的整个地址)
		printf("%s\n", cpp[-1][-1] + 1);
//*(*(cpp-1)-1)+1  首先cpp-1指向cp+2再*取出里面的内容
//c+1,c+1再-1变为c 再*表示第一个整个字符串元素  *c+1中*c的地址,加一就来到了N的位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Chl454DK-1689065763113)(C:\Users\22724\AppData\Roaming\Typora\typora-user-images\image-20230710090958015.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值