最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

环球短讯!12-指针02

来源:博客园


【资料图】

指针

回顾

1. 指针的定义

  • 指针也是一种数据类型,指针变量也是一种变量
  • 指针变量指向谁,就把谁的地址赋值给指针变量
  • “*”操作符操作的是指针变量指向的内存空间
#include int main(){int a = 0;char b = 100;printf("%p, %p\n", &a, &b); //打印a, b的地址//int *代表是一种数据类型,int*指针类型,p才是变量名//定义了一个指针类型的变量,可以指向一个int类型变量的地址int *p;p = &a;//将a的地址赋值给变量p,p也是一个变量,值是一个内存地址编号printf("%d\n", *p);//p指向了a的地址,*p就是a的值char *p1 = &b;printf("%c\n", *p1);//*p1指向了b的地址,*p1就是b的值return 0;}

注意:&可以取得一个变量在内存中的地址。但是,不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的。2.指针大小

  • 使用sizeof()测量指针的大小,得到的总是:4或8
  • sizeof()测的是指针变量指向存储地址的大小
  • 在32位平台,所有的指针(地址)都是32位(4字节)
  • 在64位平台,所有的指针(地址)都是64位(8字节)
int *p1;int **p2;char *p3;char **p4;printf("sizeof(p1) = %d\n", sizeof(p1));printf("sizeof(p2) = %d\n", sizeof(p2));printf("sizeof(p3) = %d\n", sizeof(p3));printf("sizeof(p4) = %d\n", sizeof(p4));printf("sizeof(double *) = %d\n", sizeof(double *));

1.野指针

野指针的指向的地址是随机的,不能操作野指针指针指向的地址是系统分配的,定义变量的时候向系统申请,系统进行分配指针初始化的地址不能由自己给出

#include #include #include int main(){// 野指针是指没有初始化(赋值)的指针int *p; // 定义一个指针变量p   // *p 指向的是指针变量存储的地址对应的空间// 指针变量p没有存储地址,所以p中存储的地址是随机的(指针的指向是随机的)// 将这样没有初始化的指针称之为野指针*p = 200;system("pause");return 0;}

2.空指针

  • int *p = NULL -- 表明定义了一个指针,并将其初始化为NULL,就是指向0所在的地址0x0000 0000;
  • 零指针初始化所指向的位置不用于存储其他的地址,只是表明该指针进行了初始化,可以进行使用的标志
  • 习惯:将指针使用完之后,置为NULL,这样在使用指针的时候,判断指针指向为NULL,那么该指针可以进行使用,如果该指针不为NULL,表明该指针不能使用(该指针未初始化或者正在使用)
#include #include #include int main(){// 定义一个整型变量,如果不知道存储什么值,可以将a初始化为0int a = 0;// 定义一个指针变量p,如果不知道指针存储谁的地址可以将其// 初始化为0指针,将指针指向0地址,0x00000000 -- NULLint *p = NULL;// *p = 200; // 也不对,p保存了0x000000000,0x00000000是进行初始化的标记,该地址指向的空间不存储值// NULL是指针初始化的标记,指针p指向NULL,表示该指针初始化了,该指针可以使用,// 如果指针 p !== NULL 表明该指针没有初始化,不能使用(或者该指针指向其他地址空间)// 好习惯:将指针用完之后将指针变量指向NULLif(p == NULL)  {p = &a;}system("pause");return 0;}

野指针和空指针总结

指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位为4字节,64位为8字节),但是,任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。

int a = 100;int *p;        // p中保存的地址是a的值p = a; //把a的值赋值给指针变量p,p为野指针, ok,不会有问题,但没有意义                // p中保存的地址是任意给的p = 0x12345678; //给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义*p = 1000;  //操作野指针指向未知区域,内存出问题,err

但是,野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向任何变量(空闲可用),C语言中,可以把NULL赋值给此指针,这样就标志此指针为空指针,没有任何指针。

int *p = NULL;

NULL是一个值为0的宏常量:

#define NULL    ((void *)0)

3. 万能指针

  • 可以保存任何地址的指针
  • void *p
#include #include #include int main(){// 万能指针,可以保存任意的地址int a = 10;        void *p;        p = (void *)&a;        // printf("%d\n",*p); // 编译出错,指针的类型是void *,取出的长度为sizeof(void)        // sizeof(void) -- 编译器不知道多大 -- 编译出错                // p指针变量保存的是a的地址,p的类型是void *类型        // 想要取出p中的变量 -- 需要将p指针类型从void * 转为int *        printf("%d\n",*(int *)p); // *(地址) -- 将地址进行强转 *((int *)地址)                // 不可以定义void类型的变量        // 但是可以定义void *类型,因为指针都是4个字节        // void b; 出错        void *b;system("pause");return 0;}
  • 通过万能指针取内容的时候,需要将万能指针类型转变为取值的指针类型

4.const修饰的指针变量

  • const -- 修饰变量a之后,不能通过a变量名修改a在内存中的值
  • 但是可以通过地址进行修改a的内容
#include #include #include int main(){// const修饰变量a,不能再通过a修改a内存里面的内容// 但是可以同过地址进行修改a的值const int a = 10;int *p = &a;*p = 100;printf("%d\n",a); // 100system("pause");return 0;}
  • const int p = &a -- const修饰,不能通过*p修改指向空间的内容
  • int * const p = &a -- const修饰指针变量p,p中所保存的地址不可被修改
#include #include #include int main(){int a = 10;int b = 20;// const修饰的是*还是变量p?// 这里修饰的是*const int *p = &a;  // 不能通过*p修改p所指向的空间的内容// *p = 100;  const修饰*之后,不能通过p修改p指向的空间的内容// const 修饰指针变量p// p保存的地址不可以被修改int * const p = &a;   p = &b;  // p保存的地址不可以被修改         // p本身的指向不能改变,不同通过*p修改p所指向的空间的内容const int *const p = &a;        system("pause");return 0;}

5.多级指针

#include #include #include int main(){int a = 10;// 定义指针变量p保存a的地址// *p  int a  int *pint *p = &a;// 想要定义一个变量保存p的地址// int *q   int *p    int *(*q)int **q = &p;// 通过q得到a的值// 通过q得到a的地址 -- *q 表示p的地址的内容就是a的地址// **q -- 取a地址中的内容// **q = *(*q) = *(p) = a// **q = *(*q) = *(&a) = a  // *(地址) 表示取地址中的内容// *与&相遇 -- 相互抵消// 定义变量保存q的地址// *k int **q  int ***keyint ***k = &q;// ***k = *(**K) = *(*(*k)) = *(*(&p)) = *p = *(&a) = aint **********g;int ***********h = &g;  // 保存指针类型变量地址,多一个*// ********** *h = ********** *(&g)  = *********g//分析// *与符号结合,表示变量k是一个指针变量// k是一个变量// k的类型// k用来保存地址的类型,将k与最近的*进行拖黑,剩下的就是保存地址的类型system("pause");return 0;}
int a = 10;int *p = &a; //一级指针*p = 100; //*p就是aint **q = &p;//*q就是p//**q就是aint ***t = &q;//*t就是q//**t就是p//***t就是a

6. 指针与数组

#include #include #include int main(){int a[10] = {1,2,3,4,5,6,7,8,9,10};// a 数组名 首元素的地址 - a = &a[0]// 知道首元素地址 --> a+1 = &a[1]// 定义指针保存首元素地址 -- 首元素地址类型是int// a 数组名只能指向首元素地址,通过指针可以指向数组中其他元素地址int *p = a; // &a[0]// *p -- 可以取a[0]的值int *q = &a[5]; // *q 可以取a[5]的值system("pause");return 0;}
#include #include #include int main(){int a[10] = {1,2,3,4,5,6,7,8,9,10};// a 数组名 首元素的地址 - a = &a[0]// 知道首元素地址 --> a+1 = &a[1]// 定义指针保存首元素地址 -- 首元素地址类型是int// a 数组名只能指向首元素地址,通过指针可以指向数组中其他元素地址// 操作数组元素int *p = a;//指针p保存的是首元素地址&a[0]for(int i = 0;i

例题

int main(){  int a[5] = {1,2,3,4,5};  int *ptr = (int *)(&a+1);  printf("%d %d\n",*(a+1),*(ptr-1)); // 2 5}
  • 数组地址加一,跨一个数组
  • 元素地址加一跨一个元素
  • 指针加一跨元素类型步长
  • int *p -- 步长就是sizeof(int)\
  • 要得到内存的数据,就要先得到数据的地址 -- *(地址)得到的是地址中的内容
  • *(指针变量) -- 指针变量存储的是地址 -- *(地址)-- 得到指针变量存储的地址的内容

7.指针的运算

  • 指针的加减运算与步长有关
  • 指针变量相加没有意义
  • 指针变量相减可以得到之间的数组元素
  • 两个指针的变量相减,需要保证指针的类型一致
#include #include #include int main(){int a[10] = {1,2,3,4,5,6,7,8,9,10};int *p = a;// &a+1跨整个数组// &a+1的步长是整个数组,想要前一个元素的地址,在减去一个int类型的变量长度// 将&a+1地址转变为int * -- 表示其步长为sizeof(int)// (int *)(&a+1) - 1 得到数组最后一个元素地址// 得到数组的最后一个元素,(int *)(&a+1) int *q = (int *)(&a+1)-1;// 指针相减 -- 得到之间元素的个数printf("%d\n",q-p); // 9printf("%d\n",*(p+3)); // 取第四个元素的值,4// c语言中,两个指针变量相加是没有意义的printf("%d\n",p+q); // 报错system("pause");return 0;}

8.[]使用

  • []不一定只给数组使用
  • [] == *()
  • p[0] == *(p+0);
#include int mian(){// [] 不是数组的专属// int a[10] = {1,2,3,4,5,6,7,8,9,10};int a = 10;int *p = &a;// [] == *() // p[0] == *(p+0);p[0] = 100;// 这里a = 100,表示p[0] = 100,对其内容进行操作printf("a = %d\n",a); // a = 100system("pause");return 0;}

数组中的使用

#include #include #include int main(){int a[10] = {1,2,3,4,5,6,7,8,9,10};int *p = a;//指针p保存的是首元素地址&a[0]for(int i = 0;i

9.指针数组

指针数组,它是数组,数组的每个元素都是指针类型。

#include #include #include int main(){int a = 10;int b = 20;int c = 30;// 保存三个int类型数据的指针需要定义三个指针// 如果数据多了之后就比较麻烦// int *p = &a int *q = &b  int *k = &c// 需求:数组中的每一个元素都是指针(地址)// 指针变量的类型 数组名[长度] = {初始化值}; 初始化的是地址int *num[3] = {&a,&b,&c};// int *占4个字节printf("%d\n",sizeof(num)); // 12// 用指针数组或区域元素// 打印a的地址printf("a:\n",*num[0]);printf("b:\n",*num[1]);printf("c:\n",*num[2]);for(int i = 0;i

关键词: