zoukankan      html  css  js  c++  java
  • C语言指针再回顾

    内存

    C语言内存四区:代码区,全局区,栈区,堆区

    代码区:存放代码的

    全局区:用于存放全局变量和静态变量, 里面细分有一个常量区,字符串常量和其他常量也存放在此。该区域是在程序结束后由操作系统释放。

    栈区:由系统自动开辟,系统自动释放,并不大。

    堆区:程序员动态开辟的内存,由我们手动开辟,手动释放,非常大。链表,数据结构,动态数组,动态结构体与此相关。

    地址

    一个字节8位,内存以单个字节位单位分开,每个字节有一个不可修改连续唯一的编号,这个编号就是地址。就像酒店里的房间。一个一个的房间就是一个一个字节,编号,也就是地址,就是门牌号,而且是刻在房间门上的,不可修改。

    每个在代码里的变量都有地址,用取地址运算符:& (单目运算符,优先级仅低于“()”,从右往左)来获取地址。

    首地址

    一段内存空间中,第一个存储单元的地址。如定于一个int a,占用内存中4个字节,首地址就是这四个字节中,第一个字节的地址。如图:

     第二个数组的首地址是他的第一个存储单元,也就是a[0]的地址,实际上a[0]的首地址就是他的第一个字节的首地址,数值上看是一样的,但是意义并不同

    指针变量

    地址如上所说,是一种编号,是一种数据。用来存放地址的变量,

    内存大小位4B(4个字节)

    整数 int a;

    字符 char b;

    小数 float c;

    地址  指针变量

    指针变量的定义:指针变量不是单独存在的,是相对与其他数据类型来的,比如整形指针变量 int *p;,字符型指针变量 char *p; 。

       int *p;//指明一个指针变量,存的数据为地址。int表明存放的地址指向的内存空间里面存放的数据类型是int。*表明p这个变量是指针变量。这个指针变量名字就叫做p(不是*p)。其他的类型(char,float,……)相同

    指针变量的赋值:

    int a;
    int *p;
    a=5;
    p=&a;

    加入a的地址是1001,此时p中存的是a的地址,即1001,称p指向a

    指针变量的引用:接上一条的代码,访问a的值。可以直接用a来访问,如一条printf语句,当然这里说指针,看到要用指针来访问,就像第二条printf语句。

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int i;
        int *pi;
        i = 5;
        pi = &i;
        printf("i的值为:%d
    ", i);
        printf("i的值为(指针):%d
    ", *pi);
        return 0;
    }

    指针访问:*指针变量(*为取值运算符,单目运算符,从右到左)(在定义指针变量时,*只是表明后面接的变量是一个指针变量。在未定义时出现的*,表示为取值运算符。

    野指针:不能明确指向的指针变量 ,当一个指针变量指向一个为定义的变量时,这个指针变量就是野指针。(很危险!!!!有可能在未知情况下操作意料之外的数据)

    解决部分,定义该指针为NULL,即内存中的第一个字节的地址,0

    空指针:空指针相对于int*,float*,char*,等,空指针为void*,不知道指向什么样子的内存,比如一个4个字节的内存,可以存int,long等类型的数据,未确定时,使用void,当确定下来后,可以强制把void转化需要的类型。在后期动态内存分配,用到malloc等函数时用得更多

    指针的运算

    只有4个,+, -, ++, --

    单纯指针加减没有意义,主要是为了指针偏移。指针变量的加减,以指针所指向的类型空间为单位进行偏移。如

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int i;
        char c;
        int *pi;
        char *pc;
        i = 5;
        c = 'c';
        pi = &i;
        pc = &c;
        printf("i的值为:%d
    ", i);
        printf("pi的值为:%p
    ", pi);
        printf("pi+1的值为:%p
    ", ++pi);
        printf("
    ");
        printf("c的值为:%c
    ", c);
        printf("pc的值为:%p
    ", pc);
        printf("pc+1的值为:%p
    ", ++pc);
        return 0;
    }

    从数据类型的知识可以知道,在64位windows操作系统中,int占用4个字节,char占用1个字节。 从结果中可以看到,pi+1后,指针的值比之前加了4,而pc+1后,指针的值比之前加了1。(16进制数字加减)

    首地址:一段内存空间中第一个存储单元的地址,存储单元。

    指针变量的加减:以指针所指向的类型空间位单位进行偏移。

    一维数组和指针:

      1.定义一个一维数组。数组中的元素依次存放,数组名是这个数组的‘首地址

    先定义一个数组int a[10]

    a指向a[0] ,a[0] 的类型是int,所以a是int*类型。

    a[0]这个地址指向a[0] int(*)[10]元素,字节为4,

    &a这个执行整个数组。

    如下,数组长度为10。

    第一个a+1比a增加了4,

    第二个&a+1比&a增加了40(4x10)

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int a[10];
        printf("  a=%d
    ", a);
        printf("a+1=%d
    ", a+1);
        printf("  &a=%d
    ", &a);
        printf("&a+1=%d
    ", &a+1);
    
    }

    访问数组元素:

    普通下标法:最常见,最基础的,

    指针法: 可以使用以下几种,建议*p++,*单目运算符优先级比+双目运算符优先级高,建议加一个’()‘。同时也可以使用*(a+i)来调用数组元素。此时不能用*a++。a是数组名,a++会改变a 。数组名不能改变

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int a[4]={1,2,3,4};
        int *p=a; //p指向a,即a[0]
        for(int i=0;i<4;i++)
        {
            printf("  a[i]=%d
    ", a[i]);
            printf("*(p+i)=%d
    ", *(p+i));
            printf("
    ");
        }
    }

    二维数组与指针:

    数组名是这个数组的首地址

    首地址是一段内容中第一个存储单元

    定义一个二维数组int a[3][4],在我们看来,这是一个3x4的矩阵,然鹅在计算机中,依然是线性的,此时

    a指向a[0]这个一维数组,类型为int(*)[4], a+1一次加16B

    &a指向整个二维数组,类型为int(*)[3][4]

    a[0]指向a[0][0]这个int ,类型为int* a[0]+1一次加4B

    &a[0]指向a[0]这个一维数组,类型为int(*)[4]  (a=&a[0])

    二维数组取值

    下表法:a[m][n]

    指针法:*(a[m]+n)

        *(*(a+m)+n)  (a先偏移到m行数组,再用*往下走一层,再偏移n个位置,走到a[m][n]的位置,再用一个*取这个地址的值)

     

    多维数组:

      从高到低一步一步走下去,

      假设一个5维数组 a[][][][][]

      变量名        类型

      a           int(*)[][][][]

      a[0]           int(*)[][][]

      a[0][0]        int(*)[][]

      a[0][0][0]      int(*)[]

      a[0][0][0][0]     int*

      a[0][0][0][0][0]      int

      

     善用*的取值和走向下一层和&的取地址功能,明白首地址的意义。可以很快理解各种奇奇怪怪的指针。

      注意区分int**这种多级指针int*[]这种数组指针以及int*[]这种指针数组的区别,同是还有函数指针,结构体指针,字符串与指针,指针形参的函数,

      这里我统称他们为自闭指针

     

     

  • 相关阅读:
    GBDT(MART)
    C#中数组中Skip、Take和Concat的用法
    VUE中对获取到的数组进行排序
    el-date-picker只能选择今天
    Vue获取时间
    执行Add-Migration Initial报错
    Vue中使用for循环绑定值
    Element UI——日期时间选择器el-date-picker开始时间与结束时间约束解决方案
    el-date-picker日期组件
    缓存的问题
  • 原文地址:https://www.cnblogs.com/This-is-Y/p/12417028.html
Copyright © 2011-2022 走看看