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 —— 选用输出宽度较小的格式输出实数
  • 相关阅读:
    warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    Windows10+CLion+OpenCV4.5.2开发环境搭建
    Android解决部分机型WebView播放视频全屏按钮灰色无法点击、点击全屏白屏无法播放等问题
    MediaCodec.configure Picture Width(1080) or Height(2163) invalid, should N*2
    tesseract
    Caer -- a friendly API wrapper for OpenCV
    Integrating OpenCV python tool into one SKlearn MNIST example for supporting prediction
    Integrating Hub with one sklearn mnist example
    What is WSGI (Web Server Gateway Interface)?
    Hub --- 机器学习燃料(数据)的仓库
  • 原文地址:https://www.cnblogs.com/huangjianping/p/8283216.html
Copyright © 2011-2022 走看看