指针和数组笔试题解析(1)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析DNS,个人版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 指针和数组笔试题解析(1)

一、一维数组

下面代码的输出结果是什么:(32位平台下)

int main()
{
    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));
    return 0;
}

2020062310470442.png

解析:

int a[] = {1,2,3,4};    
printf("%d\n",sizeof(a));   //16
//a作为数组名单独放在sizeof内部,表示整个数组的大小:4*4=16
printf("%d\n",sizeof(a+0));   //4/8
//a没有单独放在sizeof内部,也没有&,所以代表首元素即a[0]的地址,地址的大小是4/8个字节
printf("%d\n",sizeof(*a));   //4
//a没有单独放在sizeof内部,也没有&,所以代表首元素即a[0]的地址,首元素的地址解引用得到首元素,int 4个字节
printf("%d\n",sizeof(a+1));   //4/8
//a没有单独放在sizeof内部,也没有&,所以代表首元素即a[0]的地址,a+1代表第二个元素的地址,4/8个字节
printf("%d\n",sizeof(a[1]));  //4
//a[1]代表数组第二个元素,整形占4个字节
printf("%d\n",sizeof(&a));  //4/8
//&a取出的是整个数组的地址,地址占4/8个字节
printf("%d\n",sizeof(*&a)); //16
//&a取出整个数组的地址,然后再对其进行解引用,得到整个数组
printf("%d\n",sizeof(&a+1));  //4/8
//&a取出整个数组的地址,&a+1跳过一个数组(跳过一个数组指针)的大小,指向数组末尾,地址大小是4/8个字节
printf("%d\n",sizeof(&a[0])); //4/8
//&a[0]取出的是第一个元素的地址,地址大小为4/8个字节
printf("%d\n",sizeof(&a[0]+1)); //4/8
//&a[0]取出的是第一个元素的地址,&a[0]+1表示第二个元素的地址,地址大小为4/8个字节

总结:

1、数组名的意义

  • 数组名单独放在sizeof内部时表示整个数组;
  • &数组名取出的是整个数组的地址;
  • 其余情况数组名均表示首元素的地址;

2、指针类型的意义

  • 指针的类型决定了指针加减整数时跳过字节/元素的个数;
  • 指针的类型决定了指针解引用时的权限,即访问字节的个数(步长);

二、字符数组

1、题型一

下面代码的输出结果是什么:(32位平台下)

int main()
{
  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));
  return 0;
}

2020062310470442.png

20200623104134875.png

解析:

char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));  //6
//arr单独放在sizeof内部,代表整个数组,大小为6个字节
printf("%d\n", sizeof(arr + 0));  //4/8
//arr代表首元素的地址,4/8个字节
printf("%d\n", sizeof(*arr)); //1
//arr代表首元素地址,对其解引用代表第一个元素,大小为1个字节
printf("%d\n", sizeof(arr[1]));    //1
//arr[1]代表数组第二个元素,1个字节
printf("%d\n", sizeof(&arr)); //4/8
//&arr取出整个数组地址,4/8个字节
printf("%d\n", sizeof(&arr + 1)); //4/8
//&arr取出整个数组的地址,&arr+1跳过一个数组,指向数组后面紧挨的空间,4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));  ///4/8
//&arr[0]代表首元素地址,+1代表第二个元素地址,4/8个字节
printf("%d\n", strlen(arr));  //随机值
//arr代表首元素地址,数组从第一个元素开始求字符串长度
//strlen求的是\0以前字符的个数,因为字符数组中并不包含\0,所以strlen会一直往后寻找,直到遇到\0,而我们不知道数组后面空间的内容,所以为随机值。
printf("%d\n", strlen(arr + 0));  //随机值 
//arr+0代表首元素地址,数组从第一个元素开始求字符串长度
//随机值原因同上
printf("%d\n", strlen(*arr)); //error
//strlen函数的参数是一个地址,这里我们把第一个元素即'a'传给strlen函数,那么strlen就会把'a'的ASCII码值(97)当成地址来用,但是97处的地址并不属于我们,从而造成野指针问题,报错
printf("%d\n", strlen(arr[1])); //error
//原因和上面类似
printf("%d\n", strlen(&arr)); //随机值
//&arr虽然取出整个数组的地址,但仍然是指向首元素,所以和上面的strlen(arr)一样
printf("%d\n", strlen(&arr + 1)); //随机值
//&arr取出整个数组的地址,+1跳过整个数组,指向数组后面紧挨的空间,但我们不知道后面空间何时遇到\0,所以仍然是随机值
printf("%d\n", strlen(&arr[0] + 1));  //随机值
//&arr[0]+1代表第二个元素地址,仍然是随机值

2、题型二

下面代码的输出结果是什么:(32位平台下)

int main()
{
  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));
  return 0;
}

2020062310470442.png

20200623104134875.png

解析:

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));  //7
//arr代表整个数组,因为字符串末尾会自动补一个\0,所以arr数组有七个元素
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)); //4/8
printf("%d\n", sizeof(&arr + 1)); //4/8
printf("%d\n", sizeof(&arr[0] + 1));  //4/8
printf("%d\n", strlen(arr));  //6
//strlen遇到字符串末尾的\0停止,前面一共6个元素
printf("%d\n", strlen(arr + 0));  //6
printf("%d\n", strlen(*arr)); //error
printf("%d\n", strlen(arr[1]));    //error
printf("%d\n", strlen(&arr)); //6
printf("%d\n", strlen(&arr + 1)); //随机值
//&arr取出整个数组的地址,+1跳过整个数组,后面空间的内容未知,所以随机
printf("%d\n", strlen(&arr[0] + 1));  //5
//&arr[0]+1是第二个元素的地址,把它传给strlen,所以为5

3、题型三

下面代码的输出结果是什么:(32位平台下)

int main()
{
  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));
  return 0;
}

2020062310470442.png

20200623104134875.png

解析:

char* p = "abcdef";
printf("%d\n", sizeof(p));  //4/8
//"abcdef"是常量字符串,char* p = "abcdef" 的作用是把字符串中'a'的地址赋给P,所以4/8
printf("%d\n", sizeof(p + 1));  //4/8
//p+1代表字符'b'的地址,4/8
printf("%d\n", sizeof(*p));    //1
printf("%d\n", sizeof(p[0])); //1
printf("%d\n", sizeof(&p));    //4/8
//&p取出的是p的地址,是一个二级指针,但地址大小仍然是4/8
printf("%d\n", sizeof(&p + 1));    //4/8
//&p+1代表p所在空间后面紧挨的空间
printf("%d\n", sizeof(&p[0] + 1));    //4/8
//&p[0] <==> &(*(p+0)) <==> p,代表'a'的地址
printf("%d\n", strlen(p));    //6
printf("%d\n", strlen(p + 1));    //5
printf("%d\n", strlen(*p));    //error
printf("%d\n", strlen(p[0]));    //error
printf("%d\n", strlen(&p));    //随机值
//&p取出的是p的地址,这里有两个东西是不确定的:
//1、不知道p的地址中是否含有四个字节大小的数字0,p的地址可能0x14ffff44,也可能是0x1400ff00
//2、不知道p的后面空间的内容
//所以strlen求出来的值是随机的
printf("%d\n", strlen(&p + 1));    //随机值
//&p+1跳过了p的地址,直接来到了p其后的空间,消除了上面的第一点不确定,但第二段仍然存在
printf("%d\n", strlen(&p[0] + 1));    //5

总结:

1、数组名的意义

  • 数组名单独放在sizeof内部时表示整个数组;
  • &数组名取出的是整个数组的地址;
  • 其余情况数组名均表示首元素的地址;

2、指针类型的意义

  • 指针的类型决定了指针加减整数时跳过字节/元素的个数;
  • 指针的类型决定了指针解引用时的权限,即访问字节的个数(步长);

3、strlen的用法

  • strlen会一直向后寻找,直到遇到 ‘\0’ 才停止计算(越界计数得到随机值);
  • strlen会把传递过来的数据当成地址来使用(错误传递参数导致野指针问题);

三、二维数组

下面代码的输出结果是什么:(32位平台下)

int main()
{
  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]));
  return 0;
}

2020062310470442.png

解析:

int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));  //48
  //a单独放在sizeof内部,表示整个二维数组的大小,3*4*4=48
  printf("%d\n", sizeof(a[0][0]));  //4
  //a[0][0]代表第一个元素,整形占4个字节
  printf("%d\n", sizeof(a[0])); //16
  //二维数组的行名代表其对应一维数组的数组名
  //这里的a[0]代表二维数组第一行的数组名
  //一维数组的数组名单独放在sizeof内部,代表整个一维数组,4*4=16
  printf("%d\n", sizeof(a[0] + 1)); //4/8
  //a[0]代表第一行的数组名
  //a[0]不是单独放在sizeof内部,所以数组名代表首元素地址,即a[0][0]的地址
  //所以a[0]+1代表数组第二个元素a[0][1]的地址,4/8
  printf("%d\n", sizeof(*(a[0] + 1)));  //4
  //对数组第二个元素解的地址引用得到第二个元素,整形大小4个字节
  printf("%d\n", sizeof(a + 1));    //4/8
  //a代表首元素即第一行的地址,a+1跳过一行,指向第二行,第二行的地址4/8
  printf("%d\n", sizeof(*(a + 1))); //16
  //第一行的地址+1指向第二行的地址,解引用得到第二行
  printf("%d\n", sizeof(&a[0] + 1));  //4/8
  //&a[0]取出第一行的地址,+1指向第二行的地址
  printf("%d\n", sizeof(*(&a[0] + 1))); //16
  //对第二行的地址解引用得到整个第二行
  printf("%d\n", sizeof(*a)); //16
  //a代表首元素即第一行的地址,解引用得到第一行
  printf("%d\n", sizeof(a[3])); //16
  //sizeof求数据大小时只关注数据的类型,不关注数据的内容
  //这里虽然这里a[3]越界了,但是根据a[3]的数据类型:int (*)[4] -- 数组指针,仍能求出a[3]的大小
  //a[3]代表一维数组的数组名单独放在sizeof内部代表整个数组的大小

总结:

1、数组名的意义

  • 数组名单独放在sizeof内部时表示整个数组;
  • &数组名取出的是整个数组的地址;
  • 其余情况数组名均表示首元素的地址;

2、指针类型的意义

  • 指针的类型决定了指针加减整数时跳过字节/元素的个数;
  • 指针的类型决定了指针解引用时的权限,即访问字节的个数(步长);

3、二维数组相关

  • 二维数组的行号可以看作对应一维数组的数组名,如arr[3][4]中arr[0]代表第一行的一维数组的数组名;
  • 对于sizeof(arr[0]),由于arr[0]代表一维数组的数组名,且arr[0]单独放在sizeof内部,所以求的是这个一维数组的大小;
相关文章
|
4天前
|
存储 算法 搜索推荐
深入解析String数组的操作与性能优化策略
深入解析String数组的操作与性能优化策略
|
10天前
|
存储 C++
有关【指针运算】的经典笔试题
有关【指针运算】的经典笔试题
14 4
|
8天前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
10天前
|
C语言
【C语言】:详解函数指针变量,函数指针数组及转移表
【C语言】:详解函数指针变量,函数指针数组及转移表
14 2
|
10天前
|
C语言
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
10 1
|
10天前
|
Serverless C语言
【C语言】:对(一维)数组与指针的深入理解(1)
【C语言】:对(一维)数组与指针的深入理解(1)
10 1
|
2天前
|
存储 算法 搜索推荐
深入解析String数组的操作与性能优化策略
深入解析String数组的操作与性能优化策略
|
5天前
|
存储 Java 数据库
解析和使用String数组的方法
解析和使用String数组的方法
|
7天前
|
存储 C语言
C语言中的多级指针、指针数组与数组指针
C语言中的多级指针、指针数组与数组指针
7 0
|
7天前
|
存储 C语言
C语言数组指针详解与应用
C语言数组指针详解与应用
13 0

推荐镜像

更多