zoukankan      html  css  js  c++  java
  • C/C++(指针)

    c语言指针

    所有在内存中的数据结构均可用指针来访问。
    认识内存:线性存储

    int a[3];//逻辑和存储均为线性
    int b[3][4];//二维数组的逻辑是二维的,存储结构是线性的
    for(int i = 0;i<3;i++) {
        for(int j = 0;j < 4;j++) {
            printf("%p
    ",&arr[i][j]);
        }
        putchar(10);//输出的地址是线性的 
    }
    

    存储结构是现行的原因是由内存的物理特性决定的,数组在内存中是一段连续的存储空间

    变量的地址

    &:取地址
    除了char占一个地址,其他的类型包含多个字节也就是多个地址,当我们对一个变量取地址时拿到的是低位字节的地址。

    char a;short b;int c;double d;
    printf("%p
    ",&a);
    printf("%p
    ",&b);
    printf("%p
    ",&c);
    printf("%p
    ",&d);
    //大小问题---32位下4字节,64位机下8字节,地址的大小与类型没有关系,与平台有关系
    printf("sizeof(&a) = %d
    ",sizeof(&a));
    printf("sizeof(&b) = %d
    ",sizeof(&b));
    printf("sizeof(&c) = %d
    ",sizeof(&c));
    printf("sizeof(&d) = %d
    ",sizeof(&d));
    

    对变量取地址,取出的地址就是一个指针,且是常量指针。
    &:reference,*:derefer运算互逆。狭义上是取地址和取内容。
    常量指针不是一个单纯的地址+而是有类型的。
    指针的本质:是一个有类型的地址,类型决定了从这个地址开始的寻址能力。

    char a = 1;short b = 2;int c = 3;double d = 121.2345;
    printf("&a = %p
    ",&a);
    printf("&b = %p
    ",&b);
    printf("&c = %p
    ",&c);
    printf("&d = %p
    ",&d);
    /*
    &a = 0061FEAF
    &b = 0061FEAC
    &c = 0061FEA8
    &d = 0061FEA0
    */
    
    printf("%d
    ",*(&a));
    printf("%d
    ",*(&b));
    printf("%d
    ",*(&c));
    printf("%f
    ",*(&d));
    //互为逆运算
    printf("%d
    ",*((char *)0x0061FEAF));
    printf("%d
    ",*((short *)0x0061FEAC));
    printf("%d
    ",*((int *)0x0061FEA8));
    printf("%f
    ",*((double *)0x0061FEA0));//前面不加类型会报错。
    
    int data = 0x12345678;
    printf("%p
    ,&data");
    
    printf("%x
    ",*(&data));
    printf("%p
    ",*((int*)));
    
    

    指针变量

    申明一个指针类型变量:要保存两种东西,一个地址数据,而是类型。
    type * pointerName
    :表明了本变量是指针,4个字节大小,此处只是表示申明(其他地方是的*一般是取内容作用)。type,类型决定了该指针变量中存储的地址的寻址能力。

    int data = 0x12345678;
    int *pd = &data;
    printf("%x
    ",*(&data));//12345678通过*原始取数据
    
    printf("%x
    ",*pd);//12345678通过指针的形式直接取内容,无需转换
    printf("%x
    ",*(int*)pd);//12345678
    printf("%x
    ",*(short*)pd);//5678
    printf("%x
    ",*(char*)pd);//78类型表示取地址能力
    //对地址不可以赋值
    

    指向/被指向/更改指向

    指向:指向谁就是保存了谁的地址。
    被指向:
    更改指向:指针可以改变。

    野指针

    指向一段无效的空间,即无效的指针。
    有两种形式:

    1 未初始化
    2 指向已经被释放的空间

    int *pa;
    *pa = 100;//野指针,未知的空间
    //即使不使用申明成NULL指针
    int *p = NULL;//(void *) 0,专门初始化未初始化的指针
    

    void

    void一个字节,c语言中最小的单位。

    printf("sizeof(void) = %d
    ",sizeof(void));//1
    printf("sizeof(char) = %d
    ",sizeof(char));//1以后还可以扩展
    
    //运算符的重载,由语境决定运算符的属性
    int data;
    int *p = &data;//*表示申明
    *p = 200;//*表示解引用,取内容。
    

    指针的运算

    +,-,++,--
    指针:类型(步长)+地址(物理数据)
    数值+1:简单的加1
    指针+1:加的是步长,即指针类型的大小

    int *p = (int*)0x0001;
    int pData = 0x0001;
    printf("p = %d p+1 = %d
    ",p,p+1);//1,5
    printf("pData+1 = %d pData+1 = %d
    ",pData,pData+1);//1 2
    
    printf("(doouble*)p = %d (double*)p+1 = %d
    ",(double*)p,(double*)p+1);//1,9
    printf("(int*)pData+1 = %d (int*)pData+1 = %d
    ",(int*)pData,(int*)pData+1);//1 2
    
    int arr[10];
    int * pHead = &arr[0];
    int * pTail = &arr[9];
    printf("%d
    ",pTail - pHead);//9  pHead + 9*sizeof(int) = pTail;
    int arr1[10];
    int pHead1 = (int)&arr[0];
    int pTail1 = (int)&arr[9];
    printf("%d
    ",pTail1 - pHead1);//36
    
    

    运算关系

    判断回文

    char name[5] = {'m','a','d','a','m'};
    char *pH = &name[0];char *pT = &name[4];
    int flag = 1;
    while(pH < pT) {//指针关系判断
        if(*pH == *pT) {
            pH++;
            pT--;
        }else {
            flag = 0;
            break;
        }
    }
    if(flag ==1) {
        printf("回文!");
    }else {
        printf("不是回文!");
    }
    

    数组与指针

    一维数组的访问:

    本质法---数组偏移法
    下标法---通用访问方法

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    for(int i = 0;i < 10;i++)
    {
        printf("%d
    ",*(arr+i));//偏移法
    }
    for(int i = 0;i < 10;i++) 
    {
        printf("%d
    ",arr[i]);//通用下标法
    }
    //数组名是指针常量方可唯一的表示一个数组。数组名是数组的唯一标识符。
    //一维的数组名可以赋值给以及指针,二维不可以。
    printf("arr     =%p
    ",arr);//数组名的形式访问数组首地址 
    printf("arr + 1 =%p
    ",arr + 1);//首地址+1个int类型的大小4
    
    printf("&arr[0]     =%p
    ",&arr[0]);//取数组首元素的地址
    printf("&arr[0] + 1 =%p
    ",&arr[0]+1);//数组首元素的地址+1个int的大小
    
    

    数组名能干的指针能干,数组名不能干的指针也能干

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    for(int i = 0;i < 10;i++)
    {
        printf("%d
    ",*(arr+i));//偏移法
    }
    for(int i = 0;i < 10;i++) 
    {
        printf("%d
    ",arr[i]);//通用下标法
    }
    int *p = arr;
    //可以直接替换
    for(int i = 0;i < 10;i++)
    {
        printf("%d
    ",*(p+i));//偏移法
    }
    for(int i = 0;i < 10;i++) 
    {
        printf("%d
    ",p[i]);//通用下标法
    }
    
    for(int i = 0;i < 10;i++) {
        printf("%d
    ",*p++);
        printf("%d
    ",*(p++));
        printf("%d
    ",arr[0]++);//完全等价,++的优先级高于*
    }
    
    
    

    二维数组与指针

    二维数组的访问方式

    int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    for(int i = 2;i >= 0;i--) {
        for(int j = 3;j >= 0;j--) {
            printf("a[%d][%d] = %#x
    ",i,j,&arr[i][j]);
        }
        printf("==================
    ");
    }
    printf("arr    = %#p arr+1    = %#x arr+2    = %#x
    ",arr,arr+1,arr+2);
    printf("arr[0] = %#p arr[0]+1 = %#x arr[0]+2 = %#x
    ",arr[0],arr[0]+1,arr[0]+2)
    
    /*
    a[2][3] = 0x61fea4
    a[2][2] = 0x61fea0
    a[2][1] = 0x61fe9c
    a[2][0] = 0x61fe98
    ==================
    a[1][3] = 0x61fe94
    a[1][2] = 0x61fe90
    a[1][1] = 0x61fe8c
    a[1][0] = 0x61fe88
    ==================
    a[0][3] = 0x61fe84
    a[0][2] = 0x61fe80
    a[0][1] = 0x61fe7c
    a[0][0] = 0x61fe78
    ==================
    arr    = 0X0061FE78 arr+1    = 0x61fe88 arr+2    = 0x61fe98
    arr[0] = 0X0061FE78 arr[0]+1 = 0x61fe7c arr[0]+2 = 0x61fe80
    */
    
    
    printf("*arr    = %#p *arr+1    = %#x *arr+2    = %#x
    ",*arr,*arr+1,*arr+2);
    printf("&arr[0] = %#p &arr[0]+1 = %#x &arr[0]+2 = %#x
    ",a&rr[0],&arr[0]+1,&arr[0]+2);
    //两者互为逆运算
    //a-a[0]:对a解引用(*)会产生a[0];对a[0]引用(&)会产生a;
    printf("arr[3][2] = %d
    ",*(*(arr+2)+1));
    //arr[i]    <=> *(arr+i)
    //arr[i][j] <=> *(*(arr+i)+j)
    

    往指定的地址写如数据

    int *p = (int*)0x12345678;//指定的地址,c++要求严格的数据类型
    *p = 300;
    //很容导致内存奔溃 
    
  • 相关阅读:
    SharePoint 2010 访问WebService 增删改列表
    TFS 项目删除
    一个或多个域类型未正确安装。请转到列表设置页删除这些域。
    IIS 应用程序池 已停用
    hadoop进程全部启动成功, LiveNode也正常,但界面显示 DataNode不一致
    Jenkins 打包发布java应用程序
    centos安装JDK与Tomcat
    JAVA XStream的使用
    MongoDB副本集的实现与维护实战
    基于.NET平台常用的框架整理(转)
  • 原文地址:https://www.cnblogs.com/intelwisd/p/8262006.html
Copyright © 2011-2022 走看看