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

news/2024/10/29 1:21:31/

目录

  • 一维数组
    • 关于strlen函数和sizeof()的练习
      • 整型数组
      • 字符数组
      • 指针
  • 二维数组
  • 笔试题

前言:

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


话不多说,直接上题:

一维数组

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

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

有两种情况例外:

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

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

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

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

整型数组

练习一:

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

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

分析:

内存:

在这里插入图片描述

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

在这里插入图片描述


字符数组

练习二:

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr + 0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr + 1));printf("%d\n", sizeof(&arr[0] + 1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));printf("%d\n", strlen(*arr));printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));return 0;
}

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

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


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

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

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "abcdef";printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr + 0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr + 1));printf("%d\n", sizeof(&arr[0] + 1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));printf("%d\n", strlen(*arr));printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr + 1));printf("%d\n", strlen(&arr[0] + 1));return 0;
}

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

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

分析:

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


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

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


指针

练习三:

#include <stdio.h>
#include <string.h>
int main()
{char* p = "abcdef";printf("%d\n", sizeof(p));printf("%d\n", sizeof(p + 1));printf("%d\n", sizeof(*p));printf("%d\n", sizeof(p[0]));printf("%d\n", sizeof(&p));printf("%d\n", sizeof(&p + 1));printf("%d\n", sizeof(&p[0] + 1));printf("%d\n", strlen(p));printf("%d\n", strlen(p + 1));printf("%d\n", strlen(*p));printf("%d\n", strlen(p[0]));printf("%d\n", strlen(&p));printf("%d\n", strlen(&p + 1));printf("%d\n", strlen(&p[0] + 1));return 0;
}

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

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


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

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

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "abcdef";printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr + 0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr + 1));printf("%d\n", sizeof(&arr[0] + 1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));printf("%d\n", strlen(*arr));printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr + 1));printf("%d\n", strlen(&arr[0] + 1));return 0;
}

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

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

分析:

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

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


strlen的结果:

注意:strlen函数的参数类型

在这里插入图片描述

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

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


二维数组

练习四:

#include <stdio.h>
int main()
{int a[3][4] = { 0 };printf("%d\n", sizeof(a));printf("%d\n", sizeof(a[0][0]));printf("%d\n", sizeof(a[0]));printf("%d\n", sizeof(a[0] + 1));printf("%d\n", sizeof(*(a[0] + 1)));printf("%d\n", sizeof(a + 1));printf("%d\n", sizeof(*(a + 1)));printf("%d\n", sizeof(&a[0] + 1));printf("%d\n", sizeof(*(&a[0] + 1)));printf("%d\n", sizeof(*a));printf("%d\n", 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\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (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\n", &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\n", *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\n", **++cpp);printf("%s\n", *-- * ++cpp + 3);printf("%s\n", *cpp[-2] + 3);printf("%s\n", cpp[-1][-1] + 1);return 0;
}

结果:

在这里插入图片描述

分析:

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

在这里插入图片描述


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

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


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


http://www.ppmy.cn/news/57291.html

相关文章

Security方法注解权限控制过程及自定义权限表达式

文章目录 使用内置的权限表达式PreAuthorizePermissionEvaluator 自定义权限表达式SysMethodSecurityExpressionHandler源码流程 SysMethodSecurityExpressionRoot 使用内置的权限表达式 PreAuthorize 这个用来判断超级管理员的话&#xff0c;还得在表达式上加上或 Permissi…

STL容器类

STL 1. STL初识 1.1 迭代器 1.1.1 原生指针也是迭代器 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; void test01() {int arr[5] { 1,2,3,4,5 };int* p arr;for (int i 0; i < 5; i) {cout << arr[i] << endl;cout &…

【Java笔试强训 24】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;年终奖 …

【iOS】GCD学习

GCD的概念 GCD&#xff08;Grand Central Dispatch&#xff09;&#xff0c;是有Apple公司开发的一个多核编程的解决方案&#xff0c;用以优化应用程序支持多核处理器&#xff0c;是基于线程模式之上执行并发任务。 GCD的优点 利用设备多核进行并行运算GCD自动充分使用设备的…

​【五一创作】基于mysql关系型实现分布式锁

看完该文预计用时&#xff1a;15分钟 看之前应具体的技术栈&#xff1a;springboot mysql nginx&#xff08;了解即可&#xff09; 目录 0.写在前面 1. 从减库存聊起 1.1. 环境准备 1.2. 简单实现减库存 1.3. 演示超卖现象 1.4. jvm锁问题演示 1.4.2. 原理 1.5. 多服务问…

【51单片机】数码管显示(样例展示以及异常分析)

🎊专栏【51单片机】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 ⭐数码管 比如要显示“6”,那么下面图片中,AFEDCG=1,B=0 对应到数码管上,就是 ⭐原理 🎊P22~P24控制LED1~

transformer and DETR

RNN 很难并行化处理 Transformer 1、Input向量x1-x4分别乘上矩阵W得到embedding向量a1-a4。 2、向量a1-a4分别乘上Wq、Wk、Wv得到不同的qi、ki、vi&#xff08;i{1,2,3,4}&#xff09;。 3、使用q1对每个k&#xff08;ki&#xff09;做attention得到a1,i&#xff08;i{1,2,3,4…

FPGA时序约束(六)时序例外约束

系列文章目录 FPGA时序约束&#xff08;一&#xff09;基本概念入门及简单语法 FPGA时序约束&#xff08;二&#xff09;利用Quartus18对Altera进行时序约束 FPGA时序约束&#xff08;三&#xff09;时序约束基本路径的深入分析 FPGA时序约束&#xff08;四&#xff09;主时…