指针【进阶】

1、指针和数组笔试题

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

/*
	数组和指针
	数组 - 能够存放一组相同类型的元素,数组的大小取决于数组的元素个数和元素类型
	指针 - 地址/指针变量 ,大小是4/8个字节
	大部分情况下数组名是数组首元素的地址
	但是有2个例外:
	sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小
	&数组名 - 数组名表示整个数组,取出的是数组的地址
	strlen函数传递的是地址,能够计算\0前字符个数【int strlen ( const char * str );】
*/

int main()
{
	//整数数组
	int a1[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a1)); //16 【sizeof(a1)是数组名单独放在sizeof内部,计算的数组总大小,单位是字节】
	printf("%d\n", sizeof(a1 + 0)); //4/8 个字节 【a1+0 其实是数组首元素的地址】
	printf("%d\n", sizeof(*a1)); //4 【a1是数组首元素的地址, *a1 -> *&a1[0] -> a1[0]】
	printf("%d\n", sizeof(a1 + 1)); //4/8 【a1是数组首元素的地址是 int* 类型,a1+1 跳过1个整型, 是第二个元素的地址】
	printf("%d\n", sizeof(a1[1])); //4
	printf("%d\n", sizeof(&a1)); //4/8 【int (*pa)[4] = &a1;int(*)[4],整个数组的地址】
	printf("%d\n", sizeof(*&a1)); //16 【sizeof(a1)】
	printf("%d\n", sizeof(&a1 + 1)); //4/8 【&a1 是整个数组的地址,&a1+1 跳过一个数组】
	printf("%d\n", sizeof(&a1[0])); //4/8 【首元素的地址】
	printf("%d\n", sizeof(&a1[0] + 1)); //4/8 【第二个元素的地址】



	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr)); //随机值 【因为不知道\0的位置】
	printf("%d\n", strlen(arr + 0)); //随机值
	//printf("%d\n", strlen(*arr)); //非法访问 【'a'的ASCII值97被当成地址进行访问,非法】
	//printf("%d\n", strlen(arr[1])); //非法访问 【'b'的ASCII值98被当成地址,形参非法访问】
	printf("%d\n", strlen(&arr)); //随机值
	printf("%d\n", strlen(&arr + 1)); //随机值-6
	printf("%d\n", strlen(&arr[0] + 1)); //随机值-1

	printf("%d\n", sizeof(arr)); //6
	printf("%d\n", sizeof(arr + 0)); //4/8 【arr+0是数组首元素的地址】
	printf("%d\n", sizeof(*arr)); //1 【*arr是首元素的,计算的是首元素的大小】
	printf("%d\n", sizeof(arr[1])); //1
	printf("%d\n", sizeof(&arr)); //4/8 【&arr是数组的地址】
	printf("%d\n", sizeof(&arr + 1)); //4/8 【&arr + 1跳过一个数组后的地址】
	printf("%d\n", sizeof(&arr[0] + 1)); //4/8 【第二个元素的地址】



	//char arr[] = { 'a','b','c','d','e','f' };
	char arr2[] = "abcdef"; //【a b c d e f \0】
	printf("%d\n", strlen(arr2)); //6
	printf("%d\n", strlen(arr2 + 0)); //6
	//printf("%d\n", strlen(*arr2)); //err
	//printf("%d\n", strlen(arr2[1])); //err
	printf("%d\n", strlen(&arr2)); //6 【&arr2 存放类型为 char (*)[7]】
	printf("%d\n", strlen(&arr2 + 1)); //随机值
	printf("%d\n", strlen(&arr2[0] + 1)); //5

	printf("%d\n", sizeof(arr2)); //7
	printf("%d\n", sizeof(arr2 + 0)); //4/8
	printf("%d\n", sizeof(*arr2)); //1 【*arr2是数组首元素 = arr2[0] =  *(arr2+0)】
	//int sz = sizeof(arr2)/sizeof(*arr2);
	//int sz = sizeof(arr2)/sizeof(arr2[0]);
	printf("%d\n", sizeof(arr2[1])); //1
	printf("%d\n", sizeof(&arr2)); //4/8 【整个数组的地址,是地址就是4/8】
	printf("%d\n", sizeof(&arr2 + 1)); //4/8 【跳过一整个数组的地址】
	printf("%d\n", sizeof(&arr2[0] + 1)); //4/8 【b的地址】



	//指针变量存字符串
	char* p = "abcdef";
	printf("%d\n", strlen(p)); //6
	printf("%d\n", strlen(p + 1)); //5 【p+1是从'b'的地址开始】 
	//printf("%d\n", strlen(*p)); //err 【把'A'的ASCII码值当成地址了】
	//printf("%d\n", strlen(p[0])); //err
	printf("%d\n", strlen(&p)); //随机值 【取的是p变量的地址】
	printf("%d\n", strlen(&p + 1)); //随机值
	printf("%d\n", strlen(&p[0] + 1)); //5

	printf("%d\n", sizeof(p)); //4/8
	printf("%d\n", sizeof(p + 1)); //4/8 【'b'的地址】
	printf("%d\n", sizeof(*p)); //1
	printf("%d\n", sizeof(p[0])); //1 【*(p+0)--'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 【&p[0]+1是'b'的地址】



	//二维数组
	int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	printf("%d\n", sizeof(a)); //48 【a这个二维数组的数组名单独放在sizeof内部,计算整个数组的大小】
	printf("%d\n", sizeof(a[0][0])); //4 【第一行第一个元素,4个字节】
	printf("%d\n", sizeof(a[0])); //16 【a[0] 第一行的数组名,这时数组名单独放在sizeof内部了,计算的是数组第一行的大小,单位是字节】
	printf("%d\n", sizeof(a[0] + 1)); //4 【a[0]不是单独放在sizeof内部,a[0]表示的首元素的地址,即第一行第一个元素的地址即 &a[0][0],a[0] + 1 是第一行第2个元素的地址 &a[0][1]】
	printf("%d\n", sizeof(*(a[0] + 1))); //4 【a[0][1] 大小:4个字节】
	printf("%d\n", sizeof(a + 1)); //4/8 【a作为二维数组的数组名并非单独放在sizeof内部,所以表示首元素的地址,二维数组的首元素是第一行,这里的a就是第一行的地址类型为int (*)[4],a+1是跳过第一行,指向了第二行】
	printf("%d\n", sizeof(*(a + 1))); //16 【*(a+1)-->a[1],即第二行元素所占总字节数】
	printf("%d\n", sizeof(&a[0] + 1)); //4/8 【&a[0]是第一行的地址,&a[0]+1是第二行的地址】
	printf("%d\n", sizeof(*(&a[0] + 1))); //16 【a[1],访问的是第二行】
	printf("%d\n", sizeof(*a)); //16 【*a就是第一行,*a = *(a+0) = a[0]】
	printf("%d\n", sizeof(a[3])); //16 【访问的是第四行】
	printf("%d\n", sizeof(*a + 1)); //4/8 【a数组名代表代表二维数组的首元素地址,*a代表第一行元素a[0];a[0]又是第一行数组的数组名,代表第一行元素的首元素地址即&a[0][0];*a + 1则代表&a[0][1],还是地址】



	int b = 5;
	short s = 11;
	printf("%d\n", sizeof(s = b + 2)); //2 【sizeof并没有计算,直接根据short类型计算出2】
	printf("%d\n", s); //11 【s未进行计算,所以还是11】

	return 0;
}

2、指针笔试题

(1)练习1

#define _CRT_SECURE_NO_WARNINGS 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)); //【2,5】
	return 0;
}

在这里插入图片描述

(2)练习2

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}* p; 

int main()
{
	p = (struct Test*)0x100000; //假设p的值为0x100000
	printf("%p\n", p + 0x1); //00100014 【指针+1,跳过一个指针类型的字节,此处跳过一个结构体的大小,即+20】
	printf("%p\n", (unsigned long)p + 0x1); //00100001 【p的值强制转换为整型,+1为整型+1,即+1】
	printf("%p\n", (unsigned int*)p + 0x1); //00100004 【p的值强制转换为int*,+1为跳过一个整型,即+4】
	return 0;
}

(3)练习3

#define _CRT_SECURE_NO_WARNINGS 1
#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); //4,2000000
	return 0;
}

在这里插入图片描述

(4)练习4

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]); //1
	return 0;
}

在这里插入图片描述

(5)练习5

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

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]); //FFFFFFC,-4
	return 0;
}

在这里插入图片描述

(6)练习6

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

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
	return 0;
}

在这里插入图片描述

(7)练习7

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa); //at
	return 0;
}

在这里插入图片描述

(8)练习8

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

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

在这里插入图片描述

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值