c语言 指针的练习

文章详细分析了C语言中涉及指针和数组的各种操作,包括指针加减运算、数组地址转换、结构体指针的移动以及二维数组和字符指针数组的处理。通过多个代码示例和运行结果解析,阐述了指针在访问和操作数组时的行为和内存布局。
摘要由CSDN通过智能技术生成


一、

1.1代码:

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

1.2 分析和运行结果

分析:

  1. 将数组的地址取出来+1跳过一个数组的大小,所以ptr指针指向数组最后一个元素的下一个int类型的起始位置。ptr-1得到最后元素的地址。
  2. a是数组名,即没有单独放在sizeof中,也没有取地址,所以它代表数组首元素的地址。a+1得到第二个元素的地址,解引用就得到第二个元素。

运行结果:
在这里插入图片描述

二、

2.1代码:

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p的值位0x100000。表达式的值分别是多少?
//已知,结构体大小位20字节

int main()
{
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

2.2 分析和运行结果

分析:

  1. 这里考察的是指针+1跳过几个字节。
  2. 第一个printf里面,p指针指针的结构体是20个字节,那它+1就要跳过一个结构体的大小(20个字节)。加完1后就是:0x100014
  3. 第二个printf里面,p指针被强制转换成了(unsigned long)长整型。那转换后+1就是跳过一个字节。即:0x100001
  4. 第三个printf里面,结构体指针p被转换成了整型指针,整型指针+1就要跳过4个字节。即:0x100004

运行结果:
在这里插入图片描述

三、

3.1 代码

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

3.2 分析和运行结果

图解:
在这里插入图片描述
分析:

  1. 将数组的地址取出来+1跳过一个数组的大小,所以ptr1指针指向数组最后一个元素的下一个int类型的起始位置。ptr1[-1]又可以看成*(ptr-1)。这就是最后一个元素。
  2. 在第三行中a代表的是数组首元素的地址,将它强转为int,加一就跳过一个字节。所以ptr2就指向上图所示的位置。解引用ptr2就能访问ptr2指向的后四字节的内容。

运行结果:
在这里插入图片描述

四、

4.1 代码

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

4.2 分析和运行结果

分析:

  1. 逗号表达式的结果是最后一个元素的内容,即数组a其实只初始化前三个元素。1,3,5。
  2. 将数组首元素的地址(二维数组的地址是第一个一维数组的地址)赋给指针p。
  3. p[0] 等价于*(p+0),指针p的类型是整数指针类型的。所以访问一个整型。

运行结果:
在这里插入图片描述

五、

5.1 代码

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

5.2 分析和运行结果

图解:
在这里插入图片描述
分析:

  1. 数组a是一个二维数组,它的类型是int(*)[5]。而p的类型是int(*p)[4]。将数组a的地址赋给数组指针p。那么以指针p的视角来看数组a这个数组时,就如上图所示。
  2. 地址时由地到高的,指针减指针得到两个指针之间的元素个数。所以&p[4][2] - &a[4][2]就得到-4。
  3. %d打印就是-4
  4. %p打印就时-4的补码,即FFFFFFFC

运行结果:
在这里插入图片描述

六、

6.1 代码

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

6.2 分析和运行结果

分析:

  1. ptr1:&aa时取出的二维数组的地址,加1跳过二维数组的地址。
  2. ptr2:aa代表二维数组首元素的地址即第一个一维数组的地址。加1跳过第一个一维数组。

运行结果:
在这里插入图片描述

七、

7.1 代码

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

7.2 分析和运行结果

图解:
在这里插入图片描述
分析:

  1. a数组是字符指针数组,每个元素是字符指针,第一个指针存放的是work这个字符串的地址。第二个指针是存放day这个字符串的地址,第三个字符存放mind字符串的地址。
  2. pa是指向字符指针数组的指针,它加1是跳过一个字符指针。
  3. 将数组a的首元素地址赋值给pa,如上图所示。

运行结果:
在这里插入图片描述

八、

8.1 代码

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

	return 0;
}

8.2 分析和运行结果

图解:
在这里插入图片描述
运行结果:

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值