指针、引用和取值

什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量。在这份教程里“引用”表示计算机内存地址。从指针指向的内存读取数据称作指针的取值。指针可以指向某些具体类型的变量地址,例如int、long和double。指针也可以是void类型、NULL指针和未初始化指针。本文会对上述所有指针类型进行探讨。

根据出现的位置不同,操作符 * 既可以用来声明一个指针变量,也可以用作指针的取值。当用在声明一个变量时,*表示这里声明了一个指针。其它情况用到*表示指针的取值。

&是地址操作符,用来引用一个内存地址。通过在变量名字前使用&操作符,我们可以得到该变量的内存地址。

1 // 声明一个int指针
2 int *ptr;
3 // 声明一个int值
4 int val = 1;
5 // 为指针分配一个int值的引用
6 ptr = &val;
7 // 对指针进行取值,打印存储在指针地址中的内容
8 int deref = *ptr;
9 printf("%d\n", deref);

第2行,我们通过*操作符声明了一个int指针。接着我们声明了一个int变量并赋值为1。然后我们用int变量的地址初始化我们的int指针。接下来对int指针取值,用变量的内存地址初始化int指针。最终,我们打印输出变量值,内容为1。

第6行的&val是一个引用。在val变量声明并初始化内存之后,通过在变量名之前使用地址操作符&我们可以直接引用变量的内存地址。

第8行,我们再一次使用*操作符来对该指针取值,可直接获得指针指向的内存地址中的数据。由于指针声明的类型是int,所以取到的值是指针指向的内存地址存储的int值。

这里可以把指针、引用和值的关系类比为信封、邮箱地址和房子。一个指针就好像是一个信封,我们可以在上面填写邮寄地址。一个引用(地址)就像是一个邮件地址,它是实际的地址。取值就像是地址对应的房子。我们可以把信封上的地址擦掉,写上另外一个我们想要的地址,但这个行为对房子没有任何影响。

void指针、NULL指针和未初始化指针

一个指针可以被声明为void类型,比如void *x。一个指针可以被赋值为NULL。一个指针变量声明之后但没有被赋值,叫做未初始化指针。

 1 int *uninit; // int指针未初始化
 2 int *nullptr = NULL; // 初始化为NULL
 3 void *vptr; // void指针未初始化
 4 int val = 1;
 5 int *iptr;
 6 int *castptr;
 7
 8 // void类型可以存储任意类型的指针或引用
 9 iptr = &val;
10 vptr = iptr;
11 printf("iptr=%p, vptr=%p\n", iptr, vptr);
12
13 // 通过显示转换,我们可以把一个void指针转成
14 // int指针并进行取值
15 castptr = (int *)vptr;
16 printf("*castptr=%d\n", *castptr);
17
18 // 打印null和未初始化指针
19 printf("uninit=%p, nullptr=%p\n", uninit, nullptr);
20 // 不知道你会得到怎样的返回值,会是随机的垃圾地址吗?
21 // printf("*nullptr=%d\n", nullptr);
22 // 这里会产生一个段错误
23 // printf("*nullptr=%d\n", nullptr);

执行上面的代码,你会得到类似下面对应不同内存地址的输出。

iptr=0x7fff94b89c6c, vptr=0x7fff94b89c6c
*castptr=1
uninit=0x7fff94b89d50, nullptr=(nil)

第1行我们声明了一个未初始化int指针。所有的指针在赋值为NULL、一个引用(地址)或者另一个指针之前都是未被初始化的。第2行我们声明了一个NULL指针。第3行声明了一个void指针。第4行到第6行声明了一个int值和几个int指针。

第9行到11行,我们为int指针赋值为一个引用并把int指针赋值为void指针。void指针可以保存各种其它指针类型。大多数时候它们被用来存储数据结构。可以注意到,第11行我们打印了int和void指针的地址。它们现在指向了同样的内存地址。所有的指针都存储了内存地址。它们的类型只在取值时起作用。

第15到16行,我们把void指针转换为int指针castptr。请注意这里需要显示转换。虽然C语言并不要求显示地转换,但这样会增加代码的可读性。接着我们对castptr指针取值,值为1。

第19行非常有意思,在这里打印未初始化指针和NULL指针。值得注意的是,未初始化指针是有内存地址的,而且是一个垃圾地址。不知道这个内存地址指向的值是什么。这就是为什么不要对未初始化指针取值的原因。最好的情况是你取到的是垃圾地址接下来你需要对程序进行调试,最坏的情况则会导致程序崩溃。

NULL指针被初始化为o。NULL是一个特殊的地址,用NULL赋值的指针指向的地址为0而不是随机的地址。只有当你准备使用这个地址时有效。不要对NULL地址取值,否则会产生段错误。

指针和数组

C语言的数组表示一段连续的内存空间,用来存储多个特定类型的对象。与之相反,指针用来存储单个内存地址。数组和指针不是同一种结构因此不可以互相转换。而数组变量指向了数组的第一个元素的内存地址。

一个数组变量是一个常量。即使指针变量指向同样的地址或者一个不同的数组,也不能把指针赋值给数组变量。也不可以将一个数组变量赋值给另一个数组。然而,可以把一个数组变量赋值给指针,这一点似乎让人感到费解。把数组变量赋值给指针时,实际上是把指向数组第一个元素的地址赋给指针。

1 int myarray[4] = {1,2,3,0};
2 int *ptr = myarray;
3 printf("*ptr=%d\n", *ptr);
4
5 // 数组变量是常量,不能做下面的赋值
6 // myarray = ptr
7 // myarray = myarray2
8 // myarray = &myarray2[0]

第1行初始化了一个int数组,第2行用数组变量初始化了一个int指针。由于数组变量实际上是第一个元素的地址,因此我们可以把这个地址赋值给指针。这个赋值与int *ptr = &myarray[0]效果相同,显示地把数组的第一个元素地址赋值到了ptr引用。这里需要注意的是,这里指针需要和数组的元素类型保持一致,除非指针类型为void。

指针与结构体

就像数组一样,指向结构体的指针存储了结构体第一个元素的内存地址。与数组指针一样,结构体的指针必须声明和结构体类型保持一致,或者声明为void类型。

 1 struct person {
 2   int age;
 3   char *name;
 4 };
 5 struct person first;
 6 struct person *ptr;
 7
 8 first.age = 21;
 9 char *fullname = "full name";
10 first.name = fullname;
11 ptr = &first;
12
13 printf("age=%d, name=%s\n", first.age, ptr->name);

第1至6行声明了一个person结构体,一个变量指向了一个person结构体和指向person结构体的指针。第8行为age成员赋了一个int值。第9至10行我们声明了一个char指针并赋值给一个char数组并赋值给结构体name成员。第11行我们把一个person结构体引用赋值给结构体变量。

第13行我们打印了结构体实例的age和name。这里需要注意两个不同的符号,’.’ 和 ‘->’ 。结构体实例可以通过使用 ‘.’ 符号访问age变量。对于结构体实例的指针,我们可以通过 ‘->’ 符号访问name变量。也可以同样通过(*ptr).name来访问name变量。

总结

希望这份简短的概述能够有助于了解不同的指针类型。在后续的博文中我们会探讨其它类型的指针和高级用法,比如函数指针。

本文转自:http://blog.jobbole.com/25409/

转载于:https://www.cnblogs.com/Nicolasap/p/6489492.html

C 语言指针 5 分钟教程相关推荐

  1. c语言教程指针,(转)C语言指针5分钟教程

    指针.引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量.在这份教程里"引用"表示计算机内存地址.从指针指向的内存读取数据称作指针的取值 ...

  2. 取消对 null 指针“l”的引用。_C语言编程笔记丨C 语言指针 5 分钟教程

    指针.引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量.在这份教程里"引用"表示计算机内存地址.从指针指向的内存读取数据称作指针的取值 ...

  3. c语言指针数组课件,C语言指针与数组教程课件.ppt

    C语言指针与数组教程;教学要求;本章主要内容;引子;#include void swap ( int x, int y ) { printf("调用时:x地址为:%p, 值为:%d\n&qu ...

  4. C语言指针 五分钟入门!你要是不理解,我就当场把这个编译器.........

    话不多说,先上代码. #include <stdio.h>void test(int *p) {*p = 666666; }int main() {int* p1 = NULL;int p ...

  5. C语言指针 动画展示 指针到底是什么 指针的本质 C语音深入剖析

    是不是一直搞不懂C语言的指针,看完这个动画,你就全明白了 是不是一直搞不懂C语言的指针,看完这个动画,你就全明白了_哔哩哔哩_bilibili [指针的秘密]这可能是最好懂的C语言指针讲解?! [指针 ...

  6. c 语言输出指针的值,C 语言指针

    C 语言指针 在本教程中,您将学习指针.什么是指针,如何使用它们以及在示例的帮助下使用它们时可能遇到的常见错误. 指针是 C和C ++ 编程的强大功能.在学习指针之前,让我们学习一下C语言编程中的地址 ...

  7. C语言教程,30分钟彻底学会C语言指针视频教程

    c语言教程视频讲座简介: 沉睡者IT:C语言教程,30分钟彻底学会C语言指针视频教程 培训课程内容介绍: 此课程是针对C.C++指针的专题课程,通过对指针本质的讲解,帮助学员对指针快速的理解,并讲结合 ...

  8. “易语言.飞扬”十分钟入门教程(修订版1,update for EF1.1.0)

    "易语言.飞扬"十分钟入门教程 (修订版1,update for EF1.1.0) 作者:liigo,2007.8.12 本文地址:http://blog.csdn.net/lii ...

  9. “易语言.飞扬”十分钟入门教程

    "易语言.飞扬"十分钟入门教程 作者:liigo 2007.1.1 原文链接:http://blog.csdn.net/liigo/archive/2007/01/01/14720 ...

最新文章

  1. Network Broadcast
  2. 浪潮信息英伟达霸榜!MLPerf™最新榜单发布,浪潮信息包揽2021年度近半数冠军...
  3. struts2官方 中文教程 系列一:创建一个struts2 web Application
  4. Java数据结构和算法:HashMap的实现原理
  5. 东平谋定农业功能化-农业大健康·万祥军:品牌化精准扶贫
  6. 数字化转型最致命的5个误区
  7. slave_exec_mode参数跳过复制异常
  8. 传统新年元旦海报设计,必备高品质吉祥图案背景
  9. 发送get请求php,如何利用PHP发送GET请求
  10. PADS无模命令总结
  11. jsp中php代码格式化,JSP 语法 - [ JSP参考手册 ] - 在线原生手册 - php中文网
  12. python生成序列_python 之 生成序列号
  13. 单片机课设中期报告_毕业设计中期报告
  14. 009 [转载]天才与鬼才:黑客精英-凯文·米特尼克
  15. 物联网的概念、分层及关键技术
  16. 破解excel格式保护
  17. python 实战之模仿开发QQ聊天软件(二)MySQL数据库的连接和使用
  18. live writer实用插件合集
  19. C++继承继承知识点
  20. 对es搜索使用fork/join优化搜索

热门文章

  1. 资源文件相关学习总结
  2. 2017年实时更新系统hosts文件(不能访问时才会更新)不要用于非法行为 只供内部测试...
  3. 根据key删除Map集合中的key-value映射
  4. WCF - Versus Web Service
  5. ubuntu 桌面图标设置
  6. PHP工厂模式的研究
  7. hdu 1166 敌兵布阵
  8. virtualbox ubuntu安装图解
  9. 如何画透明位图(转)
  10. 两个场景怎样合在一起_Spring AOP应用场景你还不知道?这篇一定要看