您现在的位置是:首页 >其他 >C语言:指针【进阶】习题练习及分析讲解网站首页其他

C语言:指针【进阶】习题练习及分析讲解

ks胤墨 2023-07-09 20:00:02
简介C语言:指针【进阶】习题练习及分析讲解


前言:

前面我们刚刚学完了C语言:指针详解【进阶】的知识,这部分的知识还是要重在理解加实践,今天我这里就分享一些有关C语言指针方面的练习供大家更深入的理解指针的知识。
我们初期的指针学习大部分都是与数组的知识绑定在一起的,所以今天的练习也是大多与数组有关的,目的是透过数组中指针的操作帮助强化理解指针在内存中的是如何操作的。


话不多说,直接上题:

一维数组

关于数组对于sizeof()和strlen函数的使用,这里先回顾一下:

数组名大部分情况下代表数组的首元素的地址

有两种情况例外:

  1. 数组名单独放在sizeof内部,这里数组名代表整个数组计算的是整个数组的大小
  2. &数组名,这里取出的是整个数组的地址

sizeof()计算的是数据在内存中所占的字节大小
strlen函数只能计算字符串的长度,计算过程中遇到结束

关于strlen函数和sizeof()的练习

下面程序输出结果是什么?

整型数组

练习一:

#include <stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d
", sizeof(a));
	printf("%d
", sizeof(a + 0));
	printf("%d
", sizeof(*a));
	printf("%d
", sizeof(a + 1));
	printf("%d
", sizeof(a[1]));
	printf("%d
", sizeof(&a));
	printf("%d
", sizeof(*&a));
	printf("%d
", sizeof(&a + 1));
	printf("%d
", sizeof(&a[0]));
	printf("%d
", sizeof(&a[0] + 1));
	return 0;
}

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

分析:

内存:

在这里插入图片描述

对应题查看对应颜色的解释哦。

在这里插入图片描述


字符数组

练习二:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d
", sizeof(arr));
	printf("%d
", sizeof(arr + 0));
	printf("%d
", sizeof(*arr));
	printf("%d
", sizeof(arr[1]));
	printf("%d
", sizeof(&arr));
	printf("%d
", sizeof(&arr + 1));
	printf("%d
", sizeof(&arr[0] + 1));

	printf("%d
", strlen(arr));
	printf("%d
", strlen(arr + 0));
	printf("%d
", strlen(*arr));
	printf("%d
", strlen(arr[1]));
	printf("%d
", strlen(&arr));
	return 0;
}

这里分两部分练习(sizeof的为一部分,strlen的为一部分)
sizeof的结果:
在这里插入图片描述
分析:

内存:
在这里插入图片描述
在这里插入图片描述


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

分析:
在这里插入图片描述
练习三:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "abcdef";

	printf("%d
", sizeof(arr));
	printf("%d
", sizeof(arr + 0));
	printf("%d
", sizeof(*arr));
	printf("%d
", sizeof(arr[1]));
	printf("%d
", sizeof(&arr));
	printf("%d
", sizeof(&arr + 1));
	printf("%d
", sizeof(&arr[0] + 1));

	printf("%d
", strlen(arr));
	printf("%d
", strlen(arr + 0));
	printf("%d
", strlen(*arr));
	printf("%d
", strlen(arr[1]));
	printf("%d
", strlen(&arr));
	printf("%d
", strlen(&arr + 1));
	printf("%d
", strlen(&arr[0] + 1));
	return 0;
}

注意这里的字符数组在内存中的存储形式

这里分两部分练习(sizeof的为一部分,strlen的为一部分)
sizeof的结果:
在这里插入图片描述

分析:

内存:注意这个数组后面还放了'',''也要占一个字节
在这里插入图片描述
在这里插入图片描述


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

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


指针

练习三:

#include <stdio.h>
#include <string.h>
int main()
{
	char* p = "abcdef";

	printf("%d
", sizeof(p));
	printf("%d
", sizeof(p + 1));
	printf("%d
", sizeof(*p));
	printf("%d
", sizeof(p[0]));
	printf("%d
", sizeof(&p));
	printf("%d
", sizeof(&p + 1));
	printf("%d
", sizeof(&p[0] + 1));
	
	printf("%d
", strlen(p));
	printf("%d
", strlen(p + 1));
	printf("%d
", strlen(*p));
	printf("%d
", strlen(p[0]));
	printf("%d
", strlen(&p));
	printf("%d
", strlen(&p + 1));
	printf("%d
", strlen(&p[0] + 1));
	return 0;
}

这里分两部分练习(sizeof的为一部分,strlen的为一部分)
sizeof的结果:
在这里插入图片描述
分析:

内存:
在这里插入图片描述
在这里插入图片描述


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

分析:
在这里插入图片描述
练习三:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "abcdef";

	printf("%d
", sizeof(arr));
	printf("%d
", sizeof(arr + 0));
	printf("%d
", sizeof(*arr));
	printf("%d
", sizeof(arr[1]));
	printf("%d
", sizeof(&arr));
	printf("%d
", sizeof(&arr + 1));
	printf("%d
", sizeof(&arr[0] + 1));

	printf("%d
", strlen(arr));
	printf("%d
", strlen(arr + 0));
	printf("%d
", strlen(*arr));
	printf("%d
", strlen(arr[1]));
	printf("%d
", strlen(&arr));
	printf("%d
", strlen(&arr + 1));
	printf("%d
", strlen(&arr[0] + 1));
	return 0;
}

注意这里的字符串在内存中的存储形式

这里分两部分练习(sizeof的为一部分,strlen的为一部分)
sizeof的结果:
在这里插入图片描述

分析:

内存:注意这个字符串后面还放了'',''也要占一个字节

在这里插入图片描述
在这里插入图片描述


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

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

传入的是二级指针时指向的就是指针p的地址,strlen计算的就是从p的地址开始向后计算遇到时的长度。


二维数组

练习四:

#include <stdio.h>
int main()
{
	int a[3][4] = { 0 };

	printf("%d
", sizeof(a));
	printf("%d
", sizeof(a[0][0]));
	printf("%d
", sizeof(a[0]));
	printf("%d
", sizeof(a[0] + 1));
	printf("%d
", sizeof(*(a[0] + 1)));
	printf("%d
", sizeof(a + 1));
	printf("%d
", sizeof(*(a + 1)));
	printf("%d
", sizeof(&a[0] + 1));
	printf("%d
", sizeof(*(&a[0] + 1)));
	printf("%d
", sizeof(*a));
	printf("%d
", sizeof(a[3]));
	return 0;
}

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

分析:
该二维数组在内存中是三个一维数组连续存放的。

内存:

在这里插入图片描述

在这里插入图片描述


笔试题

通过上面的练习,相信你应该已经能理解指针在内存中的操作了,下面是几道笔试题,一起来检验一下学习成果吧。


笔试题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));
	return 0;
}
//程序的结果是什么?

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

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


笔试题2:

//由于还没深入学习结构体,这里告知结构体Test类型的大小是20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
#include <stdio.h>
int main()
{
	p = 0x100000;
	printf("%p
", p + 0x1);
	printf("%p
", (unsigned long)p + 0x1);
	printf("%p
", (unsigned int*)p + 0x1);
	return 0;
}

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

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

在这里插入图片描述


笔试题3:

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

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

分析:

%x :打印16进制的数字
注意:这里需要画更细致的内存分布图才能分析清指针的操作
(默认小端存储)

在这里插入图片描述
在这里插入图片描述


笔试题4:

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

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

分析:
这道题其实考的是大家对操作符的了解,对于一个二维数组来说,要在二维数组内初始化,需要用到的是{},而不是(),这里的()是逗号表达式的操作符。

( , , ):逗号表达式是以此执行括号内的语句,但只有最后一句的表达式是整个逗号表达式的值。

所以,这里的二维数组中只初始化了前三个元素1,2,3,后面的元素都为0a[0]代表第一行的地址,p[0]就是第一行第一个元素1


笔试题5:

#include <stdio.h>
int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d
", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

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

分析:

这里要注意不同类型的指针一次能访问到的空间是不同的
注意:地址是16进制数字

在这里插入图片描述


笔试题6:

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

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

分析:

在这里插入图片描述


笔试题7:

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s
", *pa);
	return 0;
}

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

分析:

在这里插入图片描述


笔试题8:

#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
", **++cpp);
	printf("%s
", *-- * ++cpp + 3);
	printf("%s
", *cpp[-2] + 3);
	printf("%s
", cpp[-1][-1] + 1);
	return 0;
}

结果:

在这里插入图片描述

分析:

这里必须把内存布局画出来,才能清晰的观察指针的动向。
注意:cpp进行++--操作后,指针的指向是要发生变化的。

在这里插入图片描述


本篇有关C语言指针进阶的练习就到此结束了,希望你能从中学习到在面对指针问题时,尽量画出指针的内存操作图,进而解题的思路
重点说三遍:
画图!
画图!!
还是画图!!!
如果你还有什么问题可以评论区讨论或私信我哦。😘

下一篇文章将会对前面C语言指针【进阶】中的qsort函数的模拟实现写一篇博客,保证简单易懂,看完就会。
再往后我们会对字符串的研究进行深入了解,并讲解一系列关键的字符串函数和内存函数,和它们的模拟实现。


感兴趣的的小伙伴点点赞,点点关注,谢谢大家的阅读哦!!!
点点关注,后期不错过哦。😘
你们的鼓励就是我的动力,欢迎下次继续阅读!!!😘😘😘

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。