前言
指针的学习是C语言中的一个重要部分,对于指针我们必须认真对待并加以理解,接下来就让小编给大家细细讲解一下
1.指针是什么
所谓指针大家可以理解为是地址,在我们的内存中我们会对内存的每个进行编号,以进行合理管理。
而在我们的口语中的指针其实是指针变量,用来存放内存空间地址的变量。这里我给大家演示一下
#include <stdio.h> int main() { int a = 0; int* p = &a;//这里我们定义了一个指针p指向了变量a //接下来我们分别对a和p的地址进行打印 printf("%p\n", &a); printf("%p", p); return 0; }
结果如下:
这里我们可以看到,指针变量p存储的的确是变量a的地址。
而对于该编号,往往是机器决定的,比如说你的电脑是32位机器,那么该编号便从00000000
00000000000000000000000000000000开始到11111111111111111111111111111111结束,这也就导致了此时指针变量的大小是4字节的,对于64位机器,同理,此时的指针变量大小就是8字节
2.指针类型和指针的使用
2.1指针的使用
对于指针的使用我需要和大家简单的介绍两个操作符&和*
&操作符又叫做取地址符,该作用就是取出变量的地址,而*操作符又叫做解引用操作符, 该作用和取地址符作用相反,它的作用是得到一个变量的地址,通过解引用从而得到该变量的存储内容。通过这两个操作符,我们就可以对指针变量进行初步的使用
#include <stdio.h> int main() { int a = 0; int* p = &a;//这里我们定义了一个指针p指向了变量a *p = 2;//通过解引用,改变a的值 printf("%d", a); return 0; }
这里我们得到的结果是:
2.2 指针类型
指针变量和普通变量一样,都有着不同的类型,但是对于指针类型它的意义和普通变量却有着极大的不同。
a.指针类型决定了,指针解引用操作的时候一次访问几个字节, 比如char*指针只访问一个字(其他解引用与其类型大小一致)
b.指针类型决定了指针的步长(指针+1跳过几个字节)(字符指针+1跳过一个字节,int类型跳过4个字节)
总的来说指针类型的意义在于:指针的不同类型,其实提供了不同的视角去观看和访问内存
可能直接讲概念大家可能有点不理解,下面我给大家实操一下,大家可以结合理解一下
#include <stdio.h> int main() { int a = 0x11223344; char* p = (char*)&a;//这里我们用p指向变量a * p = 02; printf("%x", a); return 0; }
结果如下:
这里由于是小端存储,所以改变的是最后一个字节,这里我们就可以充分看出指针类型的作用。还有之前给大家介绍的大小端的判断方式,这里我给大家讲解一下
int main() { int b = 1; char* q = (char*)&b; if (*q == 1) { printf("小端"); } else { printf("大端"); } return 0; }
这里我们采用的就是char类型的指针来达到对应的效果,对于常量1,在大端存储中以16进制存储达到的效果是00000001,而在小端存储中则是01000000,这就导致了我们用char类型指针访问的第一个字节的不同,这样就可以很好的判断大小端存储
3.野指针
野指针就是指针指向的位置是不可知的(随机的,不确定的,没有限制的)
成因:1.指针未初始化(里面是随机值;*P=20)
2.指针越界访问
3.指针指向空间的释放
野指针的存在是具有巨大的危害的,而对此我们要尽量规避,以免此类事件的发生
规避方法:1.指针初始化(指针未使用的时候可以把它指向空指针NULL,但是不可以直接使用)
2.小心越界
3.指针指向空间释放,及时指向NULL
4.避免返回局部变量地址
5.指针使用前检查其有效性
4.指针运算
4.1 指针+-整数
指针+-整数一般是在一段连续的空间使用的,不然该解引用就会导致非法访问
实例展示:
#include <stdio.h> int main() { int arr[10] = { 0 }; int* p = arr; int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i;//这里指针p还是指向数组首地址 } for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } }
结果如下:
4.2 指针-指针
指针-指针的绝对值(前提:指针指向同一个空间)得到的是两个指针之间的元素个数,这里我们可以封装一个判断字符串长度的函数,给大家演示一下
#include <stdio.h> int my_strlen(char* str) { char* first = str;//首先定义一个指针指向数组首元素 while (*first != '\0') { first++; }//让指针first到达字符串数组的最后一个元素 return first - str; } int main() { char arr[] = "abcdefg"; int ret = my_strlen(arr); printf("%d", ret); return 0; }
结果如下:
4.3 指针的关系运算
对于指针关系运算该前提仍然要求该在连续的一块空间中
实例展示:
#include <stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9 ,10}; int* p = arr; for (p = arr; p < &arr[10]; p++) { printf("%d ", *p); } }
结果如下:
对于指针关系的比较这里,我们可以分别对指向第一个元素之前的那个内存位置的指针进行比较
也可以与指向数组最后一个元素后面那个内存位置比较,这样都可以到达打印数组的效果,但该在C语言中是有规定要求的。
标准规定:允许指向数组元组的指针与指向数组最后一个元素后面那个内存位置比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较(越界但是没有访问)
5.二级指针
这里对于二级指针该概念,我给大家举例说明
int a=10;
int *pa=&a;*表示pa是指针
int * *ppa=&pa;int *一起表示ppa的类型,*表示ppa是指针
这里ppa就是二级指针,*ppa就是pa
而二级指针的作用则是存储一级指针的地址,以到达对一级指针变量的控制。
这里我给大家演示一下二级指针的具体用法
#include <stdio.h> int main() { int a = 10; int* p = &a; int** ppa = &p; printf("%d\n", a); printf("%d\n", *p); printf("%d\n", **ppa); }
结果如下:
6. 指针数组
指针数组指的是存储指针的数组
该类型声明如下:
指针类型 数组名[数组大小]={存储的是地址};
这里我们使用指针数组进行一维数组模拟二维数组,用法如下:
#include <stdio.h> int main() { int a[] = { 1,2,3,4 }; int b[] = { 2,3,4,5 }; int c[] = { 3,4,5,6 }; int* arr[3] = { a,b,c }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("%d ", arr[i][j]); } printf("\n"); } return 0; }
结果如下: