【数组和进阶指针经典笔试题12道】这些题,满足你对数组和指针的所有幻想,come on !

简介: 【数组和进阶指针经典笔试题12道】这些题,满足你对数组和指针的所有幻想,come on !

近几年互联网受疫情影响,许多互联网都使用牛客网在线笔试招人


很多同学因为不熟悉牛客网的环境和使用,最后在线笔试面试中屡屡受挫


牛客网提供了语言巩固,算法提高等在线OJ题,更有面试真题,大厂内推!


链接附上点击链接注册牛客网


牛客网这么好用,但是下面几个关于牛客网的知识你了解过吗?


你知道你OJ过不了,牛客网几种经典的英文报错提示的含义吗?

你知道牛客网的OJ分为IO型和接口型吗?

你使用过牛客网的调试功能吗?

众所周知,指针是C语言的灵魂,很多人就是倒在指针的脚下。今天,我来带大家看一看指针在笔试中是怎么考的吧!(提示:本篇博客测试环境是vs-x64,该环境下指针占8个字节)


练习题1

int main()
{
  int a[4] = { 1,2,3,4 };
  printf("%u\n", sizeof(a));//16-sizeof(数组名)-整个数组
  printf("%u\n", sizeof(a+0));//8-不是单独的数组名-数组首元素的地址
  printf("%u\n", sizeof(*a));//4-数组首元素的地址解引用-数组首元素
  printf("%u\n", sizeof(a+1));//8-数组第2个元素的地址
  printf("%u\n", sizeof(a[1]));//4-数组第2个元素
  printf("%u\n", sizeof(&a));//8-整个数组的地址
  printf("%u\n", sizeof(*&a));//16-对整个数组的地址解引用,得到的是整个数组-sizeof(数组名)
  printf("%u\n", sizeof(&a+1));//8-&a是整个数组的地址,+1跳过一个数组,还是一个数组的地址
  printf("%u\n", sizeof(&a[0]));//8-首元素的地址
  printf("%u\n", sizeof(&a[0]+1));//8-第2个元素的地址
  return 0;
}

232451e451e74c8daa22895bd48f860d.png


练习题2

int main()
{
  char str[5] = { 'a','b','c','d','e' };
  printf("%d\n", sizeof(str));//5-sizeof(数组名)-整个数组
  printf("%d\n", sizeof(str+0));//8-数组首元素的地址
  printf("%d\n", sizeof(*str));//1-数组首元素
  printf("%d\n", sizeof(str[1]));//1-数组第二个元素
  printf("%d\n", sizeof(&str));//8
  printf("%d\n", sizeof(&str[0]+1));//8
  printf("%d\n", sizeof(str[0]+1));//4-字符和整型相加-整型提升
  //等价于printf("%d\n", sizeof('a'+1));//4-整型提升
  return 0;
}

练习题3

int main()
{
  char str[] = { 'a','b','c','d','e' };
  printf("%d\n", strlen(str));//随机值
  printf("%d\n", strlen(str+0));//随机值
  printf("%d\n", strlen(*str));//strlen('a')-->strlen(97);//野指针
  printf("%d\n", strlen(str[1]));//野指针
  printf("%d\n", strlen(&str));//随机值
  printf("%d\n", strlen(&str+1));//随机值
  printf("%d\n", strlen(&str[0]+1));//随机值
  return 0;
}

这里的第三个printf处如果调试的话,这个错误代表的意思就是访问了非法内存(有一些内存地址是没有办法访问的,有一些是允许访问,但是也会进行一定的检测)


de0b848b14e84898af640333d16dc61b.png


关于sizeof和strlen:


strlen是求字符串长度的,关注的是字符串中的'\0',计算的是\0之前出现字符的个数


strlen是库函数,只针对字符串


sizeof只关注占用内存的大小,不在乎内存中放的是什么


sizeof是操作符


练习题4

int main()
{
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));//3*4*4=48-整个二维数组
  printf("%d\n", sizeof(a[0]));//8错//4*4=16对 sizeof(一维数组数组名)-整个第一个一维数组
  printf("%d\n", sizeof(a[0]+1));//8-第2个一维数组的地址
  printf("%d\n", sizeof(a[0][0]));//4-第一个一维数组的第1个元素
  printf("%d\n", sizeof(*(a[0]+1)));//4-第一个一维数组的第2个元素
  printf("%d\n", sizeof(*(a+1)));//8错//4*4=16对 sizeof(一维数组数组名)-整个第2个一维数组
  printf("%d\n", sizeof(a+1));//8-第2个一维数组的地址
  printf("%d\n", sizeof(&a[0]+1));//8-第一个一维数组的第2个元素
  printf("%d\n", sizeof(*a));//4*4=16-整个第一个一维数组
  printf("%d\n", sizeof(a[3]));//16-整个第四个一维数组
  return 0;
}

ea3a7d2a47e94d21b33fd4609596e49e.png


练习题5


int main()
{
  int a[5] = { 1,2,3,4,5 };
  int* ptr = (int*)(&a + 1);
  printf("%d %d", *(a + 1), *(ptr - 1));//2 5
  return 0;
}

b5f06e34c18e4a52bb6bf0ec2d188871.png


练习题6

struct Test
{
  int num1;
  char* num2;
  short num3;
  char num4[2];
  short num5[4];
}*p;
//假设p的值为0x100000,如下表达式的值分别是多少?
//已知在当前环境下,Test类型的变量大小是20个字节
//考察:指针/整数+1到底是加了多少
int main()
{
  printf("%p\n", p + 0x1);//0x100014
  printf("%p\n", (unsigned long)p + 0x1);//0x100001
  printf("%p\n", (unsigned int*)p + 0x1);//0x100004
  return 0;
}

0x1就是十六进制的1,也就是十进制的1:


对于第一个p+0x1中p是struct Test* 类型的指针,加1,跳过一个sizeof(struct Test)==20,也就是0x00014大小。


同理第二个p是被强制转换为了unsigned long类型,是一个整数,整数=1就是+1,然后按照%p打印出来,加的因为就是1(没有超过16),所以和在原来的0x10000上加1是一样的。


同理第三个p是被强制转换为了unsigned int*类型,加1,加的是4个字节。


练习题7

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

4c46a6edb63647a680655243df739b55.png

ptr3得到的方式是:

通过将整型指针强制转换为整型数值,然后加1,最后再强制转换为整型指针;

ptr4得到的方式是:

通过将整型指针强制转换为字符指针,然后加1,最后再强制转换为整型指针。

两个的效果是一样的。


8189041e8dad4a37a4b0275854892e9d.png


练习题8


int main()
{
  int a[3][2] = { (0,1),(2,3),(3,4) };//坑点:逗号表达式
  int* p;
  p = a[0];
  printf("%d\n", p[0]);
  //等价于printf("%d\n", *p);
  return 0;
}


image.png

image.png

练习题9

int main()
{
  int a[4][5];
  int(*p)[3];//重点在于这里的3,不是5
  p = a;
  printf("%p %d\n", &p[3][2] - &a[3][2], &p[3][2] - &a[3][2]);
  return 0;
}

7c2873f684734dce97c0fa5dac16347e.png

fd60fd2b401b4b0fafd61ef9ce827c22.png

aeaef388fff84272941b26f9b653c25b.png


练习10

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

245da5cdc95c4d8eaa5ac1832995ef65.png

218494cf3cb64adf9ff0931ec565ba11.png


练习11

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

a4c411b03e2b4372a7cee017ff1c476e.png

f0251ec56a734e998dbb953adf05ae1d.png


练习题12

int main()
{
  char* c[] = { "ENTRE","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[-1]就是指向的*(cpp-1),就是先指针-1(指向发生改变),然后过桥(找到指针指向的那个目标);


然后这里的虚线就是不会有自增++有副作用


a=a+1;有副作用(a变了)


但是a+1;就没有副作用(a没有变


4d303d9bda204aff88d2dc47d27b5853.png

1de501f1747c4c78b5a6ae9e89d43ccc.png

33026e9a368342cfbd056f49feafb74b.png

image.png


image.png


目录
相关文章
|
3天前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
3天前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
3天前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
4天前
|
存储 C++
有关【指针运算】的经典笔试题
有关【指针运算】的经典笔试题
12 4
|
3天前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
4天前
|
C语言
【C语言】:详解函数指针变量,函数指针数组及转移表
【C语言】:详解函数指针变量,函数指针数组及转移表
10 2
|
4天前
|
C语言
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
8 1
|
4天前
|
Serverless C语言
【C语言】:对(一维)数组与指针的深入理解(1)
【C语言】:对(一维)数组与指针的深入理解(1)
8 1
|
1天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
6 0
|
1天前
|
存储 C语言
C语言中的多级指针、指针数组与数组指针
C语言中的多级指针、指针数组与数组指针
5 0