第十九章指针一基本概念 19.1指针是什么? 19.2指针的大小 19.3定义一个指针变量 19.4初始化指针变量 19.4.1指向不明的指针 19.4.2给指针变量赋值 19.5地址解析及其操作符* 19.6上机实验一指向普通变量的指针和指针之间的互相赋值 上机实验二:改变指针所指变量的值,改变指针的指向 19.8指针的加减操作 19.8.1指向数组的指针 19.8.2上机实验三:指向数组的指针 19.8.3偏移指针 19.8.4上机实验四:指针的最小移动单位 19.8.5指针的+=、 操作 19.8.6上机实验五:指针的前置++与后置++的区别 19.8.7*(地址解析符)与++的优先级 19.8.8上机实验六:指针的++与--操作 19.9小结 19.1指针是什么? 当我们说“人”这个词时,有时指的是“人类”如:“人是一种会笑的动物”,有时则指个 体:比如“张三这人
第十九章 指针一 基本概念 19.1 指针是什么? 19.2 指针的大小 19.3 定义一个指针变量 19.4 初始化指针变量 19.4.1 指向不明的指针 19.4.2 给指针变量赋值 19.5 地址解析 及其操作符 * 19.6 上机实验一 指向普通变量的指针和指针之间的互相赋值 19.7 上机实验二:改变指针所指变量的值,改变指针的指向 19.8 指针的加减操作 19.8.1 指向数组的指针 19.8.2 上机实验三:指向数组的指针 19.8.3 偏移指针 19.8.4 上机实验四:指针的最小移动单位 19.8.5 指针的 += 、 -= 、++、 -- 操作 19.8.6 上机实验五:指针的前置++与后置++的区别 19.8.7 * (地址解析符)与 ++ 的优先级 19.8.8 上机实验六:指针的 ++与--操作 19.9 小结 19.1 指针是什么? 当我们说“人”这个词时,有时指的是“人类”如:“人是一种会笑的动物”,有时则指个 体:比如“张三这人
“指针”这个要念也一样,它可以意指“指针类型”,也可以代表某个具体的“指针变量” 下面我们重点要讲的是:“什么叫指针变量” 所以这一小节的题目其实应是:“指针变量是什么?” “指针变量”是什么?诚如其名,它首先是一个变量 变量最重要的特性是什么?那就是它可以存储一个值。比如 下面是三行代码,行号是我为了表达方便而特意加上的,并不在实际代码中出现。 int a (2) (3) 第(1)行定义了一个变量:a。现在它存储的那个值的大小是不定的,因为我们还没有赋给 它具体的值呢。 到了(2)行执行以后,a就存了一个值,这个值多大?答:100 这里举的是一个整型变量,但其实无论是什么类型的变量,都是用来存值的 并且,变量的值可以在以后改变大小,比如第(3)行,a中存放的值成了200。 忆完普通变量的特性,现在说“指针变量” 指针也是变量,所以也是用于存储一个值。重点是,它存储的这个值,意义有点特别 指针存储的不是普通的一个值,而是另外一个变量的地址。 句话:指针是一种用于储存“另外一个变量的地址”的变量。或者拆成两句:指针是一个 变量,它的值是另外一个变量的地址
“指针”这个要念也一样,它可以意指“指针类型”,也可以代表某个具体的“指针变量”。 下面我们重点要讲的是:“什么叫指针变量”。 所以这一小节的题目其实应是:“指针变量是什么?” “指针变量”是什么?诚如其名,它首先是一个变量。 变量最重要的特性是什么?那就是它可以存储一个值。比如: 下面是三行代码,行号是我为了表达方便而特意加上的,并不在实际代码中出现。 (1) int a; (2) a = 100; (3) a = 200; 第(1)行定义了一个变量:a。现在它存储的那个值的大小是不定的,因为我们还没有赋给 它具体的值呢。 到了(2)行执行以后,a 就存了一个值,这个值多大?答:100。 这里举的是一个整型变量,但其实无论是什么类型的变量,都是用来存值的。 并且,变量的值可以在以后改变大小,比如第(3)行,a 中存放的值成了 200。 回忆完普通变量的特性,现在说“指针变量”。 指针也是变量,所以也是用于存储一个值。重点是,它存储的这个值,意义有点特别。 指针存储的不是普通的一个值,而是另外一个变量的地址。 一句话:指针是一种用于储存“另外一个变量的地址”的变量。或者拆成两句:指针是一个 变量,它的值是另外一个变量的地址
这就是指针变量与其它的变量的同与不同:的都是一个变量,都用来存储一个值:但,指针 存放的是另外一个变量的地址。 可以这样打个比方: 有一间房子,它的地址是:人民路108号。这个房子相当于一个变量。那么 如果它是普通变量,则房子里可能今天住的是张三,明天住的是李四。张三,李四就是 这个变量的值。通过访问这间房子,我们可以直接找到张三或李四 如果它是一个指针变量,则房子里不住具体的人,而是放一张纸条,上面写:“南京东 路77号”。 “南京东路77号”是一个什么东西?是一个地址。 通过该地址,我们继续找,结果在“南京东路77号”里找到张三 变量的存储的值可以改变,指针变量的值同样可以变更 过一天,我们再去访问这个房子,纸条变了“珠海路309号”,通过它,我们找到的是另 个人 图解 个指针变虽,存放着 另一个变的地址 20000007 10000008 △地址 500 20000007 能够说出图中两个“2000007”的关系吗? 本质就这点不同,同样是变量,同样要占用一定大小的内存空间,不同的是普通变量在那个 内存里,存储了一个具体的值:而指针变量存放的是另一个变量的地址
这就是指针变量与其它的变量的同与不同:的都是一个变量,都用来存储一个值;但,指针 存放的是另外一个变量的地址。 可以这样打个比方: 有一间房子,它的地址是:人民路 108 号。这个房子相当于一个变量。那么: 一、如果它是普通变量,则房子里可能今天住的是张三,明天住的是李四。张三,李四就是 这个变量的值。通过访问这间房子,我们可以直接找到张三或李四。 二、如果它是一个指针变量,则房子里不住具体的人,而是放一张纸条,上面写:“南京东 路 77 号”。 “南京东路 77 号”是一个什么东西?是一个地址。 通过该地址,我们继续找,结果在“南京东路 77 号”里找到张三。 变量的存储的值可以改变,指针变量的值同样可以变更: 过一天,我们再去访问这个房子,纸条变了“珠海路 309 号”,通过它,我们找到的是另一 个人。 图解: 能够说出图中两个“20000007”的关系吗? 本质就这点不同,同样是变量,同样要占用一定大小的内存空间,不同的是普通变量在那个 内存里,存储了一个具体的值;而指针变量存放的是另一个变量的地址
不过,什么叫“变量的地址”?只要你是一直跟着我们的课程学习到这里,相信你能明白什 么叫变量的“地址”。否则,您可以需要从第一章从头看起了 说到这里,我们其实一直在说的是“指针变量”,而不是“指针类型”。指针也需要类型 它所存储的那个变量类型,就称为指针的类型。继续前面的比方,有一天我们去人民路108号 今天纸条写着的地址是:“美眉街8号”,于是我们兴冲冲地去了……结果“美眉街8号”里 住着一头猪!是不是很失落一一我们以为是“人类”,并且是“美眉”,未料却关着一头“猪 计算机虽然不懂得什么叫“失落”,但为了它的准确性,我们需要事先定义好一个指针到底 是放的是什么类型的变量。这个类型通常也当作是该指针的类型。 “指针变量中存储某变量的地址”这种说法是不是有些绕?所以有一个简短的说法:“指针 指向某一变量” 这种说法的缺陷是不能像第一种说法好样道出指针的本质。但它确实方便。下面我们将不 断的使用这两种说法,大家需要知道它们具有相同意义 19.2指针的大小 指针的大小是问:一个指针变量占用多少内存空间 分析:既然指针只是要存储另一个变量的地址,。注意,是存放一变量的地址,而不是存放 个变量本身,所以,不管指针指向什么类型的变量,它的大小总是固定的:只要能放得下 个地址就行!(这是一间只有烟盒大小的“房间”,因为它只需要入一张与着地址的纸条 存放一个地址需要几个字节?答案是和一个int类型的大小相同:4字节
不过,什么叫“变量的地址”?只要你是一直跟着我们的课程学习到这里,相信你能明白什 么叫变量的“地址”。否则,您可以需要从第一章从头看起了。 说到这里,我们其实一直在说的是“指针变量”,而不是“指针类型”。指针也需要类型, 它所存储的那个变量类型,就称为指针的类型。继续前面的比方,有一天我们去人民路 108 号, 今天纸条写着的地址是:“美眉街 8 号”,于是我们兴冲冲地去了……结果“美眉街 8 号”里 住着一头猪!是不是很失落——我们以为是“人类”,并且是“美眉”,未料却关着一头“猪 类”?! 计算机虽然不懂得什么叫“失落”,但为了它的准确性,我们需要事先定义好一个指针到底 是放的是什么类型的变量。这个类型通常也当作是该指针的类型。 “指针变量中存储某变量的地址”这种说法是不是有些绕?所以有一个简短的说法:“指针 指向某一变量”。 这种说法的缺陷是不能像第一种说法好样道出指针的本质。但它确实方便。下面我们将不 断的使用这两种说法,大家需要知道它们具有相同意义。 19.2 指针的大小 指针的大小是问:一个指针变量占用多少内存空间? 分析:既然指针只是要存储另一个变量的地址,。注意,是存放一变量的地址,而不是存放 一个变量本身,所以,不管指针指向什么类型的变量,它的大小总是固定的:只要能放得下一 个地址就行!(这是一间只有烟盒大小的“房间”,因为它只需要入一张与着地址的纸条)。 存放一个地址需要几个字节?答案是和一个 int 类型的大小相同:4 字节
所以,若有 nt* pInt char* pChar float* fLoat double* double 则: sizeof(pInt)、 sizeof( pChar)、 sizeof( pOol)、 sizeof( fLoat)、 sizeof( dOuble) 的值全部为:4。 (你敢拆电脑吗?拆开电脑,认得硬盘数据线吗?仔细数数那扁宽的数据线由几条细线组 成?答案:32条,正是4*8) 我们这一章有很多上机实验。这就算是第一个,只是我提供了代码:请写一个程序,验证上 面关于 sizeof(T*)的结论。在写程序之前,务必要先参考一下“数据结构”这一章中 sizeof 的例 19.3定义一个指针变量 数据类型*变量名 或 数据类型*变量名; 和申请一个普通变量相比,只是在数据类型后面多了一个星号。比如:
所以,若有: int* pInt; char* pChar; bool* pBool; float* pFloat; double* pDouble; 则: sizeof(pInt)、sizeof(pChar)、sizeof(pBool)、sizeof(pFloat)、sizeof(pDouble) 的值全部为:4。 (你敢拆电脑吗?拆开电脑,认得硬盘数据线吗?仔细数数那扁宽的数据线由几条细线组 成?答案:32 条,正是 4 * 8)。 我们这一章有很多上机实验。这就算是第一个,只是我提供了代码:请写一个程序,验证上 面关于 sizeof(T *)的结论。在写程序之前,务必要先参考一下“数据结构”这一章中 sizeof 的例子。 19.3 定义一个指针变量 数据类型* 变量名; 或: 数据类型 *变量名; 和申请一个普通变量相比,只是在数据类型后面多了一个星号。比如: int* p;
星号也可以靠在变量名前面, int *p 要同时定义多个相同类型的指针,则为 int *pl, *p2 注意,每个变量之前都必须有* 19.4初始化指针变量 是变量就存在一个初始化的问题。一个不能确定是住着什么人的房间,总是有点恐怖。 19.4.1指向不明的指针 我先定义一个整型指针 nt* p 现在,p是一个指针,int规定它只能存放整型变量的地址,而不是其它如字符型,布尔型 等等 我们称:p是一个整型指针。 不过,现在p指向哪里(即:p存储的是哪个变量的地址)? 变量在没有赋值之前,其值不定的。对于指针变量,值不定可以表述为:指向不明 重点来了!一个指向不明的指针,是一个危险的家伙。很多软件有BUG,其最后的原因 就在这里。 来看看下而的“恐怖片
星号也可以靠在变量名前面,如: int *p; 要同时定义多个相同类型的指针,则为: int *p1, *p2; 注意,每个变量之前都必须有 * 。 19.4 初始化指针变量 是变量就存在一个初始化的问题。一个不能确定是住着什么人的房间,总是有点恐怖。 19.4.1 指向不明的指针 我先定义一个整型指针: int* p; 现在,p 是一个指针,int 规定它只能存放整型变量的地址,而不是其它如字符型,布尔型 等等。 我们称:p 是一个整型指针。 不过,现在 p 指向哪里 (即:p 存储的是哪个变量的地址 )? 变量在没有赋值之前,其值不定的。对于指针变量,值不定可以表述为:指向不明。 重点来了! 一个指向不明的指针,是一个危险的家伙。很多软件有 BUG,其最后的原因, 就在这里。 来看看下而的“恐怖片”:
打开火折,但见 你来到一间阴森森的 你前往这纸条 纸条内容:“XX街3K XXX街3K号”里住着 房间,这房间里有一张 千年老妖!你 > 0x3F0073D是哪里的 程序访问了一个没有 程序随即访问内存?说不定正好是 初始化的指针: p的内存是随机的一个 内存地址 Windows老大要用的内 数,比如:0x3FF0073D 0x3FF0073D 存,你竟敢访问 Windows一生气,蓝屏 既然没有赋值的指针这么危险,下面来看看如何给指针赋值。 19.4.2给指针变量赋值 (1) int k= 100 int米 p=&k;//p取得变量k的地址(也称:p指向k) 第1行定义一个整型变量k 第2行定义了一个整型指针p 而第3行,“指针p存储了变量k的地址”。短的说法是“p指向了k” 执行了上面三行代码后,结果是:p指向k。我们来看具体的内存示意图
你来到一间阴森森的 房间,这房间里有一张 纸条 ---> 打开火折,但见 纸条内容:“XXX 街 3K 号” ---> 你前往这纸条 的神秘地 址…… ---> “XXX 街 3K 号”里住着 一千年老妖!你…… 程序访问了一个没有 初始化的指针: int* p; p 的内存是随机的一个 数,比如: 0x3FF0073D 程序随即访问 内存地址: 0x3FF0073D 0x3FF0073D 是哪里的 内 存 ? 说 不 定 正 好 是 Windows 老大要用的内 存,你竟敢访问! Windows 一生气,蓝屏。 既然没有赋值的指针这么危险,下面来看看如何给指针赋值。 19.4.2 给指针变量赋值 (1) int k = 100; (2) int* p; (3) p = &k; //p 取得变量 k 的地址 (也称:p 指向 k) 第 1 行定义一个整型变量 k。 第 2 行定义了一个整型指针 p。 而第 3 行,“指针 p 存储了变量 k 的地址”。短的说法是“p 指向了 k”。 执行了上面三行代码后,结果是: p 指向 k。我们来看具体的内存示意图
且k:|100 11000002 变员k 11000006 1100000 110014004 p指向k示意图 上图中,红色数字代表什么?红数字11000002是变量k的内存地址 指针初始化的结果,就是让它存储下另一个变量的地址。简称指向另一个变量 下面说说三种常见的,给指针赋值的操作: 、用&取得普通变量的地址。 要想让指针指向某个普通变量,需要通过&来得到该普通变量的地址。 nt k int*p=&k 指针之间的赋值 两个指针之间也可以相互赋值,此时不需要通过&来取址。 It k int* pl
p 指向 k 示意图 上图中,红色数字代表什么?红数字 11000002 是 变量 k 的内存地址。 指针初始化的结果,就是让它存储下另一个变量的地址。简称指向另一个变量。 下面说说三种常见的,给指针赋值的操作: 一、用 & 取得普通变量的地址。 要想让指针指向某个普通变量,需要通过 & 来得到该普通变量的地址。 int k; int* p = &k; 二、指针之间的赋值。 两个指针之间也可以相互赋值,此时不需要通过 & 来取址。 int k; int* p1
//p1先指向 //然后,p2也指向 注意,p2=p1的结果是:让p2也指向“p1所指的内容”,而不是让p2指向“p1本身” 上面的情况可以改为直接在定义时就赋值 t**p1=&k 三、让指针指向数组 数组本身就是地址,所以对数组变量也不用通过&来取址 char name[]="NanYu char*p=name;//不用取址符& 或者 int arr[3]={100,99,80}; 四、让指针指向一个新地址 前而的赋值方法都是让指针指向一个已有的内存空间的地址。比如:int*p=&k:指针变 量p存放的是已有的变量k的地址。其实指针也可以指向一个新开辟的内存空间,这一内存空 间不归属于其它变量
int* p2; p1 = &k; //p1 先指向 k p2 = p1; //然后 ,p2 也指向 k。 注意,p2 = p1 的结果是:让 p2 也指向“p1 所指的内容”,而不是让 p2 指向“p1 本身”。 上面的情况可以改为直接在定义时就赋值: int k; int* p1 = &k; int* p2 = p1; 三、让指针指向数组 数组本身就是地址,所以对数组变量也不用通过 & 来取址。 char name[] = "NanYu"; char* p = name; //不用取址符 & 或者: int arr[3] = {100,99,80}; int* p = arr; 四、让指针指向一个新地址 前而的赋值方法都是让指针指向一个已有的内存空间的地址。比如:int* p = &k; 指针变 量 p 存放的是已有的变量 k 的地址。其实指针也可以指向一个新开辟的内存空间,这一内存空 间不归属于其它变量
在C++中,常用一个关键字:new来为指针开辟一段新空间。比如 int* p= new int 现在,指针变量p存储着一个内存地址,该内存地址确实存在一一它是由new操作符申请 而得。可以这样认为,new是一位特权人物,不通过它,指针只能指向已有的“房间”:而使 用了它,则可以要求系统为指针“新开辟一片空地,然后建上新房间”。 有特权的人不仅仅是“new”,还有几个系统定义的函数,及 Windows提供的函数,都可以 实现“向系统要空间”的功能。我们将在后面专门的章节详细讲解。 19.5地址解析及其操作符* *在C,C++语言里除了起“乘号”的作用以外,前面我们还刚学了它可以在定义变量时,表 明某个变量是属于“指针类型”。现在,则要讲到它还能起“地址解析”的作用。 什么叫“地址解析”?假设有一int类型变量k ntk= 100 内存 内存地址 100 11000000 方框是变量k所占用的内存。100是该内存中存放的值。而11000000则是该内存的地址。 “地址解析”就是地址->值的解释过程。即:通过地址110000(到位于地址的变量 可见“地址解析(*)”和“取址(&)”正好是一对相反的操作
在 C++中,常用一个关键字:new 来为指针开辟一段新空间。比如: int* p = new int; 现在,指针变量 p 存储着一个内存地址,该内存地址确实存在——它是由 new 操作符申请 而得。可以这样认为,new 是一位特权人物,不通过它,指针只能指向已有的“房间”;而使 用了它,则可以要求系统为指针“新开辟一片空地,然后建上新房间”。 有特权的人不仅仅是“new”,还有几个系统定义的函数,及 Windows 提供的函数,都可以 实现“向系统要空间”的功能。我们将在后面专门的 章节详细讲解。 19.5 地址解析 及其操作符 * * 在 C,C++语言里除了起“乘号”的作用以外,前面我们还刚学了它可以在定义变量时,表 明某个变量是属于“指针类型”。现在,则要讲到它还能起“地址解析”的作用。 什么叫“地址解析”?假设有一 int 类型变量 k: int k = 100; 内存 内存地址 100 11000000 方框是变量 k 所占用的内存。100 是该内存中存放的值。而 11000000 则是该内存的地址。 “地址解析”就是 地址->值 的解释过程。即:通过地址 11000000 得到位于地址的变量。 可见“地址解析(*)” 和 “取址(&)” 正好是一对相反的操作