指针的进阶3—试题

本文详细讨论了C语言中指针与数组在使用sizeof和strlen时的不同情况,包括一维数组、字符数组、二维数组的特例分析,以及涉及指针的计算。特别强调了sizeof运算符计算的是对象的内存大小,而strlen函数则用于计算字符串的长度,两者在处理数组和指针时的区别和潜在问题。
摘要由CSDN通过智能技术生成

指针的进阶3—试题

1.一维数组

int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16
	//是第一种特殊情况,计算的是整个数组的大小  4*4 = 16  四个元素,每个元素的是int类型,大小为4字节
	printf("%d\n", sizeof(a + 0));//4/8
	//不是数组单独在sizeof内部,所以a代表的是数组首元素的地址,a+0代表的也是数组首元素的地址,地址就是4/8字节
	printf("%d\n", sizeof(*a));//4
	//不是特殊情况,所以a代表的是数组首元素的地址,对地址解引用得到的是首元素1,大小为4个字节
	printf("%d\n", sizeof(a + 1));//4/8
	//同第二种情况,代表的是第二个元素的地址,地址就是4/8字节
	printf("%d\n", sizeof(a[1]));//4
	//a[1]就是数组下标为1的元素->2,int类型,大小为4
	printf("%d\n", sizeof(&a));//4/8
	//是第二种特殊情况,取出的是整个数组的地址,地址就是4/8
	printf("%d\n", sizeof(*&a));//16
	//先取出整个数组的地址,然后对其进行解引用,得到的是整个数组,(大致可以理解为&和*相抵消)4*4 = 16
	printf("%d\n", sizeof(&a + 1));//4/8
	//&a取出的是整个数组的地址,+1跳过整个数组,产生的4后边位置的地址,地址就是4/8
	printf("%d\n", sizeof(&a[0]));//4/8
	//a先和[0]结合,取出的是数组第一个元素1,然后取出1的地址,地址就是4/8
	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//取出的是数组第二个元素的地址,地址就是4/8
}

总结:

数组名一般代表的是数组首元素的地址
但也有两种特殊情况:
1.sizeof(arr) 求的是整个数组的大小
2.&arr 取出的是整个数组的地址

2.字符数组

1.char arr[] = { 'a','b','c','d','e','f' };

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
	//求的是数组首元素地址的大小,地址就是4/8
	printf("%d\n", sizeof(*arr));//1
	//*arr得到的是数组首元素'a',类型为char,大小为1
	printf("%d\n", sizeof(arr[1]));//1
	arr[1]得到的是数组第二个元素'b',大小为1
	printf("%d\n", sizeof(&arr));//4/8
	//&arr得到的是整个数组的地址,地址大小为4/8
	printf("%d\n", sizeof(&arr + 1));//4/8
	//&arr取出的是整个数组的地址,+1跳过整个数组,产生的是'f'后边位置的地址,地址就是4/8
	printf("%d\n", sizeof(&arr[0] + 1));//4/8
	//&arr[0]取出的是数组第一个元素的地址,+1跳过一个char,就是数组第二个元素的地址,地址就是4/8

	printf("%d\n", strlen(arr));//随机值
	//arr代表的是数组首元素的地址,从该地址开始向后访问字符,统计\0之前出现的字符个数
	//但是arr只有六个字符,并没有'\0',所以继续向后找,但是不知道'\0'会出现在那,所以结果为随机值
	printf("%d\n", strlen(arr + 0));//随机值
	//arr+0也是数组首元素的地址,第一个情况一样,结果也为随机值
	printf("%d\n", strlen(*arr));//err
	//*arr得到的是数组第一个元素'a','a'的ASCII值为97,strlen会将97看成是地址去访问,
	//但是该地址不允许人访问
	printf("%d\n", strlen(arr[1]));//err
	//与上一种情况一样
	printf("%d\n", strlen(&arr));//随机值
	//&arr取出的是数组的地址,所以从数组第一个元素开始访问
	printf("%d\n", strlen(&arr + 1));//随机值
	//跳过该数组,从'f'后面的地址开始访问
	printf("%d\n", strlen(&arr[0] + 1));//suijiz
	//从数组第二个元素开始访问
}

总结:

sizeof是一个操作符
sizeof 计算的是对象所占内存的大小-单位是字节,size_t
不在乎内存中存放的是什么,只在乎内存大小

strlen 库函数
求字符串长度,从给定的地址向后访问字符,统计\0之前出现的字符个数
从例子中总结:strlen括号总放的必须是一个地址,要不然就会err

2.char arr[] = "abcdef";

int main()
{
	char arr[] = "abcdef";
	//[a b c d e f \0]
	printf("%d\n", sizeof(arr));//7
	//包括'\0',7*1 = 7
	printf("%d\n", sizeof(arr + 0));//4/8
	//arr+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
	//&arr整个数组的地址,地址大小4/8
	printf("%d\n", sizeof(&arr + 1));//4/8
	//'\0'后面的地址
	printf("%d\n", sizeof(&arr[0] + 1));//4/8
	//第二个元素的地址

	printf("%d\n", strlen(arr));//6
	//从数组首元素开始,直到读取到'\0',大小为6
	printf("%d\n", strlen(arr + 0));//6
	//也是从数组首元素开始
	printf("%d\n", strlen(*arr));//err
	//*arr得到的是数组第一个元素'a','a'的ASCII值为97,strlen会将97看成是地址去访问,
	//但是该地址不允许人访问
	printf("%d\n", strlen(arr[1]));//err
	//同上
	printf("%d\n", strlen(&arr));//6
	//从数组首元素开始,直到读取到'\0'
	printf("%d\n", strlen(&arr + 1));//随机值
	//&arr+1 跳过这个数组,从'\0'之后开始,直到读取到'\0'
	printf("%d\n", strlen(&arr[0] + 1));//5
	//从数组第二个元素开始,直到读取到'\0'
}

3.char* p = "abcdef";

int main()
{
	char* p = "abcdef";
	//让指针变量p指向a,p中存放a的地址
	printf("%d\n", sizeof(p));//4/8
	//p是一个指针变量,计算的是指针变量的大小,——>4/8
	printf("%d\n", sizeof(p + 1));//4/8
	// p+1是'b'的地址
	printf("%d\n", sizeof(*p));//1
	//*p,得到的是'a',大小为1
	printf("%d\n", sizeof(p[0]));//1
	//同上
	printf("%d\n", sizeof(&p));//4/8
	//p是个一级指针,&p就是取出p这个一级指针的地址
	printf("%d\n", sizeof(&p + 1));//4/8
	//&p+1是跳过p地址之后的地址
	printf("%d\n", sizeof(&p[0] + 1));//4/8
	//'b'的地址

	printf("%d\n", strlen(p));//6
	//从字符串a的地址开始,直到读取到'\0'
	printf("%d\n", strlen(p + 1));//5
	//从字符串b的地址开始,直到读取到'\0'
	printf("%d\n", strlen(*p));
	//err
	printf("%d\n", strlen(p[0]));
	//err
	printf("%d\n", strlen(&p));//随机值
	//从一级指针p的地址开始
	printf("%d\n", strlen(&p + 1));//随机值
	//从一级指针p的地址后面的地址开始
	printf("%d\n", strlen(&p[0] + 1));//5
	//从b的地址开始
}

2.二维数组

int main()
{
	int a[3][4] = { 0 };
	//arr数组3行4列
	printf("%d\n", sizeof(a));//48
	//计算的是整个数组的大小 3*4*4 = 48
	printf("%d\n", sizeof(a[0][0]));//4 
	//a[0][0]:0行0列的元素,大小为4
	printf("%d\n", sizeof(a[0]));//16
	//a[0]:第一行的地址,大小为4*4 = 16
	printf("%d\n", sizeof(a[0] + 1));//4/8
	//a[0]:不是单独挡在sizeof中,也没有被取地址,所以指的是第一行首元素的地址,a[0]+1:第一行第二个元素的地址
	printf("%d\n", sizeof(*(a[0] + 1)));//4
	//*(a[0]+1):第一行第二个元素 大小为4
	printf("%d\n", sizeof(a + 1));//4/8
	//a代表数组首元素的地址。在二维数组中就是第一行的地址,a+1:第二行的地址
	printf("%d\n", sizeof(*(a + 1)));//16
	//*(a+1):第二行的元素 4*4 = 16
	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//&a[0]:第一行的地址,&a[0]+1:第二行的地址
	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	//*(&a[0] + 1)):第二行的元素,大小为4*4 = 16
	printf("%d\n", sizeof(*a));//16
	//  a代表的是数组首元素的地址,在二维数组中指的是第一行的地址,*a得到第一行的元素,4*4 = 16
	printf("%d\n", sizeof(a[3]));//16
	//第4行大小
}

3.试题

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	//&a取出的是整个数组的地址,&a+1跳过这个数组之后的地址。
	// 本来只想数组的指针应该是 int(*p)[5] ,强转成int*类型
	//ptr指向的是5之后的地址
	printf("%d,%d", *(a + 1), *(ptr - 1));
	//*(a+1):第二个元素->2  *(ptr-1):ptr-1向后减去一个int的大小,然后 *(ptr - 1)得到的是5
	//   2     5
	return 0;
}
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	//要想表示3行2列的数组应该这样写 int a[3][2] = {{0,1},{2,3}{4,5}};
	//而题中表示的是一个逗号表达式,结果为 int a[3][2] = {1,3,5};
	int* p;
	p = a[0];
	//a[0]表示的是第一行第一个元素
	printf("%d", p[0]);
	//p[0]等价于*(p+0),表示的也是第一行第一个元素->1
	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;
}
//a[0]表示的是第一行第一个元素
printf("%d", p[0]);
//p[0]等价于*(p+0),表示的也是第一行第一个元素->1
return 0;

3.
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;
}

image-20230515001730430

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值