zoukankan      html  css  js  c++  java
  • (一)指针就是地址

    首先明确一个观点:指针就是地址。这是理解指针的起始一步。

    直观感受下,变量的地址

     1 int main()
     2 {
     3     int foo;
     4     int *foo_p;
     5     foo = 5;
     6     foo_p = &foo;
     7     printf("   foo...%d
    ", foo);
     8     printf("*foo_p...%d
    ", *foo_p);
     9     printf("  &foo...%p
    ", &foo);
    10     printf(" foo_p...%p
    ", foo_p);
    11     printf("&foo_p...%p
    ", &foo_p);
    12     return 0;
    13 }

    几点说明:

    1. %p中的p是pointer(指针)的意思,专门用于打印指针变量中的内容。
    2. 有时看到用%x打印指针的,虽然结果一样,但含义完全不同。%p:用合适的方式(一般是十六进制)输出指针变量中存放的另一个变量的地址;%x:用十六进制的方式打印出变量的值。并且在我的环境中使用%x打印指针变量的话,会省略前面的0。
    指针变量的示意图
    左上角是变量名,右上角是变量地址,中间是变量存储的内容。
    可以这样来理解指针:指针是一种特殊的语言机制,它存放的是其它变量的地址,并且可以通过解引用操作符*,来获取该地址的内容。这也造成了一种指向的关系,如上图 foo_p->foo。
     
    高阶指针
    如二级指针:指向指针的指针。
    int main()
    {
        int foo = 5;
        int *foo_p = &foo;
        int **foo_pp = &foo_p;
        printf("     foo...%d
    ", foo);
        printf("   &foo...%p
    ", &foo);
        printf("  foo_p...%p
    ", foo_p);
        printf(" &foo_p...%p
    ", &foo_p);
        printf("  *foo_p...%d
    ", *foo_p);
        printf(" foo_pp...%p
    ", foo_pp);
        printf("&foo_pp...%p
    ", &foo_pp);
        printf("*foo_pp...%p
    ", *foo_pp);
        printf("**foo_pp...%d
    ", **foo_pp);
        return 0;
    }

    由运行结果,画出内存示意图:
    各变量的类型推导,foo_p是指针,且指向int,故foo_p的类型是int*,也就是在'*'前添加int;foo_pp也是指针,且指向foo_p,故foo_pp的类型是int**,也就是在'*'前添加int*。
    更高阶的指针类型,以此类推。
    环境中各基本类型分配的内存大小:
    int main()
    {
        printf("sizeof(char)...%d
    ", sizeof(char));
        printf("sizeof(int)...%d
    ", sizeof(int));
        printf("sizeof(float)...%d
    ", sizeof(float));
        printf("sizeof(double)...%d
    ", sizeof(double));
        printf("sizeof(int*)...%d
    ", sizeof(int*));
        return 0;
    }

    在我的环境中,指针类型分配的大小是 sizeof(int*)=4;也就是说用4个字节的大小来存储变量的地址,这也是目前大多数环境下的结果。以后讨论基于这个结果。至于在c标准中,没有规定指针类型的大小,具体大小依靠具体的环境。
    关于 sizeof
    首先必须指出:sizeof是操作符,而不是函数。被误解为函数,可能是大多数情况下,我们都这样使用它:sizeof()。其实这样用 sizeof 类型,如sizeof int也是可以的。
    正确的使用是:如果Type是类型名,则sizeof(Type);如果Type是变量,则加不加括号,都可以。

    探讨几个问题
    (1)竟然指针存放的是变量的地址,而在同一环境中地址是同种类型的整数,如4字节大小的,那为何还有指针类型的说法?
    int main()
    {
        int foo;
        int *int_p=&foo;
        double *dou_p=&foo;
        foo=5;
        printf("foo...%d
    ", foo);
        printf("int_p...%p
    ", int_p);
        printf("dou_p...%p
    ", dou_p);
    
        printf("*int_p...%d
    ", *int_p);
        printf("*int_p...%f
    ", *int_p);
        printf("*dou_p...%d
    ", *dou_p);
        printf("*dou_p...%f
    ", *dou_p);
    }

    为什么会出现这种情况,关键在于:不同类型的变量有不同的存储方式。如4字节的int和同样4字节的float,所分配的空间大小一样,但能够表示的数据范围有很大差距。具体存储方式,大家可查下。
    这就说明,在进行解引用时,必须指出相应的类型方式,才可正确获取变量值。
    指针是派生类型,它的类型依靠它所指向的对象。
    两个概念
    指针的类型、指针所指向的类型
    用实例说明:int *p;
    (i)p是指针,它的类型是 int*
    (ii)p是指针,它所指向的类型是 int
    另一个实例:int **p;
    (i)p是指针,它的类型是 int**(二级指针,它的用法以后会讲到)
    (ii)p是指针,它所指向的类型是 int*
    方法很简单:是不是指针类型,就看声明中有没有*;指针的类型就是去掉变量名后,剩下的部分;指针所指向的类型就是去掉变量名和离它最近的*,剩下的就是。
    同样提醒我们:不可忽视编译器的警告!
     
    (2)空指针类型:void*
    在ANSI C中提供了一种,可以接受任何类型的指针类型:void*(空指针类型)
    int foo = 5;
    void *p = &foo;   //这句话是不会报错的
    printf("*p...%d ", *p);   //这句话无法通过编译
    不能通过编译的原因:如果仅仅知道变量的内存地址,但却不知道变量的类型,编译器也就不知道如何对这段地址上的内容进行解析,也就是无法解引用。
    (3)printf()函数
    printf(格式控制,输出表);
    功能:按照规定格式输出指定数据。
    “格式控制”是用双引号括起来的格式控制转换字符串。“输出表”中的数据可以是合法的常量、变量和表达式,要与“格式控制”中的格式字符一一对应。
    几个格式输出符
    %d —— 以带符号的十进制形式输出整数
    %o —— 以无符号的八进制形式输出整数
    %x —— 以无符号的十六进制形式输出整数
    %u —— 以无符号的十进制形式输出整数
    %c —— 以字符形式输出单个字符
    %s —— 输出字符串
    %f —— 以小数点形式输出单、双精度实数
    %e —— 以标准指数形式输出单、双精度实数
    %g —— 选用输出宽度较小的格式输出实数
  • 相关阅读:
    idea常用快捷键及操作
    Ubuntu 装nexus
    ubuntu安装gitlab
    ubuntu安装jdk,maven,tomcat
    ubuntu安装gitlab-ci-runner、注册
    ubuntu开启远程shell,开启上传下载
    Ubuntu安装软件提示boot空间不足
    POJ3461 KMP简单变形输出模式串在主串出现的次数
    涨姿势stl map['a']['a']=b;
    对链表的操作(数据结构线性表算法设计练习)
  • 原文地址:https://www.cnblogs.com/huangjianping/p/8283216.html
Copyright © 2011-2022 走看看