整理指针相关练习

简介: strlen是求字符串长度的,统计的是\0之前出现的字符个数,一定要找到\0才能结束,所以可能存在越界访问的可能

这里收录的是相关指针的练习,主要针对的是指针与sizeof之间的练习,练完你对指针的理解将更进一层喔


一维数组指针练习


一维数组相关练习,下面答案是多少呢,为什么呢?


int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));


解析:


int main()
{
  //一维数组
  int a[] = { 1,2,3,4 };
  printf("%d\n", sizeof(a));
  //16
  //a为数组名,但在sizeof(数组名)表示的计算整个数组的大小
  printf("%d\n", sizeof(a + 0));
  //4或8
  //首元素地址
  printf("%d\n", sizeof(*a));
  //4
  //首元素解引用--第一个元素1的大小为4字节
  printf("%d\n", sizeof(a + 1));
  //4或8
  //第二个元素的地址
  printf("%d\n", sizeof(a[1]));
  //4
  //第二个元素2,4字节
  printf("%d\n", sizeof(&a));
  //4或8
  //&数组名表示取出的是整个数组的地址,地址的大小就是4或8
  printf("%d\n", sizeof(*&a));
  //16
  //*和&抵消还是a,sizeof(数组名)表示计算整个数组大小
  printf("%d\n", sizeof(&a + 1));
  //4或8
  //&a取出的是整个地址大小,+1也是加上整个数组地址大小,但地址大小就是4或8
  printf("%d\n", sizeof(&a[0]));
  //4或8
  //a[0]就是   *(a+0)就是第一个元素,然后再取地址,就是首元素地址了
  printf("%d\n", sizeof(&a[0] + 1));
  //4或8
  //第二个地址
  return 0;
}


答案:


b0a5e5cd52974cce891a7d39d15c2960.png


字符数组指针练习


字符数组相关练习,下面答案是多少呢,为什么呢?


1.


char arr[] = { 'a','b','c','d','e','f' };
  printf("%d\n", sizeof(arr));
  printf("%d\n", sizeof(arr + 0));
  printf("%d\n", sizeof(*arr));
  printf("%d\n", sizeof(arr[1]));
  printf("%d\n", sizeof(&arr));
  printf("%d\n", sizeof(&arr + 1));
  printf("%d\n", sizeof(&arr[0] + 1));
  printf("%d\n", strlen(arr));
  printf("%d\n", strlen(arr + 0));
  printf("%d\n", strlen(*arr));
  printf("%d\n", strlen(arr[1]));
  printf("%d\n", strlen(&arr));
  printf("%d\n", strlen(&arr + 1));
  printf("%d\n", strlen(&arr[0] + 1));


解析:


int main()
{
  char arr[] = { 'a','b','c','d','e','f' };
  printf("%d\n", sizeof(arr));
  //6
  //sizeof(数组名)表示计算的是整个数组大小为6字节
  printf("%d\n", sizeof(arr + 0));
  //4或8
  //这里arr+0表示首元素地址
  printf("%d\n", sizeof(*arr));
  //1
  //这里的arr表示首元素地址,*arr表示第一个元素'a'
  printf("%d\n", sizeof(arr[1]));
  //1
  //表示第二个元素'b'
  printf("%d\n", sizeof(&arr));
  //4或8
  //&arr表示取出的是整个数组地址,但还是地址
  printf("%d\n", sizeof(&arr + 1));
  //4或8
  //&arr表示取出的整个数组大小,+1表示加上整个数组大小地址
  printf("%d\n", sizeof(&arr[0] + 1));
  //4或8
  //第二个元素地址
  printf("%d\n", strlen(arr));
  //这里要注意strlen是专门用来计算字符大小的函数,遇到'\0'停止,而arr这个数组没有\0
  //所以这个为随机值
  printf("%d\n", strlen(arr + 0));
    //无\0,所以为随机值
  printf("%d\n", strlen(*arr));
  //对首元素解引用,访问的是第一个元素,strlen('a')->strlen('97')---非法访问
  //strlen()里面放的应该是一个地址,然后strlen跟着这个地址往后找,找到\0就停止了
  //但这里strlen('a')里放的不是地址,而是97这个数,所以造成非法访问。
  printf("%d\n", strlen(arr[1]));
  //第二个元素strlen('b')->strlen('97')---也是非法访问。
  printf("%d\n", strlen(&arr));
  //&arr表示取出的是整个数组地址,但不知道后面是否有\0,所以还是随机值
  printf("%d\n", strlen(&arr + 1));
  //这里的arr表示首元素地址,&首元素地址,取出一个地址,这个地址指向的是arr首元素地址,再+1呢,也不知道这个地址是啥了
  //还是随机值
  printf("%d\n", strlen(&arr[0] + 1));
  //&arr[0]+1,第二个元素地址,后面无\0,为随机值。
  return 0;


2.


char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));


解析:


int main()
{
  char arr[] = "abcdef";
  //这里是有\0的
  printf("%d\n", sizeof(arr));
  //7
  //sizeof()计算整个数组大小,\0也算大小而strlen不算\0
  printf("%d\n", sizeof(arr + 0));
  //4或8
  //首元素地址
  printf("%d\n", sizeof(*arr));
  //第一个元素大小 1
  printf("%d\n", sizeof(arr[1]));
  //第二个元素大小 1
  printf("%d\n", sizeof(&arr));
  //&arr取出的是整个数组的地址,还是地址
  printf("%d\n", sizeof(&arr + 1));
  //4或8
  //地址
  printf("%d\n", sizeof(&arr[0] + 1));
  //4或8
  //第二个元素地址
  printf("%d\n", strlen(arr));
  //首元素地址,后面有\0可以停止
  //6
  printf("%d\n", strlen(arr + 0));
  //6
  //首元素地址
  printf("%d\n", strlen(*arr));
  //第一个元素strlen(a)-->strlen(97)
  //非法访问了
  printf("%d\n", strlen(arr[1]));
  //第二个元素
  //非法访问
  printf("%d\n", strlen(&arr));
  //6
  //&arr取出的是整个数组地址,但&arr地址和首元素地址是一样的然后可以找到\0
  printf("%d\n", strlen(&arr + 1));
  //随机值
  //&arr取出的是整个地址,+1,跳过整个数组地址,不知道后面是否有\0
  printf("%d\n", strlen(&arr[0] + 1));
  //第二个元素地址
  //5
  return 0;
  }


3.`


char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));


解析:


int main()
{
  char* p = "abcdef";
//  p表示字符指针,指向的是首元素的地址
  printf("%d\n", sizeof(p));
  //4或8
  //计算首元素地址大小
  printf("%d\n", sizeof(p + 1));
  //4或8
  //第二个元素地址
  printf("%d\n", sizeof(*p));
  //1
  //第一个元素a
  printf("%d\n", sizeof(p[0]));
  //1
  //第一个元素a
  printf("%d\n", sizeof(&p));
  //4或8
  //&p是二级指针,指向的是a的地址的地址
  printf("%d\n", sizeof(&p + 1));
  //4或8 
  //地址
  printf("%d\n", sizeof(&p[0] + 1));
  //4或8
  //第二个元素的地址
  printf("%d\n", strlen(p));
  //6
  //p表示首元素地址,strlen直达\0停止
  printf("%d\n", strlen(p + 1));
  //5
  //从第二个元素地址开始
  //printf("%d\n", strlen(*p));
  *p表示a
  非法访问了
  //printf("%d\n", strlen(p[0]));
  非法访问
  strlen(a)
  printf("%d\n", strlen(&p));
  //二级指针,指向首元素的地址的地址
  //所以为随机值
  printf("%d\n", strlen(&p + 1));
  //随机值
  printf("%d\n", strlen(&p[0] + 1));
  //第二个元素地址
  //5
  return 0;
}


二维数组指针练习


二维数组相关练习,下面答案是多少呢,为什么呢?


    int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));
  printf("%d\n", sizeof(a[0][0]));
  printf("%d\n", sizeof(a[0]));
  printf("%d\n", sizeof(a[0] + 1));
  printf("%d\n", sizeof(*(a[0] + 1)));
  printf("%d\n", sizeof(a + 1));
  printf("%d\n", sizeof(*(a + 1)));
  printf("%d\n", sizeof(&a[0] + 1));
  printf("%d\n", sizeof(*(&a[0] + 1)));
  printf("%d\n", sizeof(*a));
  printf("%d\n", sizeof(a[3]));


解析:


int main()
{
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));
  //48
  //sizeof(数组名)表示计算的整个数组大小
  printf("%d\n", sizeof(a[0][0]));
  //4
  //第一行第一个元素大小
  printf("%d\n", sizeof(a[0]));
  //a[0]表示第一行数组名,sizeof(数组名)表示计算的是第一行数组大小
  //16
  printf("%d\n", sizeof(a[0] + 1));
  //a[0]表示第一行数组名,但没有单独放进sizeof()中也没有&,所以表示首元素地址,首元素地址+1表示第二个元素地址
  //4或8
  printf("%d\n", sizeof(*(a[0] + 1)));
  //4
  //(a[0]+1)表示第一行第二个元素地址,解引用访问第二个元素
  printf("%d\n", sizeof(a + 1));
  //a是数组名,表示首元素地址,表示第一行的数组地址,+1表示第二行地址
  //4或8
  printf("%d\n", sizeof(*(a + 1)));
  //16
  //(a+1)表示第二行地址,解引用表示整个第二行元素
  printf("%d\n", sizeof(&a[0] + 1));
  //a[0]表示第一行数组名,&数组名,表示取出的是第一行整个地址,+1跳过整个第一行数组地址大小所以表示第二行地址
  //4或8
  printf("%d\n", sizeof(*(&a[0] + 1)));
  //16
  //第二行数组地址解引用
  printf("%d\n", sizeof(*a));
  //a数组名,没有单独放进sizeof中也没有&,所以表示的是首元素地址,表示第一行地址
  //4或8
  printf("%d\n", sizeof(a[3]));
  //arr[3]表示第四行数组名,单独放进sizeof()内部表示计算整个数组大小
  // a[3]类型是int[4]----sizeof(int[4])  
  // 答案是16,而不是越界访问
  //根据类型来计算大小,不会真实访问内部空间
  //表达式不参与运算,不进行计算
  return 0;
}


练习总结:


  1. sizeof(数组名)表示计算的整个数组大小,数组名单独放进sizeof()才可以
  2. &数组名表示取出的整个数组的地址
  3. 处以上两个情况,其他数组名都表示首元素地址。
  4. sizeof()内部不参与运算,不进行真实的空间访问
  5. sizeof() 只关注占用内存空间的大小,单位是字节,不关心内存中放的是什么
  6. strlen是求字符串长度的,统计的是\0之前出现的字符个数,一定要找到\0才能结束,所以可能存在越界访问的可能
  7. sizeof 是操作符 strlen是库函数


指针笔试真题


第一题:考察&数组名表示什么意思


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


结果:


603931d71a25401891884f5202c309bd.png


解析


int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int* ptr = (int*)(&a + 1);
    //ptr是个int*类型的指针,这里的&a表示取出的是整个数组的地址再+1的话,表示跳过整个数组大小的地址
    //(&a+1)的类型是数组指针,然后这里将它强制类型转化成int *类型
    printf("%d,%d", *(a + 1), *(ptr - 1));
    //*(a+1),这里的a表示首元素地址,+1表示第二个元素地址,解引用访问第二个元素,2
    //*(ptr-1),ptr被强制类型转换成int*类型,减1后就访问到最后一个元素的地址了
    return 0;
}


总结:

&数组名表示取出的是整个数组的地址,+1表示跳过整个数组大小。


788214aaf83240e6a6d099d29529aa7a.png


第二题:考察指针加1到底加多少?


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


结果:


44b49e30499a481da944af7f19fd8217.png


解析:


int main()
{
  p = (struct Test*)0x100000;
  printf("%p\n", p + 0x1);
  //p+1取决于指针类型,这个指针是结构体类型大小为20,所以加1就跳过一个结构体大小20
  //16进制的20为14
  //0x100014
  printf("%p\n", (unsigned long)p + 0x1);
  //这里将p强制类型转换成无符号长整形,也就变成了整数了,整数加1就是简单的加减运算
  //0x100001
  printf("%p\n", (unsigned int*)p + 0x1);
  //这里将p强制类型转换成int*类型,所以p+1跳过一个整形大小,也就是4个字节
  //0x100004
  return 0;
}


总结:

指针加+1到底加几呢?

指针加1跳过多少取决于指针类型

整数加一就是加1


第三题:考察指针解引用访问多大空间?


//环境是小段字节序存储,X86
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;
}


结果:


731fdb2f4e8141749f7b9889ae9cd071.png


解析:


int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int* ptr1 = (int*)(&a + 1);
    //&a取出的是整个数组地址,+1跳过整个数组大小,然后又被强制转换成int*类型
    int* ptr2 = (int*)((int)a + 1);
    //a表示首元素地址,强制类型转换成整形,这个地址+1,就是整数+1,然后又被强制转换成int*类型
    printf("%x,%x", ptr1[-1], *ptr2);
    //ptr1[-1]可以这样表示-->   *(ptr-1)
    //对ptr2这个指针解引用,能访问多大空间呢?
    return 0;
}


9e3325b824ef46f38397eaddb4264048.png

2bcad447111b4a1ea5b2a27007a08afd.png


总结:


指针解引用访问多少空间也取决于指针类型,要记住指针解引用是要看访问多少空间的喔,不要忘记啦。


第四题:考察观察,逗号表达式


#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;
}


结果:


f58039f271f14d12af6d4c3daf8ae3ea.png


解析:


int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    //注意这个不是将(0,1),(2,3),(4,5)放进数组,括号里是个逗号表达式,最终结果应该是{1,3,5};
    //所以这个二维数组放的是1,3,5,0,0,0
    int* p;
    p = a[0];
    //a[0]表示数组第一行的数组名,没有单独放进sizeof中,也没有&,所以表示首元素地址,放进p里
    printf("%d", p[0]);
    //p[0]表示*(p+0),就是第一个元素 1
    return 0;
}


第五题:考察指针-指针表示什么意思


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;
}


结果:


ca5e5a0d2f624dc89f432b9000aa1f72.png


解析:


指针-指针表示指针之间的元素个数,由于低地址减去高地址,所以为都为-4,但注意到,第一个是以%p的形式进行打印,是打印地址的,-4在内存中是以补码的形式进行保存,-4的原码反码补码分别是:


 //100000000000000000000000000000100原码
//111111111111111111111111111111011反码
//111111111111111111111111111111100补码
补码直接转换成16进制形式就是

cd90cf568214411887f38b16f36be698.png


ca97ee88505548e5a982fb157c6930a0.png


总结:指针-指针表示指针之间的元素个数


第6题:不同类型的指针+1表示跳过多少?


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;
}


结果:


61c1002ae91c436d9bc2bb92303614b2.png


解析:


上面有题目和这个类似


d738bf1afb06423a8c81419eedd4ea75.png


第7题:考察pa++,到底指什么意思呢?

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


结果:


cecaf975a393482ab13639d15d3f0a2a.png


解析:


dfe48e9256e14b1db67955e68505f8a0.png


总结:


pa++,其实是pa指向的元素进行++

相关文章
C进阶:指针的练习(1)
C进阶:指针的练习(1)
104 1
关于指针,你不可以错过的练习(c/c++)
关于指针,你不可以错过的练习(c/c++)
|
C语言
C语言指针——练习
C语言指针——练习
144 0
|
C语言 C++
【C语言进阶】 指针强化练习(二)
【C语言进阶】 指针强化练习(二)
177 0
|
C++
指针习题练习
指针习题练习
74 0
指针应用基础练习
指针应用基础练习
107 0
|
存储 人工智能
指针的应用练习(数组与指针的关系)
指针的应用练习(数组与指针的关系)
109 0
|
存储 搜索推荐
【C/PTA】指针专项练习(二)
【C/PTA】指针专项练习(二)
314 0