zoukankan      html  css  js  c++  java
  • 【C】Re05 指针

    一、变量 & 指针

    变量 = 内存地址 + 存储值

    指针变量 = 内存地址 + 存储值【变量的内存地址】

    作用: 间接访问内存地址

    内存地址 = 地址编号

    地址编号:内存中的每个字节唯一的编号,从0开始记录,使用十六进制显示

    可以使用指针变量存储变量的地址

    不同数据类型就有对应的指针的数据类型

    二、使用

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdlib.h>
    #include <stdio.h>
    
    
    void pointer () {
        // 指针变量
        int * pointer;
        // 变量
        int varA = 100;
    
        printf("pointer -> x16 %x, x10 %d, x8 %o
    ", pointer, pointer, pointer);
        printf("varA -> %d
    ", varA);
    
        printf("- - - - - - - - - - - - - - -
    ");
    
        // 把varA的地址赋值给指针变量pointer
        pointer = &varA;
        // 通过指针变量pointer取地址访问varA变量
        *pointer = 20;
    
        printf("pointer -> x16 %x, x10 %d, x8 %o
    ", pointer, pointer, pointer);
        printf("varA -> %d
    ", varA);
    }
    
    int main() {
        pointer();
        return EXIT_SUCCESS;
    }

    输出格式注意:

     // %p显示完整十六进制位数, %x只显示进制数

    语法递进:

        int tf = (*pointer == *&varA); // 0 false, 1 true
        int tf2 = (pointer == &varA);
        int tf3 = (*pointer == varA);
    
        printf(" %d
    ",tf);
        printf(" %d
    ",tf2);
        printf(" %d
    ",tf3);

    三、空指针& 野指针

    空指针定义

    void nullPointerAndWildPointer () {
        // 定义一个空指针
        int * nullPointer = NULL;
    }

    指向的NULL常量来自于STDLIB标准库头文件的这一段

    #else
    #define NULL ((void *)0)
    #endif
    #endif

    最后指向的还是一个0而已

    void nullPointerAndWildPointer () {
        // 定义一个空指针
        int * nullPointer = 0;
    }

    实际上不建议直接写0,容易混淆指针变量与变量

    空指针不能被访问到:

    void nullPointerAndWildPointer () {
        // 定义一个空指针
        int * nullPointer = NULL;
        printf("nullPointer -> %p", *nullPointer);
    }
    
    int main() {
        nullPointerAndWildPointer();
        return EXIT_SUCCESS;
    }

    因为内存地址编号0 - 255已经被操作系统占用了

    空指针的作用:

    不知道应该对指针定义多少合适时使用

    野指针定义:

    void nullPointerAndWildPointer () {
        int * wildPointer = 0xffff;
        printf("wildPointer -> %p
    ", *wildPointer);
    }

    指针变量存储了非法的、未知的一个内存地址,该地址存储的内容将无法访问

    但是允许查看地址

    void nullPointerAndWildPointer () {
        // 定义一个空指针
    //    int * nullPointer = NULL;
    //    printf("nullPointer -> %p
    ", *nullPointer);
    
        // 定义一个野指针
    //    int * wildPointer = 0xffff;
    //    printf("wildPointer -> %p
    ", *wildPointer);
    
        int * nullPointer = NULL;
        printf("nullPointer -> %p
    ", nullPointer);
    
        int * wildPointer = 0xffff;
        printf("wildPointer -> %p
    ", wildPointer);
    }
    
    int main() {
        nullPointerAndWildPointer();
        return EXIT_SUCCESS;
    }

    野指针的第二种情况:

    也是一样,地址可以访问,但是内部存储的值无法访问

        // 野指针的第二种情况
        int * wildPointer2;
        printf("wildPointer2 -> %p
    ", wildPointer2);
        // printf("wildPointer2 value -> %d
    ", *wildPointer2);

    四、无类型指针 和 万能指针

    1、Void类型概述

    void voidUsage() {
        // void 是一个数据类型,所以也具备对于的指针类型 void *
        // void 的用途是修饰函数返回类型和形参类型
    }
    
    // 形参修饰了void 表示 该函数不需要参数
    void noNeedParam( void ) {
        
    }

    2、函数返回类型省略

    当函数的返回值类型声明的是void时,我们可以省略,不需要return

    不过不建议这样书写,C++并不支持这样的语法

    aaa () {
        printf("void返回类型省略的函数调用!!!");
    }
    
    int main() {
        aaa();
        return EXIT_SUCCESS;
    }

    如果函数不需要注入任何类型的参数,编写时是可以明确标注void 数据类型即可

    3、无类型指针与万能指针:

     无类型指针可以强转任意类型接收对于的类型的变量地址

    void noTypePointer() {
        void * p = NULL;
        printf("sizeof p = %d
    ", sizeof(p)); // 64位 sizeof p = 8 32位 sizeof p = 4
    
        int num = 10;
        p = &num;
        // printf("p = %d
    ", *p); int指针类型赋值给void指针类型, 类型不匹配错误
        // 使用强转来转换指针类型
        printf("p = %d
    ", *(int *)p);
    }

     另外可以作为万能指针使用:

    void anyTypePointer() {
    
        void * pointer = NULL;
    
        int * varA = NULL;
        char * varB = NULL;
    
        // 一个是int指针类型一个是char指针类型,直接这样赋值不会有语法错误提示
        // 但是在编译执行时会有警告提示,另外,如果指针调用了就会报错。。。
        // varA = varB;
        // 所以需要强转处理
        varA = (int *)varB;
    
        // void*指针类型的指针可以赋值给任何指针类型,不需要强转【自动转换?】
        varA = pointer;
    }
    
    // 因为void*指针类型 第二用,作为参数类型
    void function ( void * sss) {
        
    }

    五、Const修饰指针变量

    void constWithPointer() {
        // 1、const修饰的是*, *p 是只读的, p可读可写的
        int varA = 100;
        const int * pToVarA = &varA; // 如何判断是修饰* 还是 p? 看*还是p靠前,和const近, 等同于 int const * pToVarA = &varA;
        // *pToVarA = 20; 不允许访问地址写入了
    
        printf("pointer -> %p
    ", pToVarA);
    
        int varB = 200;
        pToVarA = &varB; // 更改赋值地址是允许的
    
        printf("pointer -> %p
    ", pToVarA);
    
        // 总结下来就是:指针指向地址的存储值不可以改变,指向地址可以改变
    
        // --------------------------------------------------------------
    
        // 2、const修饰的是p, p 是只读的, *p可读可写的
        int c = 150;
    
        // 语法
        int * const p = &c;
    
        // 可以对指向地址的存储值进行写入更改
        *p = 20;
        // p = &varA; 但是不再允许指向其他地址了
    
        // 指针指向地址的存储值可以修改,但是指针的指向地址不可以修改
    
        // --------------------------------------------------------------
    
        // 3、const修饰的是*和p, *和p都是只读的
        int d = 120;
        int const * const p2 = &d;
        // p2 = &c; 更改指向 不允许
        // *p2 = 230; 更改存储值 不允许
    }
    
    int main() {
        constWithPointer();
        return 0;
    }

    六、不同指针类型的区别?

    void differFromPointers() {
        char * p1 = NULL;
        int * p2 = NULL;
        double * p3 = NULL;
    
        printf("p1 -> %p
    ", p1);
        printf("p2 -> %p
    ", p2);
        printf("p3 -> %p
    ", p3);
    
        // 区别1 不同指针类型 叠加字面值的步长不一样,这取决于他们的数据类型长度
        printf("p1 + 1 -> %p
    ", p1 + 1); // char指针类型向前移动一个字节
        printf("p2 + 1 -> %p
    ", p2 + 1); // int指针类型向前移动4个字节
        printf("p3 + 1 -> %p
    ", p3 + 1);
    
        // 区别2 解引用的字节数量也不一样,取到的值也就不一样
        int num = 0x01020304; // int num = 0x01020304; int num = 0x21348903;
        int * p4 = &num;
        printf("*p4 -> %#x
    ", *p4); // *p4 -> 0x1020304
    
        short * p5 = &num;
        printf("*p5 -> %#x
    ", *p5); // *p5 -> 0x304
    
        char * p6 = &num;
        printf("*p6 -> %#x
    ", *p6); // *p5 -> 0x304
    }
    
    int main() {
        differFromPointers();
        return 0;
    }
  • 相关阅读:
    1. 两数之和
    RabbitMQ主题交换机
    RabbitMQ路由
    RabbitMQ发布订阅
    RabbitMQ简介和安装
    55. 跳跃游戏
    63. 不同路径 II
    62. 不同路径
    6. Z 字形变换
    sql注入攻击与防御第一章(笔记)
  • 原文地址:https://www.cnblogs.com/mindzone/p/13936772.html
Copyright © 2011-2022 走看看