前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >抽丝剥茧C语言(高阶)指针进阶练习

抽丝剥茧C语言(高阶)指针进阶练习

作者头像
有礼貌的灰绅士
发布于 2023-03-28 07:33:08
发布于 2023-03-28 07:33:08
29900
代码可运行
举报
运行总次数:0
代码可运行

指针进阶的笔试题

导语

这里我会把我见过的笔试题都和大家分享一下,并且讲解。 本章用的是32位平台。

试题部分

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	char str1[] = "hello baiye.";
	char str2[] = "hello baiye.";
	const char* str3 = "hello baiye.";
	const char* str4 = "hello baiye.";
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");

	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");

	return 0;
}

代码运行结果是:

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//数组名单独放在sizeof中是计算整个数组的长度
	printf("%d\n", sizeof(a + 0));//数组名不是单独放在sizeof内,也就等于首元素地址,加0等于没动,算的是首元素地址的长度(64位平台就是8个字节)
	printf("%d\n", sizeof(*a));//同上不是单独放在内部,解引用之后算的是第一个元素的长度
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));//算的还是一个地址的长度,只要是地址,不是4就是8
	printf("%d\n", sizeof(*&a));//这个就等于取出数组的地址,然后又解引用等于是一个数组在sizeof的内部
	printf("%d\n", sizeof(&a + 1));//这个是跳过一数组,但要算的也是地址的长度
	printf("%d\n", sizeof(&a[0]));//取出的是数组下标为0元素的地址
	printf("%d\n", sizeof(&a[0] + 1));
	return 0;
}

代码运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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));//char类型的长度是一个字节
	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));//stelen是将你要计算的字符串的首地址传过去,因为读取到\0才会停止,这里我们是一个字符一个字符放进去的,所以是随机值
	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;
}

代码运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//sizeof会把末尾的\0也算上
	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));
}

代码运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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));

代码运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <string.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));//一维数组的数组名不是单独放在sizeof内部,所以算的是一维数组的第二个元素地址的长度
	printf("%d\n", sizeof(*(a[0] + 1)));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(*(a + 1)));//这个虽然是跳过一个二维数组之后才解引用,但是sizeof不会看里面有什么元素,所以数组越界了也没事,因为它已经知道了里面有4的整形元素
	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.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	printf("%p\n", p + 0x1);//这里加的是结构体类型的指针大小20,但是因为要转换为16进制所以是加14
	printf("%p\n", (unsigned long)p + 0x1);//将地址强制类型转换为十进制然后加1之后再转为十六进制(这次算的就是整形的加法了)
	printf("%p\n", (unsigned int*)p + 0x1);//这里是转换为整形指针,加1等于跳过一个整形的长度也就等于加4
	return 0;
}

代码结果:

2.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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; 
}

大家想必对ptr2非常的疑惑; 因为数组名(首元素地址)被强制类型转换为int,也就是变成了整数之后加一,也就等于我们原来的地址跳过了一个字节。 我的计算机是小端储存方式

因为是倒着存进去(高位放到高地址,低位放到低地址),那么也要把00 00 00 02倒着拿出来,所以就有了上面的结果。 3.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

运行结果:

4.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

运行结果如下:

指针相减算的是中间元素的个数。

p[4][2]可以看成(*(*p+4)+2) 第二个结果因为是低地址减高地址,所以是-4 第一个结果是因为用%p打印,所以把-4的补码给换算成了16进制,就变成了FFFFFFC 5.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;//指向了a的地址
	pa++;
	printf("%s\n", *pa);
	return 0;
}

运行结果:

6.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

运行结果:

这道题一开始是这个样子的

charc储存的是各个字符串的首字母地址,char**cp指向的是charc的地址,char*cpp指向的是charcp的地址。 第一个,因为++cpp所以移动到了这里

两次解引用之后就得到了POINT。 第二个又要++cpp再解引用,然后又要减减再解引用,最后再加三

我们发现,cp中的第三个元素从c+1变成了c,因为是- -运算符和++一样有永久性,不像c+1-1没有赋值给自己一样。至于为什么红色箭头指向了E,是因为后面的加三让指向这个字符串的首字母向后移动了三个字符的距离。 第三个找的是cp中的-2位置,因为前两个++导致我们找到了c+3那个位置(蓝色箭头表示)

注意,这次的cpp是临时移动而已,找到cpp[-2]的位置之后会回到原位。后面解引用之后又加了一个3就是同上,打印的就是ST。 最后第四个也就容易理解了,先找到cpp[-1]的位置,然后找到了c+2,c+2指向的位置是POINT这个字符串,因为又要找cp[-1]的位置所以又到了NEW的位置,又因为最后的+1所以变成了EW。

总结

1.数组名的意义:

sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。 &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。 除此之外所有的数组名都表示首元素的地址。

2.cpp[-2][1]这样的代码可以转换为(*(*cpp-2)+1)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
PySide——Python图形化界面入门教程(二)
PySide——Python图形化界面入门教程(二)   ——交互Widget和布局容器                ——Interactive Widgets and Layout Containers 翻译自:http://pythoncentral.io/pyside-pyqt-tutorial-interactive-widgets-and-layout-containers/ 上一个教程中,我们了解了一些QWidget提供的功能,还有一个特殊的子类QLabel。更进一步的,我们完成了一个用来说
ascii0x03
2018/04/12
2.7K0
PySide——Python图形化界面入门教程(二)
PySide6 GUI 编程(3):信号槽机制
信号的重载在 PySide6 中并不推荐使用,对于从 QT5 遗留的代码可以继续使用这一能力。
bowenerchen
2024/05/19
6291
PySide6 GUI 编程(3):信号槽机制
PySide6 GUI 编程(4):使用 Slot 装饰器定义槽函数
bowenerchen
2024/05/20
5891
PySide6 GUI 编程(4):使用 Slot 装饰器定义槽函数
基于PySide6的GUI程序开发全流程(看完就会)
GUI程序的开发方式太多了,这里肯定就是Python语言了,至于为什么,就不多描述了;
MinChess
2023/09/29
14.5K0
基于PySide6的GUI程序开发全流程(看完就会)
PySide6 GUI 编程(38):信号拦截与 lambda 槽函数
在之前的文章:PySide6 GUI 编程(3):信号槽机制中已经探讨过关于自定义信号的场景。在一些更追求灵活性的场景下,我们需要自定义信号,以此触发更多自定义的行为。
bowenerchen
2024/08/31
9770
PySide6 GUI 编程(38):信号拦截与 lambda 槽函数
PySide——Python图形化界面入门教程(六)
PySide——Python图形化界面入门教程(六)             ——QListView和QStandardItemModel 翻译自:http://pythoncentral.io/pyside-pyqt-tutorial-qlistview-and-qstandarditemmodel/ 上一个教程中,我们讨论了Qt的QListWidget类,它用来实现简单的单列列表框(list boxes)。然而,我们还需要更加灵活的widget来实现列表,Qt为此提供了QListView 来实现多种多样
ascii0x03
2018/04/12
2.2K0
PySide——Python图形化界面入门教程(六)
事件与信号
所有的应用都是事件驱动的。事件大部分都是由用户的行为产生的,当然也有其他的事件产生方式,比如网络的连接,窗口管理器或者定时器等。调用应用的exec_()方法时,应用会进入主循环,主循环会监听和分发事件。
小飞侠xp
2018/12/24
1.3K0
PySide6 GUI 编程(6):QPushButton的使用
bowenerchen
2024/07/20
4662
PySide6 GUI 编程(6):QPushButton的使用
【Python篇】PyQt5 超详细教程——由入门到精通(序篇)
PyQt5 是 Python 的图形用户界面 (GUI) 框架,它基于强大的 Qt 库。Qt 是一个跨平台的 C++ 框架,用于构建桌面应用程序。通过 PyQt5,我们可以用 Python 轻松构建跨平台的桌面应用程序,支持 Windows、macOS 和 Linux。
半截诗
2024/10/09
21.6K0
【Python篇】PyQt5 超详细教程——由入门到精通(序篇)
PySide——Python图形化界面入门教程(五)
PySide——Python图形化界面入门教程(五)               ——QListWidget 翻译自:http://pythoncentral.io/pyside-pyqt-tutorial-the-qlistwidget/ Qt具有简洁和方便的几个部件,用来作单列表选择,我们称之为列表框。最灵活的方法是使用一个是Qlistview,它提供了一个必须由程序员定义UI视图、高度灵活的列表模式;一个简单的方法是使用QListWidget,它具有一个预先定义的基于项目的模型,用来处理常见的列表框。
ascii0x03
2018/04/12
1.9K0
PySide——Python图形化界面入门教程(五)
PyQt5 基本窗口控件(状态栏/窗口/图标/提示消息/QLabel/文本类控件)
文章目录 1. 状态栏 2. 窗口居中显示 3. 关闭窗口 4. QWidget 5. 添加图标 6. 气泡提示信息 7. QLabel 添加快捷键 8. QLineEdit echoMode 验证器 inputMask 综合练习 9. QTextEdit learn from 《PyQt5 快速开发与实战》 1. 状态栏 self.statusbar.showMessage("hello, Michael", 2000),第二个参数是显示多长时间ms,默认无限长时间 # -*- coding: utf-8
Michael阿明
2022/05/10
2.6K0
PyQt5 基本窗口控件(状态栏/窗口/图标/提示消息/QLabel/文本类控件)
Python Qt GUI设计:窗口之间数据传递(拓展篇—5)
在开发程序时,如果这个程序只有一个窗口,则应该关心这个窗口里面的各个控件之间是如何传递数据的。如果这个程序有多个窗口,那么还应该关心不同的窗口之间是如何传递数据的。
不脱发的程序猿
2021/12/08
3.4K0
Python Qt GUI设计:窗口之间数据传递(拓展篇—5)
PySide——Python图形化界面入门教程(一)
PySide——Python图形化界面入门教程(一) ——基本部件和HelloWorld 翻译自:http://pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/ 本教程第一部分将给出PySide的最基本知识点,包含使用的对象,和一些能帮助你了解Python/Qt应用是如何构建的小例子。 首先来看一下基本的Qt对象。Qt包含了许多类去处理XML、多媒体、数据库和网络等等事物,但我们现在重点关注可视化的元素——窗口、对话框和
ascii0x03
2018/04/12
2.5K0
PySide6 GUI 编程(31):多个 QWidget 窗口展示
进程在刚启动时会初始化出两个窗口,这可以证明 init_new_window() 返回的对象是可以正常展示的
bowenerchen
2024/08/21
6133
PySide6 GUI 编程(31):多个 QWidget 窗口展示
PyQt十讲 | 浅谈信号与槽
信号与槽机制作为Qt最重要的特性,提供了任意两个Qt对象之间的通信机制。信号会在某个特定情况或动作下被触发,槽是用于接收并处理信号的函数。
潘永斌
2019/10/08
1.4K0
PyQt十讲 | 浅谈信号与槽
PySide6 GUI 编程(46): 基于QThread构造常驻后台的线程
在 PySide6 中,QRunnable 和 QThread 都可以用来在后台执行任务,但它们的使用场景和设计目的有所不同。
bowenerchen
2024/09/17
5040
PySide6 GUI 编程(46): 基于QThread构造常驻后台的线程
Python:PyQt学习
上面的代码把控件对应的变量名全部作为全局变量。如果要设计稍微复杂一些的程序,就会出现太多的控件对应的变量名。而且这样也不利于代码的模块化。所以,我们通常应该把 一个窗口和其包含的控件,对应的代码全部封装到类中,如下所示:
小简
2023/01/04
10.8K0
Python:PyQt学习
用PyQt5做图形界面(一)Hello world
PyQt是Python版本的Qt库,是最常用的跨平台图形界面编程框架之一。代码不用修改,就能同时运行在windows、linux、ios、andriod等平台。因此,对芯片设计行业来说,既可以用来开发大型EDA工具(通常用Qt的C++库),也可以用来开发公司内部的flow工具,还可以用作应用工程师的测试工具。所以,今天,以Linux平台为例,来介绍一下Python Qt的基本用法。
ExASIC
2023/02/17
1.6K0
用PyQt5做图形界面(一)Hello world
PySide——Python图形化界面入门教程(四)
PySide——Python图形化界面入门教程(四)               ——创建自己的信号槽               ——Creating Your Own Signals and Slots 翻译自:http://pythoncentral.io/pysidepyqt-tutorial-creating-your-own-signals-and-slots/ 你不必局限于Qt widget提供的信号,你可以使用Signal类来创建自己的信号。下面是一个定义的简单例子: 1 from PyS
ascii0x03
2018/04/12
1.2K0
Qt Theme 纯 qss 的 Qt 主题
源码地址:https://github.com/hubenchang0515/QtTheme/
用户2270320
2025/03/11
2370
Qt Theme 纯 qss 的 Qt 主题
推荐阅读
相关推荐
PySide——Python图形化界面入门教程(二)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档