指针是 C 语言中的一个特点,也是内存地址,是内存单元的编号,指针变量是用来寄存内存地址的变量,不同类型的指针变量所占用的存储单元长度是雷同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针当前,不仅能够对数据自身,也能够对存储数据的变量地址进行操作;个别把指针称为指针变量,指向的对象能够是变量或者数组等;指针指向数组时,它内容存储的是数组的首地址,所以数组和指针就产生了肯定的关系。那什么是数组呢?具备雷同类型的若干元素按有序的模式组织起来的一种汇合就叫做数组,上面会对指针、指针和数组相结合的一些用法进行剖析。

1、指针

1、1 定义 int * 类型的指针变量以及批改这个指针变量,其余类型的指针变量写法也相似

int * p; //p是变量的名字,int * 示意 p 变量寄存的是 int 类型变量的地址;它并不是示意定义了名叫 *p 的变量int i = 5;p = &i; //p 保留了 i 的地址,所以 p 指向 iint i2 = 6;p = &i2; //批改 p 的值不影响 i 的值int * p2 = &i;i = 9; //批改 i 的值不影响 p2 的值printf("%d\n",*p2); //*p2 输入为9,*p2 等同于 i 的值,p2 等同于 i 的地址;*p2 能够了解为以 p2 的内容为地址的变量,p2 的内容就是 i 的地址

1、2 指针与指针变量是不同的概念

零碎为每一个内存单元调配一个地址值,C 语言中把这个地址值称为“指针”。例如 int j = 6; int p=&j; 寄存变量 j 的内存单元的编号 &j 被称为指针,它的实质是一个操作受限的非负整数。“指针变量”则是寄存前述“地址值”的变量,也能够表述为,“指针变量”是寄存变量所占内存空间“首地址”的变量。把 j 的指针 &j 赋给了int 型指针变量p,就是说 p 存入着 &i,因而说指针变量是寄存指针的变量。

1、3 当某一类型的指针变量没有指向任何一个地址时,它的值为垃圾值

int i = 6;int * p;int * p2;p = &i;*p = p2; //这里语法编译谬误,因为 *p 和 p2 是两个不同的类型,*p 示意 int 类型的内容,p2 示意 int * 类型变量的地址*p = *p2; //谬误的,因为 p2 是垃圾值,所以 *p2 也是垃圾值p = p2; //p2 是垃圾值,p2 赋值给 p,p 也变成了垃圾值printf("%d\n",*p); //p 的空间是属于以后程序的,因而以后程序能够读写 p 的内容,如果 p 的内容是垃圾值,那么以后程序不能读写 *p 的内容,因为 *p 所代表的内存单元的管制权限并没有调配给以后程序,所以运行到这一行会出错

1、4 在以后函数中通过获取2个某一类型(个别是根本数据类型)变量的地址并传入另外一个函数进行内容替换,可实现2个某一类型变量内容的替换

void swop(int * p1,int * p2){   int t = 0; //这里的 t 必须定义为 int 类型的,因为 *p1 和 *p2 都是 int 类型的   t = *p1;   *p1 = *p2;   *p2 = t;      /*   ** 以下这种替换的写法是谬误的,只是替换了 p1 和 p2 指向的地址   ** 并没有替换 以 p1 和 p2 的内容为地址的变量,即 i1 和 i2   **   **   int * t;   **   t = p1;   **   p1 = p2;   **   p2 = t;   */}int main(){    int i1 = 2;    int i2 = 3;    swop(&i1,&i2);    printf("i1 = %d,i2 = %d\n",i1,i2); //这个时候输入时,i1 = 3,i2 = 2;真正实现了替换    return 0;}

1、5 “*” 代表的含意

1.5.1 示意乘法

1.5.2 示意定义指针变量,举个例子
int * p1; //定义了名叫 p1 的变量,int 代表 p1 只能寄存 int 变量的地址

1.5.3 示意指针运算符,该运算符放在定义好的指针变量的背后,举个例子
如果 p 是一个曾经定义好的指针变量,那么 *p 代表以 p 的内容为地址的变量

1、6 假如 n >= 2 , n 级指针变量只能指向 n - 1 级指针变量的地址

int i = 3; //假如 i 的地址为 1001hint * p = &i; //p 寄存的内容是 i 的地址,假如 p 的地址为 1002hint ** q = &p; //q 寄存的内容是 p 的地址,假如 q 的地址为 1003hint *** r = &q; //r 寄存的内容是 q 的地址,假如 r 的地址为 1004h//int *** r2 = &p; //error,只能寄存二级指针变量的地址printf("*p = %d\n", *p); //这里输入 i 的内容 3printf("*q = %d\n", *q); //这里输入 p 寄存的地址,即 i 的地址printf("**q = %d\n", **q); //这里输入 *p,因为 *(*q) 等同于 *pprintf("*r = %d\n", *r); //这里输入 q 寄存的地址printf("**r = %d\n", **r);  //这里输入 p 寄存的地址,因为 *r = q,**r = *q = pprintf("***r = %d\n", ***r); //这里输入 i 的内容,即 3;***r = **q = *p = i 

2 指针和数组

2、1 指针变量指向一维数组时,它寄存的是一维数组的地址同时也是一维数组第一个元素的地址

int a[5] = {1,2,3,4,5};int * p = a;int * p2 = &a[0];int boolean = p == p2;printf("boolean的值为%d\n",boolean); //boolean 的值为1,证实了 a 数组的地址和 a[0] 元素的地址相等

2、3 如果 p 是一个指针变量且指向一个一维数组,能够应用它输入数组元素,且 p[i] 等价于 *(p + i)

int a[5] = {1,2,3,4,5};int * p = a;int i = 0;for (i = 0; i < 5;i++) {  printf("p[i]的值为%d\n",p[i]); //p[i] 等价于 a[i]  printf("*(p+i)的值为%d\n",*(p+i)); //因为 a 数组的地址是间断的,p + i 等价于 a 的地址加上 i,即 p + i 等价于 a[i] 的地址,那么 *(p + i) 等价于 a[i] 的元素}

2、4 指针变量不能相加,不能相乘,也不能相除;如果两个指针变量指向的是同一块间断空间中的不同存储单元,那么这两个指针变量才能够相减

int a[5] = {1,2,3,4,5};int * p = a;int * p2 = &a[3];int j = p2 - p; //正确int j2 = p2 + p; //error,不能相加int j3 = p2 / p; //error,不能相除int j4 = p2 * p; //error,不能相乘

2、5 一个指针变量,无论它指向的地址的变量占多少个字节,该指针变量自身只占4个字节

char c = 'c';int i = 0;double d = 2.0;char * p = &c;int * p2 = &i;double * p3 = &d;printf("p所占的字节数为%d\n",sizeof(p)); //sizeof(p) 输入为 4printf("p2所占的字节数为%d\n",sizeof(p2)); //sizeof(p2) 输入为 4printf("p3所占的字节数为%d\n",sizeof(p3)); //sizeof(p3) 输入为 4

2、6 动态数组长度必须当时确定,而且只能是常整数,不能够是变量

int length = 4;int a[2]; //正确int a2[length]; //谬误的,数组长度不能够是变量

2、7 应用 malloc 函数动静结构数组

int length = 0;int * pArr;printf("请输出数组的长度\n");scanf("%d",&length);/**** 1、应用 malloc 函数,要增加 malloc.h 头文件** 2、malloc 函数只有一个形参而且只能是整形的,它示意申请零碎为以后程序调配的字节数** 3、malloc 函数返回的是第一个字节的地址** 4、一共调配了 8 * length 个字节,pArr 变量占 4 * length 个字节,pArr 指向的内存也占 4 * length 个字节** 5、pArr 自身所占的内存是动态调配的,pArr 指向的内存是动态分配的** 6、动静结构一个一维数组,假如 length = 5,相似 int pArr[20] 数组*/pArr = (int *)malloc(4 * length);int i = 0;for(i = 0; i < length;i++) {    pArr[i] = 2 * i;}for(i = 0; i < length;i++) {    printf("%d\n",pArr[i]);}

2、8 数组动态内存和动态内存的比拟

2、8、1 动态数组内存是由零碎主动调配,是在栈调配的,由零碎主动开释;动态定义的数组,它的内存无奈让程序员手动开释,在一个函数运行期间,零碎为该函数中数组调配的空间会始终存在,直到该函数运行结束时,数组的空间才会开释;数组的长度一旦定义,其长度不能够更改;
函数中定义的数组,函数运行完后数组无奈再给其余函数应用。

2、8、2 动静数组能够解决动态数组的一些缺点;动静数组内存是由程序员手动调配的,且是在堆中调配的,须要手动开释。

好了,本篇文章写到这里就完结了,因为自己技术水平无限,难免会有出错的中央,欢送批评指正,谢谢大家的浏览。


关注公众号,浏览更多乏味的文章