指针进阶篇

本文围绕指针展开,介绍了字符指针、指针数组、数组指针等概念,阐述了数组和指针作为函数参数的设计方法,还讲解了函数指针、函数指针数组、指向函数指针数组的指针以及回调函数,最后对指针和数组的笔试题进行了解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.字符指针

  1. 指针就是个变量,用来存放地址,地址是唯一的标识空间,内存单元有编号,编号=地址=指针
  2. 指针固定4/8字节(32位/64位)
  3. 指针有类型,类型觉得指针+1-1时的步长,决定了指针解引用时访问的大小

2.指针数组

指针数组是数组
字符数组–存放字符的数组
整型数组–存放整型的数组
指针数组–存放指针的数组,数组中的元素都是指针元素的
int* arr[5] char* ch[6]

3.数组指针

指针数组是数组,是存放指针的数组
数组指针是指针
字符指针–指向字符的指针
整型指针–指向整型的指针
浮点型指针-指向浮点型的指针
数组指针–指向数组的指针

数组名理解:数组名是数组首元素的地址,但是存在两个例外

  1. sizeof(数组名),这里表示整个数组,所以计算的是整个数组所占大小,单位为字节
  2. &数组名,这里数组名表示整个数组,取出的是数组的地址
int main(){
    int arr[10]={0};
    int (*p)[10]=&arr;
    char *arr2[5];
    char* (*pc)[5]=&arr2;
    char arr3[5];
    char(*p3)[5]=&arr3;
    return 0;
}

数组指针到底有什么用?

sizeof数组指针可以获得数组的全部长度,所以数组指针存放的是数组的地址,而不是数组首元素的地址。

一维数组传参

//数组作为形参时,长度可以不写
void prints(int arr[],int sz){
    for (int i = 0; i < sz; i++)
    {
      printf("%d ",arr[i]);
    }
    
}
//一维数组传参传递首元素的地址,本质是指针,可以用int指针接收
void prints1(int* arr,int sz){
    for (int i = 0; i < sz; i++)
    {
      printf("%d ",arr[i]);
    }
    
}
int main(){
  int arr[]={1,2,3,4,5};
  int sz=sizeof(arr)/sizeof(arr[0]);
  prints1(arr,sz);
  return 0;
}

二维数组传参

void print(int arr[][5],int r,int c){
  for (int i = 0; i < r; i++)
  {
    for (int j = 0; j < c; j++)
    {
      printf("%d ",arr[i][j]);
    }
    printf("\n");
  }
  

}
//传递第一行数组的地址,可以用数组指针接收
void print(int (*arr)[5],int r,int c){
  for (int i = 0; i < r; i++)
  {
    for (int j = 0; j < c; j++)
    {
      printf("%d ",*(*(arr+i)+j));
    }
    printf("\n");
  }
  

}
//二维数组传参 传递二维数组的数组名其实是传递二维数组的首元素地址,也就是第一行数组整体的地址,注意不是第一行数组第一个元素的地址
int main(){
  int arr[][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};
  print(arr,3,5);
  return 0;
}

练习

int arr[5];//arr是能存储五个元素的数组
int *parr1[10];//parr1是一个指针数组,元素是整形指针类型,能存储十个元素
int (*parr2)[10];//parr2是数组指针,指向元素个数为10的整型数组的地址。
int (*parr3[10])[5];//parr3是数组,数组的元素是数组指针,每个元素指向长度为5的整型数组。parr可以存储十个数组指针

4.数组参数、指针参数

写代码的时候难免要把数组或指针传给函数,那函数参数该如何设计呢

一维数组传参

#include <stdio.h>
void test(int arr[])//ok 数组传参,形参可以写成数组形式
{}
void test(int arr[10])//ok形参数组的大小可以写错,因为传的本质是地址
{}
void test(int *arr)//ok 本质是首元素的地址,所以可以用指针接收
{}
void test2(int *arr[20])//ok可以用数组接收
{}
void test2(int **arr)//ok 传递的是指针数组首元素的地址,指针数组的首元素是指针类型,用二级指针接收 没问题
{}
int main(){
    int arr[10] = {0};
    int *arr2[20] = {0};
    test(arr);
    test2(arr2);
}

二维数组传参

void test(int arr[3][5])//ok?二维数组作为参数,使用二维数组进行接收
{}
void test(int arr[][])//ok?//二维数组作为参数,必须指定列长度
{}
void test(int arr[][5])//ok?二维数组作为参数,行可以省略
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?传递arr数组名,实际传递的是arr的首元素地址也就是第一行的数组地址,不能使用整型指针接收
{}
void test(int* arr[5])//ok?传递arr数组名,实际传递的是arr的首元素地址也就是第一行的数组地址,可以使用指针数组接收
{}
void test(int (*arr)[5])//ok?传递arr数组名,实际传递的是arr的首元素地址也就是第一行的数组地址,可以使用数组指针接收
{}
void test(int **arr)//ok?二级指针是用来接收一级指针的地址,所以不行 
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}

一级指针传参

void print(int *p, int sz)//一级指针传参,使用一级指针接收就可以
{
int i = 0;
for(i=0; i<sz; i++)
{
printf("%d\n", *(p+i));
}
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9};
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}

当一个函数以一级指针为参数,函数能接收什么参数

void test(int *p);
int a=10;
int *p=&a;
int arr[10];
test(&a);//整形变量的地址
test(p);//传递一级指针
test(arr);//传递一维数组的数组名

二级指针传参

void test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int*p = &n;
int **pp = &p;
test(pp);//传递二级指针
test(&p);//传递一级指针的地址
return 0;
}

当一个函数以二级指针为参数,函数能接收什么函数

void test(int **pp);
int a = 10;
int *p = &a;
int **pp=&p;
test(pp);//可以接收二级指针
test(&p)//可以接收一级指针的地址
int* arr[10];
test(arr)//可以接收指针数组的首元素地址。因为指针数组的元素为指针类型,指针类型的地址就是二级指针。

5.函数指针

数组指针—指向数组的指针—存放的是数组的地址—&数组名得到
函数指针—指向函数的指针—存放的是函数的地址—函数名也是函数的地址

int add(int x,int y){
    return x+y;
}
int main(){
   int (*pf1)(int,int) = add;
   int (*pf2)(int,int) = &add;
//    printf("%d",pf1==pf2);
printf("%d",(pf1)(3,2));
    return 0;
}

6.函数指针数组

int (* p[10])(int),本质上是一个数组
指针数组—char * arr[]存放的是字符指针
整型指针数组—int * arr2[]存放的是整型指针
函数指针数组是数组,数组的元素是函数指针,也就是函数的地址

用函数指针数组完成计算机

#include<stdio.h>
int Add(int x,int y){
    return x + y;
}
int Sub(int x,int y){
    return x - y;
}
int Mul(int x,int y){
    return x * y;
}
int Div(int x,int y){
    return x / y;
}

int main(){
    int input = 1,ret = 0,A1 = 0,A2 = 0;
    int (*cal[5])(int,int)={NULL,Add,Sub,Mul,Div};
    do
    {
        printf("********************\n");
        printf("***1.Add****2.Sub***\n");
        printf("***3.Mul****4.Div***\n");
        printf("***0.Exit***********\n");
        printf("********************\n");
        scanf("%d",&input);
        if (input==0)
        {
           printf("退出系统");
        }else if (input>0&&input<5)
        {    printf("请输入两个数字\n");
             scanf("%d %d",&A1,&A2);
             ret = cal[input](A1,A2);
             printf("ret = %d\n",ret);
            /* code */
        }else{
            printf("输入错误\n");
        }
        
        
    } while (input);
    
    return 0;
}

7.指向函数指针数组的指针

int(* (*p)[10])(int)

int main(){
    int a = 10;
    int b = 20;
    int c = 30;
    int *arr[] = {&a,&b,&c};//整型指针数组
    int (*p)[3] = &arr;//指向整型数组的指针
    //函数指针数组 - 数组 - 存放的是函数的地址
    int (*pfArr[5])(int,int)={NULL,Add,Sub,Mul,Div}; 
    //指向函数指针数组的指针
    int(*(*pF)[3])(int,int) = &pfArr;

}

8.回调函数

依赖函数指针,有函数指针才能实现回调函数
回调函数是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向函数时,我们说这就是回调函数。回调函数不应该由函数的实现方直接调用,而是在特定的事件或条件发生时由另一方调用,对于该事件或条件进行相应。

简单来说就是不可以直接使用函数名+()的形式调用,需要将回调函数的地址传给函数指针,通过函数指针来调用。

通过函数指针调用回调函数

void cals(int (*p)(int,int)){
     int a1,a2;
     printf("请输入两个数字\n");
     scanf("%d %d",&a1,&a2);
     int ret = p(a1,a2);
     printf("ret = %d\n",ret);
}
int main(){
    int input = 1,ret = 0,A1 = 0,A2 = 0;
    // int (*cal[5])(int,int)={NULL,Add,Sub,Mul,Div};
    do
    {
        printf("********************\n");
        printf("***1.Add****2.Sub***\n");
        printf("***3.Mul****4.Div***\n");
        printf("***0.Exit***********\n");
        printf("********************\n");
        scanf("%d",&input);
       switch (input)
       {
       case 1:
        cals(Add);
        break;
        case 2:
        cals(Sub);
        break;
         case 3:
        cals(Mul);
        break;
         case 4:
        cals(Div);
        break;
      case 0:
      printf("退出系统\n");
      break;
      default:
      printf("输入错误,重新输入\n");
      break;
       }
        
        
    } while (input);
    
    return 0;
}

qsort的使用

qsort是头文件stdlib.h中的函数。此函数有四个参数
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
第一个base代表要排序数组的第一个元素的地址一般传入数组名,如果想部分排序,需要获得其实排序元素的地址。
第二个代表要排序的元素的个数
第三个代表要排序数组中的每个元素的大小,以字节为单位
第四个需要传入一个compare函数,compare函数参数必须为void类型的指针。因为qsort()为了对所有类型排序。void类型指针可以接收任何类型的指针。compare的返回值为int。
类型为void的指针补充:类型为void类型的指针不具备访问内存空间的能力。但是此类型指针的特点是可以存储任何类型的指针,后续使用时可以把void类型转换为当时转换前的指针类型。

// int main(){
//     int a = 10;
//     int b = 20;
//     int c = 30;
//     int *arr[] = {&a,&b,&c};//整型指针数组
//     int (*p)[3] = &arr;//指向整型数组的指针
//     //函数指针数组 - 数组 - 存放的是函数的地址
//     int (*pfArr[5])(int,int)={NULL,Add,Sub,Mul,Div}; 
//     //指向函数指针数组的指针
//     int(*(*pF)[3])(int,int) = &pfArr;

// }
struct stu
{
    char name[20];
    int age;
};

// void print_arr(int* arr,int len){
//     for (int i = 0; i < len; i++)
//     {
//         printf("%d ",arr[i]);
//     }
//     printf("\n");
    
// }
// int compare(const void* p1,const void* p2){
//  return *(int*)p1-*(int*)p2;
// }
// int main(){
//     int arr[]={9,8,7,6,5,4,3,2,1};
//     int sz=sizeof(arr)/sizeof(arr[0]);
//     print_arr(arr,sz);
//     qsort(arr,sz,sizeof(arr[0]),compare);
//     print_arr(arr,sz);
//     return 0;
// }
// void print_struct(struct stu *stu,int sz){
//     for (int i = 0; i < sz; i++)
//     {
//         printf("name = %s , age = %d\n",(stu+i)->name,(stu+i)->age);
//     }
    
// }
// int compare(void *p1,void *p2){
//     return ((struct stu*)p1)->age-((struct stu*)p2)->age;
// }
// int compare_str(void *p1,void *p2){
//      return strcmp(((struct stu*)p1)->name,((struct stu*)p2)->name);
// }
// int main(){
//     struct stu Stus[3]={{"zvjing",61},{"xanjiam",20},{"yhangfei",43}};
//     print_struct(Stus,3);
//     // qsort(Stus,3,sizeof(Stus[0]),compare);
//      qsort(Stus,3,sizeof(Stus[0]),compare_str);
//     print_struct(Stus,3);
//     return 0;
// }

9.指针和数组笔试题解析

int main(){
    int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); //a为数组名 sizeof数组名为数组的整体长度,单位为字节 ans=16字节
printf("%d\n",sizeof(a+0));//a+0为数组的首元素地址,sizeof地址为指针的大小,单位是字节 ans=4/8
printf("%d\n",sizeof(*a));//*a为数组的第一个元素,sizeof int ans=4
printf("%d\n",sizeof(a+1));//a+1为数组第二个元素的地址,sizeof地址 ans=4/8
printf("%d\n",sizeof(a[1]));//a[1]为数组的第二个元素,等于sizeof int ans=4
printf("%d\n",sizeof(&a));// &a为数组的地址,sizeof地址 ans=4/8
printf("%d\n",sizeof(*&a));//&a为数组整体的地址,类型为int *p[4],*p为数组的地址,等价于sizeof(a),ans=16
printf("%d\n",sizeof(&a+1));//&a为数组的地址,&a+1会跨国整个数组,ans=4/8
printf("%d\n",sizeof(&a[0]));//&a[0]为数组首元素的地址,ans=4/8
printf("%d\n",sizeof(&a[0]+1));//为第二个元素的地址 ans=4/8
    return 0 ;
}

int main(){
    char arr[] = {'a','b','c','d','e','f'};//字符数组依次赋值,不会自动给末尾加结束符。
    printf("%d\n", sizeof(arr));//arr为数组名。sizeof数组名代表数组的整体长度,单位为字节。ans = 6
    printf("%d\n", sizeof(arr+0));//数组首元素的地址 ans=4/8
    printf("%d\n", sizeof(*arr));//sizeof 第一个元素为a, sizeof('a') ans = 1
    printf("%d\n", sizeof(arr[1]));//sizeof 第二个元素 ans = 1
    printf("%d\n", sizeof(&arr));//sizeof 地址,ans = 4/8
    printf("%d\n", sizeof(&arr+1));//跨越整个数组 ans = 4/8
    printf("%d\n", sizeof(&arr[0]+1));//sizeof 第二个元素的地址 ans=4/8
    return 0;
}
int main(){
    char arr[] = {'a','b','c','d','e','f'};//字符数组依次赋值,不会自动给末尾加结束符。
    printf("%d\n", strlen(arr));//由于不会自动加结束符,所以所以答案为随机值 ans = x x>=6
    printf("%d\n", strlen(arr+0));//为数组首元素的地址,ans = x x>=6
    //printf("%d\n", strlen(*arr));//strlen('a') err
    //printf("%d\n", strlen(arr[1]));//strlen('b') err
    printf("%d\n", strlen(&arr));//虽然&arr的类型为 char *p[6],但是&arr的值和arr的值一样,strlen的参数为const char *p,只会warning。不会影响结果 ans=x x>=6 部分编译器报错
    printf("%d\n", strlen(&arr+1));//&arr+1跨越了整个数组 ans=x-6 部分编译器报错
    printf("%d\n", strlen(&arr[0]+1));//从第二个元素开始 ans = x-1
    return 0;

}
int main(){
    char arr[] = "abcdef";//通过这种形式给字符串赋值,会自动在结尾加结束符
    printf("%d\n", sizeof(arr));//sizeof数组名 获取数组的长度 单位为字节 ans = 7 因为又结束符
    printf("%d\n", sizeof(arr+0));//为数组首元素的地址 ans=4/8
    printf("%d\n", sizeof(*arr));//sizeof('a') ans = 1
    printf("%d\n", sizeof(arr[1]));//sizeof('b') ans = 1
    printf("%d\n", sizeof(&arr));//&arr为数组的地址 ans=4/8
    printf("%d\n", sizeof(&arr+1));//&arr+1跨域整个数组 ans=4/8
    printf("%d\n", sizeof(&arr[0]+1));//为第二个元素地址 ans = 4/8
    return 0;

}

int main(){
    char arr[] = "abcdef";//通过这种形式给字符串赋值,会自动在结尾加结束符
    printf("%d\n", strlen(arr));//判断结束符前的字符 ans = 6
    printf("%d\n", strlen(arr+0));//从第一个元素到最后一个元素 ans = 6
    // printf("%d\n", strlen(*arr));//strlen的参数为char * *arr='a' err
    // printf("%d\n", strlen(arr[1]));//arr[1]='b',b
    printf("%d\n", strlen(&arr));//ans = 6
    printf("%d\n", strlen(&arr+1));//随机值
    printf("%d\n", strlen(&arr[0]+1));//从第二个元素到最后 ans = 5
    return 0;
}
int main(){
    char *p = "abcdef";//实际上p存储的是字符a的地址
    printf("%d\n", sizeof(p));//p存储的是a的地址 ans=4/8
    printf("%d\n", sizeof(p+1));//存储的是b的地址 ans=4/8
    printf("%d\n", sizeof(*p));//*p为字符a,ans = 1
    printf("%d\n", sizeof(p[0]));//p[0]==*p ans = 1
    printf("%d\n", sizeof(&p));//&p为指针的地址 ans=4/8
    printf("%d\n", sizeof(&p+1));//跨越一个指针的距离 ans=4/8
    printf("%d\n", sizeof(&p[0]+1));//指向b的地址 ans=4/8
    return 0;
}
int main(){
    char *p = "abcdef";//实际上p存储的是字符a的地址,自动补充结束符
    printf("%d\n", strlen(p));//a开始到f结束 ans=6
    printf("%d\n", strlen(p+1));//b开始 ans=5
    // printf("%d\n", strlen(*p));//strlen参数为char 不是字符'a' *p err
    // printf("%d\n", strlen(p[0]));//strlen参数为char 不是字符'a'  *p err
    // printf("%d\n", strlen(&p));//,p为指针,取指针的地址没有意义,随机值 
    // printf("%d\n", strlen(&p+1));//p地址+1 随机值
    printf("%d\n", strlen(&p[0]+1));//b-f anns=5
    return 0;
}

int main(){
    int a[3][4] = {0};
printf("%d\n",sizeof(a));//sizeof数组名获得的是数组整体的大小,数组一共十二个元素所以ans = 48
printf("%d\n",sizeof(a[0][0]));//a[0][0]为数组第0行的第0个元素,类型为int ans = 4
printf("%d\n",sizeof(a[0]));//a[0]为数组第0行的数组名,sizeof数组名代表数组整体的大小,也就是第0行的大小 ans = 16
printf("%d\n",sizeof(a[0]+1));//a[0]为数组第0行的数组名,这里是第0行的首元素地址,加一之后为第0行第一个元素的地址 ans = 4/8
printf("%d\n",sizeof(*(a[0]+1)));//为第0行第一列元素的值,ans = 4
printf("%d\n",sizeof(a+1));//这里a代表首元素的地址,也就是第0行的地址,加一变成第一行的地址,ans = 4/8
printf("%d\n",sizeof(*(a+1)));//a+1代表第1行的地址,解引用代表第1行的数组名。 ans = 16
printf("%d\n",sizeof(&a[0]+1));//a[0]代表数组第0行的数组名,对数组名&获得的是整个数组的地址,在加一变成第1行数组的地址 ans = 4/8
printf("%d\n",sizeof(*(&a[0]+1)));//代表第一行的数组名 ans = 16
printf("%d\n",sizeof(*a));//代表第一行的数组名 ans = 16
printf("%d\n",sizeof(a[3]));//sizeof不会真实访问a[3] 等价于sizeof(a[1]) ans = 16 
    return 0;
}

总结:数组名的意义

  1. 数组名单独放在sizeof中时,计算的时数组的长度
  2. &数组名,取出的是数组的地址,类型为int(*)[]
  3. 除此之外,数组名都表示数组首元素的地址

10.指针笔试题

1

int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?

&a获得的是数组的地址,&a+1会跨越整个数组,也就是指向数组最后一个元素的下一个位置。然后将&a-1强转成int*。ptr-1就指向了5的地址。a代表数组首元素的地址,a+1就代表第二个元素的地址。所以输出 2,5。

2

struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}

p为结构体类型的指针,p+1应该跳过一个结构体类型的大小也就是20字节。所以p+1=00100014
把p转换成int,那么p+1就是+1。p=00100001
把p转换为int*,p+1跳过整型的大小。p=00100004;

3

int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}

对数组使用取地址符(&),可以获得数组的地址,那么&a+1就指向了4后面那个元素的地址,随后被强转成了int*。ptr[-1]等于*(ptr-1)就等于4。小端存储就低位存在低地址,高位存在高地址。所以*ptr2从第二个字节开始向后四个字节。输出200000

4

#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}

数组里的元素为逗号表达式。实际上存储的值为 1,3,5。p=a[0],p存储的是数组首元素的地址也就是第一行的地址。p[0]等于第一行的第0个元素,也就是1

5

int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}

p和a都是地址,地址-地址代表中间相差了几个元素。之间差了四个元素所以%d的差值为-4,16进制的-4为FFFFFFFC,

6

int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}

&aa可以获取数组的地址。&aa+1就指向了10后面的那个元素的地址。*(ptr-1)就等价于指向了10。aa代表数组首元素的地址。aa+1代表指向了第二行。*(aa+1)就获得了第二行的数组名。第二行第一个元素的地址-1就等于上一行最后一个元素的地址所以输出5

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5C%E6%96%B0%E5%BB%BA%E6%96%87%E4%BB%在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
B6%E5%A4%B9%5Cimage-20230917201846110.png&pos_id=img-y6dLumcB-1694959831595)

7

int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}

pa是存放char*类型的指针。pa++应该跳过一个char*指针类型,指向存放at的指针,所以输出at

8

int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}

**++cpp,cpp存储的是char**类型的变量,++cpp将cpp指针向后移动一位指向c+2的地址*cpp指向c+2,**cpp代表c+2的地址。也就是P的地址,所以输出POINT
此时cpp指向c+2的地址,*++cpp=c+1.*–c+1+3=*c+3=E的地址,所以输出ER
cpp[-2]=cpp指针向前移动两个元素,等于c+3,*(c+3)=P的地址,在加三等于S的地址,输出ST
cpp[-1]表示cpp指向向前移动一个元素,等于c+2,*(c+2-1)=*(c+1)=N的地址,加一等于E的地址,输出ew

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值