IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 第一站:初识C语言(终幕)你真的理解指针了吗? -> 正文阅读

[C++知识库]第一站:初识C语言(终幕)你真的理解指针了吗?

目录

十三、指针

1.内存

2.指针变量的大小

十四、结构体

总结

?


十三、指针

1.内存

要理解指针,我们首先要理解内存,那什么是内存呢?内存是计算机上的一种存储空间,我们的电脑中常见的由8G/16G内存,程序在运行的时候会载入内存,程序如果有数据需要存储也会申请内存空间。那么如何有效的使用内存呢?

在生活中,我们有很多的空间,很多的楼,为了方便我们使用这些空间,我们会对其进行编号,比如西安邮电大学长思四101,102,103等等。这就是一种一个门牌号对应一个房间的关系,有了这些门牌号,我们可以很方便的找到对应的空间。

而我们计算机也是采用了这一种方式,我们假设内存是一个大长方形,然后我们对其进行等分,如下图所示(笔者画图水平不高,还望包涵)

?然后我们将每一个小格子称作内存单元,我们可以对每一个内存单元进行编号,如下图所示,这样未来在我们可以通过编号很快的找到我们的每一个内存单元

中间的每一个格子叫做内存单元,实践中,每一个内存单元的大小是一个字节,我们将右边的称作内存单元编号

?

?由于在现实生活中我们将西安邮电大学a栋教学楼a101也叫做地址,通过这些地址可以找到所需要的空间,事实上我们也将内存单元编号称作地址,而在c语言中我们也将地址叫做指针。

?那我们又有了一个新问题,如果访问一个内存单元,那内存单元的地址(指针)该如何产生呢?

我们的电脑机器常见的就是32位,64位(这里的位指的是比特位)。当然,现在主流的都是64位机器,但是我们为了能形象一点,我们这里以32位机器为例子

我们的32位机器,有32根地址线,就是我们物理中的哪些电线,地址线如果通电,那我们就会有电信号,就会有高电平,低电平。转换成数字信号就是1和0(如果大家想了解数字逻辑电路,数字信号等相关知识的话,可以在评论区留言,有时间可以出一些博客来讲解一下这些内容),也就是我们的二进制0和1。

那如果32根地址线全部通电呢?这样就会产生32位二进制序列,如下图所示,而这些二进制序列恰好对应于上面的每一个内存编号,因为二进制与上面的十进制的内存编号是可以互相转换的,这在进制转换这篇外传中已经详细讲过了。

?因此,我们将这些二进制序列与内存编号一一对应得到如下

?这样的话,每一个由32根地址线决定的二进制序列就可以管理我们的内存,而这些二进制序列就称作我们这每一个内存单元的地址。

而且我们这32根地址线最多产生,2的32次方个地址,每一个地址对应一个内存单元,而每一个内存单元是一个字节的大小,也就是说,最多可以管理2的32次方个字节的内存大小。

2的32次方字节内存大小我们换算一下

1KB=2的10次方字节

1MB=2的十次方KB

1GB=2的十次方MB

因此2的32次方字节等于4GB

也就是说32位机器最多拥有4GB内存,这也就是为什么我们以前最常见到的内存是4GB的一个原因。这是由于硬件所决定的最大内存

而我们现在随着硬件设施的发展,现在已经拥有64位机器,这样我们最多可以控制4*2的32次方个GB,这已经是相当大了。当然我们日常中最常见到的就是8GB/16GB了

经过上面的讲解,相信大家已经较为深刻的理解内存了,内存单元编号就是我们的地址也就是c语言中的指针。通过内存单元编号,也就是指针可以去找到我们这个内存里的数据。这叫做访问,通过一个指针去访问。

我们看下面一段代码

#include<stdio.h>
int main()
{
	int a = 5;//向内存申请四个字节的空间
	printf("%d", sizeof(a));
	return 0;
}

?不难得知结果是4,也就是a向内存申请了四个字节的空间,如下图所示,假设橙色区域即为a所申请的四个字节空间。

?在这里我们有个习惯,因为使用32个二进制位(也就是比特位)表示内存单元的编号,太过于冗杂,由于四位二进制数等于一位十六进制数,于是我们采用十六进制数来表示内存,这样我们就只需要八个数字即可清晰的表示出地址,也就是我们c语言中的指针。

这里有一点需要注意,我们c语言中的十六进制数需要加上前缀0x,八进制数加上前缀0。

我们打印一下a的地址

这段代码需要注意的是,&a的意思是取出a的地址,%p是打印地址的意思。可以跟%d是打印整型类比。

#include<stdio.h>
int main()
{
	int a = 5;//向内存申请四个字节的空间
	printf("%p", &a);
	return 0;
}

运行后,我们会发现,只打印出来了一个地址,可是,我们的a占了四个字节啊,也就是四个内存单元,应该占据了四个地址,那我们这个地址是这四个地址中的哪一个呢?

?

注:有的人打印出来的地址和我这个不太一样,他们的不只是8个十六进制数,而是16个十六进制数,这其实是因为你们的编译器目前是64位环境下,而我的编译器是32位环境。下面给出如何将编译器切换成32位环境下的方法。

?我们的visual stido环境下,那里有一个x86和x64的选项,其中x64是64位环境,x86是32位环境,想要切换环境,直接选择即可。而且当你运行完毕以后你可能会发现,每次打印出来的a的地址都不一样,这是正常的,每次编译后,编译器都会重新为其分配地址。

想要直到到底占用了哪一个地址,我们调试打开内存窗口,按住crtl +fn+f10(有的电脑直接ctrl+f10),然后点击调试,点击窗口,点击内存,内存1,2,3,4随便选择一个即可。

我们选择内存1,先将下面改成4

?变成如图所示

这是a的地址,0x0093FCE8,当然这个显示是四个字节中a的地址,但是我们此时已经得知a的地址了。

然后我们将列改为1

?我们发现有四个地址,其中最小的那个地址刚好就是a的地址

于是我们得出结论,a的地址为它所占的几个内存单元中最小的地址,也就是第一个字节的地址,这是一个很重要的结论。

用图片来表示即为

?a的地址为对应内存单元最小的一个,也就是第一个字节的地址

那么现在我们讲了这么多的内容,那么指针怎么用呢?先阅读下面一段代码,我们来讲解一下

#include<stdio.h>
int main()
{
	int a = 5;//向内存申请四个字节的空间
	int* pa = &a;
	printf("%p", pa);
	printf("%p", &a);
	return 0;
}

??????? 这段代码中,我们创建了a,并申请了四个字节的空间,然后我们使用一个变量pa来存放a的地址,这个变量pa就叫做指针,pa因为也是一个变量,所以我们习惯上叫它为指针变量。pa前面的那颗*表示pa是一个指针,而前面的int代表着pa这个指针(地址)指向的是一个int类型,所以合起来pa的类型我们称作int*,也就是所谓的指针类型。

?这段代码运行结果为上图所示,也就是说&a,和pa其实是一回事。

那么我们使用指针变量可不仅仅只是记录一下a的地址什么的,我们是需要通过这个地址来改变它里面的数据。这才是指针的用处。

#include<stdio.h>
int main()
{
	int a = 5;//向内存申请四个字节的空间
	int* pa = &a;
	*pa = 20;
	printf("%d\n",a);
	return 0;
}

如图所示,这个*pa中,*的意思是解引用,也就是说这个操作可以使我们通过pa这个地址找到a的值。然后我们对其赋值,从而篡改了a的值,此时a的值已经变成了20

2.指针变量的大小

我们运行一下下面这段代码

#include<stdio.h>
int main()
{
	int* a;
	char* b;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(b));
	return 0;
}

32位机器下结果应该是两个4,64位机器结果是两个8

可见指针变量的大小与其所指向类型无关,只与机器是多少位有关系。

为什么会产生这种情况?

因为指针变量存放的是一些比特位

32位环境下,一共有32个比特位,也就是4个字节。

64位环境下,一共有64个比特位,也就是8个字节

十四、结构体

在c语言中我们已经见过许多的类型了,有int,char,short,long,long long ,double ,float等等这些都是c语言中的内置类型。除此之外,我们c语言中还有一种类型是自定义类型,自定义类型分为三种,结构体,联合体,枚举。这三种类型之中,我们已经初步了解过枚举类型了,那么我们现在来了解一下结构体。

当我们在描述一个人的时候需要描述它的身高,体重,姓名性别,年龄等等。当我们需要了解一本书的时候,需要描述它的书名,作者,出版社,定价等。这些都是一种比较复杂的类型。这时候就需要结构体了。

结构体的关键词是struct,那这个该怎么用呢?我们定义一个学生类型

struct Stu
{
	char namr[20];
	char sex[5];
	int age;
};

我们使用一下这个结构体

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	char name[20];
	char sex[5];
	int age;
};
int main()
{
	struct Stu s = { "zhangsan","男",18 };
	struct Stu s2 = { "如花","女",20 };
	printf("%s\n", s2.name);
	printf("%s\n", s2.sex);
	printf("%d\n", s2.age);
	return 0;
}

?在main函数中,我们定义两个结构体变量,然后对其初始化,最后打印出来。值得注意的是这个.操作符,是通过结构体变量来找到成员的。

结构体变量.成员名

除此以外我们还可以采用函数的方式来打印结构体,具体代码实现如下

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	char name[20];
	char sex[5];
	int age;
};
void Printf(struct Stu* ps) {
	printf("%s %s %d\n", (*ps).name, (*ps).sex, (*ps).age);
	printf("%s %s %d\n", ps->name, ps->sex, ps->age);
}
int main()
{
	struct Stu s = { "zhangsan","男",18 };
	struct Stu s2 = { "如花","女",20 };
	Printf(&s);
	/*printf("%s\n", s2.name);
	printf("%s\n", s2.sex);
	printf("%d\n", s2.age);*/
	return 0;
}

运行结果如下

?这里有两种打印方式,一种是将结构体指针解引用后使用.操作符。

另外一种是使用->操作符。也就是结构体指针->结构体成员。


?

总结

本节我们讲解了指针与结构体。我们需要对指针有一个深刻的理解。

本站结束,下一站,分支和循环

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 20:56:54  更:2022-10-22 20:57:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 4:48:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码