C++指针讲解

概念
指针:是一个变量,其值为地址,必须要为其初始化
声明指针或者不在使用后都要将其置为0 (NULL)
野指针:未初始化的指针
悬空指针:指针最初指向的内存已经被释放的一种指针
指针在32位机器上 占4个字节 64位占8个字节

1.指针基本使用

&号 用来取一个对象的地址
*号 一个间接寻址符,用于访问指针所指向的地址的值。

    int *p;
    int a = 200;
    p = &a;    //指针初始化  p地址指向a
    *p = 100;
    printf("a = %d \n",a);
    printf("*p = %d\n",*p);
    a=300;    
    printf("a = %d \n",a);
    printf("*p = %d\n",*p);
    printf("p的地址:[%x]  a的地址[%x]\n",p,&a);
输出:
a=100
*p=100
a=300
*p=300    

2.*p++ (*p)++ *++p ++*p 区别

*p++ :先取指针p指向的值,p在自身+1
(p)++ :先取p指向的值,在将该值+1 (不是将p的地址+1,是将p加1)
++p : 先将指针p的地址+1,在取该p的值
++*p : 先取p指向的值,在将该值+1

例如:p1 p2 p3 p4 都指向数组attr
int attr[] = {3,10,15,20,25,40};
int *p1= attr;
int *p2= attr;
int *p3= attr;
int *p4= attr;         //printf计算从右向左  ←
printf("*p1++: %d  %d\n",*p1++,*p1); //*p1=3 *p1 p1++  打印 3 3 
printf("(*p2)++ : %d   %d\n",(*p2)++,*p2);//*p2=3 *p2=*p2+1 4
printf("*++p3   : %d   %d\n",*++p3,*p3); //*p3=4 p3++ *p3=10
printf("++*p4   : %d   %d\n",++*p4,*p4);  //*p4=4 *p4=*p4+1 5
printf("attr[0] :  %d\n",attr[0]);//5
printf("attr地址:%x  p1[%x] p2[%x] p3[%x] p4[%x]\n",attr,p1,p2,p3,p4);
//attr地址:61fdd0  p1[61fdd4] p2[61fdd0] p3[61fdd4] p4[61fdd0]   
attr是数组attr首个元素的地址,int4字节,每次地址+1,都加4字节

在次举例:
    int array[]={1,2,3,4,5,6};
    int *ptr_1= (int *)(&array+1);
    printf("array[%x] array+1[%x] *(array+1)[%d] \n &array[%x] &array+1[%x] *(&array+1)[%d]\n ptr_1[%x] ptr_1-1[%x] *(ptr_1-1)[%d]\n",
    array,array+1,*(array+1),&array,&array+1,*(&array+1),ptr_1,ptr_1-1,*(ptr_1-1));
    //array   :数组的首个元素的地址
    //array+1 :数组首个元素地址+1 array[1] 的地址
    //&array  :数组首元素地址
    //&array+1:数组首元素地址+1,地址:array+array*sizeof(int)*6
    //ptr_1   :数组的首元素+1的地址
    //ptr-1 -1:数组的首元素+1的地址 - sizeof(int)  
打印:
array[61fd70] array+1[61fd74] *(array+1)[2]
&array[61fd70] &array+1[61fd88] *(&array+1)[6421896]
ptr_1[61fd88] ptr_1-1[61fd84] *(ptr_1-1)[6]
    

3指针常量 常量指针 指向常量常量指针

int *p : 整型指针 表示指向整形的指针
int const *p : 常量指针 表示指针指向的值不可修改
int * const p : 指针常量 表示指针指向的地址不可修改
const int * const p 指向常量的指针常量 表示值和地址都不可变

int a11 = 200;
int a12 = 300;
int *p11 = 100;                //(1)整形指针
int * const ptr11 = &a11;      //(2)指针常量
//ptr11 = a12;                 错误指针指向的地址不可改变
int const *ptr12 = &a12;       //(3)常量指针
//*ptr12 = 100;                 错误指针指向的值不可改变

3 野指针使用注意

int *pointt;
*pointt=100; //不允许 这样做

4通用指针

1int com = 100;
int *p_com = &com;
void *comm = p;// 把一个整形指针转化成通用指针,它的指向地址不会改变,但是类型会丢失
int *common = (int *)comm;
printf("common :[%d] \n",*common);2typedef struct
{
   int num;
   char buff[1024];
}MSG;
void funcomon(void *point) {
    MSG *msg = (MSG *)point;
    if(msg!=NULL) {
      printf("MSG [%d] [%s]\n",msg->num,msg->buff);
      msg->num = 111111;
      memcpy(msg->buff,"abcd",10);
    }
}

5 指针的算术运算(指针步长)

++ - -

   // int 型指针步长sizeof(int)  4
    int a = 100;
    int *p = &a;
    printf("p   [%p]\n",p);
    printf("p+1 [%p]\n",p+1); 
    printf("p+2 [%p]\n",p+2);
    printf("p+3 [%p]\n",p+3);
   // char 型指针步长 sizeof(char) 1
    char c = 'a';
    char *pc = &c;
    printf("pc   [%p]\n",pc);
    printf("pc+1 [%p]\n",pc+1);
    printf("pc+2 [%p]\n",pc+2);
    printf("pc+3 [%p]\n",pc+3);
    //void 型指针步长1
    int v = 100;
    void *vv =(void *) &v;     
    printf("vv   [%p]\n",vv); //void类型 步长为1
    printf("vv+1 [%p]\n",vv+1);
    printf("vv+2 [%p]\n",vv+2);
    printf("vv+3 [%p]\n",vv+3);

6 指针与数组

6.1指针与一维数组

例如:
int a[3];

a &a a+1 &a+1
a :代表数组首个元素的地址 = &a[0]
a+1 :代表数组首个元素的地址+1,即为&a[1]的 地址

&a :代表的是数组首地址
&a+1:代表数组首地址+1,即&a[0] 的地址 + 40

1int array[] = {1,2,3,4,5,6}; //数组名就是数组的起始地址,数组名就是一个常量指针
int *ptr_array = array;
//打印地址
printf("address: [%x] [%x] [%x] [%x] \n",array+3,&array[3],ptr_array+3,&ptr_array[3]);   //代表同一个地址,第3个元素的地址
//打印值
ptr_array[1] = 100;
printf("value: [%d] [%d] [%d] [%d] [%d] [%d]\n",array[1],*(array+1),ptr_array[1],*(ptr_array+1),*&array[1],*&ptr_array[1]);//代表同一个值
//地址打印
printf("array[%x] &array+1 [%x] &ptr_array+1 [%x] \n",array,&array+1,ptr_array+1);
//array:首地址  &array+1:取首地址+1:+1是加整个数组+24      ptr_array+1 :表示首地址+四个字节

输出:
address: [61fdfc] [61fdfc] [61fdfc] [61fdfc]
value: [100] [100] [100] [100] [100] [100]
array[61fdf0] array+1[61fdf4] &array+1 [61fe08] &ptr_array+1 [61fdf4]2
int array[]={1,2,3,4,5,6};
int *ptr_1= (int *)(&array+1);
printf("array[%x] array+1[%x] *(array+1)[%d] \n &array[%x] &array+1[%x] *(&array+1)[%d]\n ptr_1[%x] ptr_1-1[%x] *(ptr_1-1)[%d]\n",array,array+1,*(array+1),&array,&array+1,*(&array+1),ptr_1,ptr_1-1,*(ptr_1-1));
//array   :数组的首个元素的地址
//array+1 :数组首个元素地址+1 array[1] 的地址
//&array  :数组首元素地址
//&array+1:数组首元素地址+1,地址:array+array*sizeof(int)*6
//ptr_1   :数组的首元素+1的地址
//ptr-1 -1:数组的首元素+1的地址 - sizeof(int)  
打印:
array[61fd70] array+1[61fd74] *(array+1)[2]
&array[61fd70] &array+1[61fd88] *(&array+1)[6421896]
ptr_1[61fd88] ptr_1-1[61fd84] *(ptr_1-1)[6]

6.1.1 一维数组函数传参

一般的函数传参分为传值和传址,传值意味着对实参没有影响,仅仅是对拷贝进行操作;传址意味着可以访问实参指针所指向的值,也可以对其进行操作。
数组传参比较有趣的地方在于既是传址也是传值。传址是传递数组的地址或首元素的地址,可以通过该指针对数组进行间接访问,也修改数组值;传值是因为,对形参指针的操作并不影响实参指针。
2种方式:
void pointOneArg1(int *attr)
void pointOneArg2(int attr[])

void pointOneArg1(int *attr) {
    printf("pointOneArg [%d]\n",sizeof(attr));
    *attr = 100;
}
void pointOneArg2(int attr[]) {
    printf("pointOneArg1 [%d]\n",sizeof(attr));
    attr[5]=111;
}

   int ptr_arg[10] = {1,2,3,4,5,6,7,8,9};
   for (size_t i = 0; i < sizeof(ptr_arg)/sizeof(ptr_arg[0]); i++){
       printf("[%d] ",ptr_arg[i]);
   }
   printf("\n");
   pointOneArg1(ptr_arg);
   for (size_t i = 0; i < sizeof(ptr_arg)/sizeof(ptr_arg[0]); i++){
       printf("[%d] ",ptr_arg[i]);
   }
   printf("\n");
   pointOneArg2(ptr_arg);
   for (size_t i = 0; i < sizeof(ptr_arg)/sizeof(ptr_arg[0]); i++){
       printf("[%d] ",ptr_arg[i]);
   }
   printf("\n");

//打印:
[1] [2] [3] [4] [5] [6] [7] [8] [9] [0]
pointOneArg [8]
[100] [2] [3] [4] [5] [6] [7] [8] [9] [0]
pointOneArg1 [8]
[100] [2] [3] [4] [5] [111] [7] [8] [9] [0]

6.2 指针与二维数组

int a[6][10];
1:访问地址
a:第一行元素的地址
a+n:表示第n+1行元素地址

*a和a[0]:表示第一行第一个元素的地址,&a[0][0]表示第一行第一个元素的地址,因此a=&a[0]=&(&a[0][0]),a表示地址的地址
*(a+n)+n和a[n]+n: 表示第n+1行第n+1个元素地址

2:访问元素
a[n][n]和*(*(a+n)+n) :访问第n+1行第n+1个元素,可以用

   
 int array2[][3]={1,2,3,4,5,6,7,8,9};
    //array2    行地址  array2+1 表示第1行的地址
    //array2[0]  *array2 表示第0行第0个元素的地址
    //array2[0]+1 *(array2)+1  表示0行第1个元素的地址
    //array2[1][1]  *(*(array2+1)+1)  1行1列的值
    printf("[%x]  [%x]\n",array2,array2+1); //表示0行地址  1行地址
    printf("[%x]  [%x]\n",array2[0],array2[1]);//0行0列地址  1行0列地址
    printf("[%x] [%x]\n",array2[0]+1,*(array2+1)+1);//同上
 printf("[%d] [%d]\n",array2[1][1],*(*(array2+1)+1));
输出:
[61fdd0]  [61fddc]
[61fdd0]  [61fddc]
[61fdd4] [61fde0]
[5] [5]

6.2.1 二维数组函数传参

二维数组int a[2][3]中a是一个指向整型数组的指针,又名数组指针。
int a[2][2];
int(*p)[2] = a;

多维数组进行函数传参时,下面两种形式任选一种即可
void func(int (*p)[2]); 数组指针(行指针)
void func(int p[][2]);

 int array_2[][3]={{1,2,3},{11,22,33},{111,222,333}};
   //地址打印
   printf("行地址 [%x] [%x]\n",array_2,array_2+1);//表示行地址
   printf("行的0元素地址 [%x] [%x]\n",array_2[0],array_2[1]);
   printf("行的0 ,1元素地址 [%x] [%x]\n",*(array_2),*(array_2+1));
   printf("1行1个元素地址 [%x]\n",*(array_2+1)+1);

//打印:
行地址 [61fd80] [61fd8c]
行的0元素地址 [61fd80] [61fd8c]
行的0 ,1元素地址 [61fd80] [61fd8c]
11个元素地址 [61fd90]

7 数组指针与指针数组

概念:
指针数组
int *a[10] : 本质上就是数组元素是是个int型指针的一维数组,先找到声明符a,然后向右看,有[ ]说明a是个数组,再向左看,是int *,说明数组中的每个元素是int *。所以这是一个存放int指针的数组。

数组指针
int (a)[10] : a是指针,指向一个数组。此数组有10个int型元素,先找到声明符a,被括号括着,先看括号内的(优先级高),然后向右看,没有,向左看,是,说明a是个指针,什么指针?再看括号外面的,先向右看,有[ ] 是个数组,说明a是个指向数组的指针,再向左看,是int,说明数组的每个元素是int。所以,这是一个指向存放int的数组的指针。

7.1 数组指针

数组指针练习
数组指针本身就是二维指针,表示的是行指针, 指向一维二维数组的行指针。
数组指针指向一维时
int a[]={1,2,3};
int (*ptr)[3] = &a; //行指针地址
数组指针指向二维时
int a[][3] ={1,2,3,4,5,6,7,8,9,10};
int (*ptr)[3];
ptr=a; //行指针地址

    //数组指针 与一维数组
    int array_1[]= {1,2,3,4,5,6,7,8,9,10};
    int (*ptr_1)[10]=&array_1;          //必须要取地址,取的是首地址
    printf("[%d] [%d] [%d] [%d] [%d]\n",ptr_1[0][0],ptr_1[0][1],ptr_1[0][2],ptr_1[0][3],ptr_1[0][4]);
    
    //数组指针与二维数组
    int array1[][3]={1,2,3,4,5,6,7,8,9};//定义 x 行 3 列的数组
    int (*ptr)[3]=array1;
    //打印值
    printf("%d %d %d %d\n",array1[0][0],ptr[0][0],*(*(array1+1)+1),*(*(ptr+1)+1));//打印0行0列  1行1列的值
    ptr++;//行地址+1
    printf(" %d \n",*(*(ptr)));//表示1行0列的值  4
输出:
[1] [2] [3] [4] [5]
1 1 5 5
4

7.2指针数组(元素指针)

指针数组与一维数组
int array2[3] = {12,3};
int *ptr[2];
ptr[0]=array2;

指针数组与二维数组
int *ptr_22[3];
int array22[][2] ={1,2,3,4,5,6};
for (size_t i = 0; i < sizeof(array22)/sizeof(array22[0]); i++)
ptr_22[i] = array22[i];//将i行第0个元素的地址赋给指针数组

    //指针数组与一维数组(指针数组指向一维数组的,元素指针)
    int array2[] = {1,2,3,4,5,6,7};
    int *ptr_2[2];
    ptr_2[0] = array2; //首行第一个元素的地址
    printf("%d %d\n",ptr_2[0][0],ptr_2[0][1]);
    
//指针数组与二维数组(指针数组 指向二维数组的元素指针)
    int *ptr_22[3];
    int array22[][2] ={1,2,3,4,5,6};
    for (size_t i = 0; i < sizeof(array22)/sizeof(array22[0]); i++){
        ptr_22[i] = array22[i];//将i行第0个元素的地址赋给指针数组
    }
    
    for (size_t i = 0; i < 3; i++)
    {
        for (size_t j = 0; j < 2; j++)
        {
            printf("[%d]",ptr_22[i][j]);
        }
    }

输出:
1 2
[1][2][3][4][5][6]

8.指针的指针

一般用作函数参数
例如:

void fun(char *str,int *indx,char c,char **strr) {//strr n会把修改后的值带回
    int i=0;
    while (*str!=NULL)
    {
        if (*str == c)
        {
            *strr = str;
            *indx = i;
            break;
        }
        i++;
        str++;
    }
}
    int a = 100;
    int *ptr = &a;
    int **ptrr = &ptr;
    printf("[%d] [%d] [%d]\n",a,*ptr,**ptrr);


    char str[] = "hanbaf baop bmkand aob";
    char *strr = NULL;
    int indx;
    fun(str,&indx,'k',&strr);//找到下标以k开头,在把k之后的打印出来
    printf("[%d] [%s]\n",indx,strr);

输出:
[100] [100] [100]
[14] [kand aob]

9.函数指针

一般用作回调,JNI编程
在C++中,作为回调函数,必须为静态

//函数指针
void callback(int a,int b) {
    printf("函数指针回调 [%d] [%d]\n",a,b);
}

typedef void (*CallBack)(int a,int b);//定义两种方式
typedef void (CallBack1)(int a,int b);

void Func(int ID,CallBack callback) {
    callback(10,20);
}
  
Func(1,callback);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值