【数组和进阶指针经典笔试题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


目录
相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
37 3
|
24天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
28天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
28天前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
28天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
1月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
53 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
48 2
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
105 13
|
2月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
36 0
|
3月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
136 4