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\n", i);
    printf("i的值为(指针):%d\n", *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\n", i);
    printf("pi的值为:%p\n", pi);
    printf("pi+1的值为:%p\n", ++pi);
    printf("\n");
    printf("c的值为:%c\n", c);
    printf("pc的值为:%p\n", pc);
    printf("pc+1的值为:%p\n", ++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\n", a);
    printf("a+1=%d\n", a+1);
    printf("  &a=%d\n", &a);
    printf("&a+1=%d\n", &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\n", a[i]);
        printf("*(p+i)=%d\n", *(p+i));
        printf("\n");
    }
}

 

 

二维数组与指针:

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

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

定义一个二维数组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*[]这种指针数组的区别,同是还有函数指针,结构体指针,字符串与指针,指针形参的函数,

 

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

 

 

 

 

 

 

posted @ 2020-03-05 16:40  This_is_Y  阅读(283)  评论(0编辑  收藏  举报