C语言数组和指针笔试题(五)(一定要看)

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

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接

🐒🐒🐒个人主页

🥸🥸🥸C语言

🐿️🐿️🐿️C语言例题

🐣🐓🏀python

指针运算笔试题解析

题目1

#include <stdio.h>
  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[5]是一个整形类型的数组,&a是取的整个数组的地址,因此&a+1就是跳过整个数组,(int*)是强制类型转换,是将&a+1强制转换成int类型的指针(&a+1也可以写成int(*)[5])

*(a+1)中的a是数组首元素的地址,a+1=&a[1],解引用结果就是a[1]=2

ptr-1这里就要好好说一下了,我们用一个图来表示

如图因为&a+1是跳过整个数组,因此ptr的地址在a[4]之后,与a[4]相差4个字节,而ptr-1是跳过1个元素,也就是往前跳过4个字节,因此ptr-1的地址其实就是&a[4],解引用之后就是a[4]=5

结果

题目2

//在X86环境下,假设结构体的大小是20个字节,程序输出的结构是什么
struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
  printf("%p\n", p + 0x1);
  printf("%p\n", (unsigned long)p + 0x1);
  printf("%p\n", (unsigned int*)p + 0x1);
  return 0;
}

解析

0x开头的是16进制,因此0x1其实就是1,p是结构体指针,因为结构体指针+1是跳过一个结构体的大小,而结构体大小是20个字节,又因为是16进制,所以结果是0x100014

,(unsigned long)p是将p强制类型转换为无符号的long,所以p+1就是0x100001

而printf(“%p\n”, (unsigned int*)p + 0x1),因为是将p转换为无符号整形指针,所以+1就是跳过4个字节,就是0x100004

因为是16进制的地址,所以需要4个字节,结果是

0x00100014

0x00100001

0x00100004

结果

题目3

#include <stdio.h>
  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;
  }

解析

int* ptr1 = (int*)(&a + 1)和第一题是一样的所以就不解释了

int* ptr2 = (int*)((int)a + 1)中(int)a是将a强制转换为整形类型,因为整形类型的运算和数学运算是差不多的,因此这里的+1其实就数学上的+1,举个例子假如a的地址是0x0012ff40,通过转换这个地址对应的数字是1244992,所以(int)a+1其实就是1244992+1=1244993,然后将这个结果强制类型转换为整形指针,所以转换之后的地址就是0x0012ff41

我们知道内存存储是分大小端的,这里VS是用小端存储

当用%x打印是02 00 00 00中2前面的0不会打印,所以结果是2000000

而*ptr打印就是4

结果

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

解析

这是一个二维数组,但是要注意数组的元素,我们可以看到数组中用括号括起来了两个数组,这里需要用到逗号表达式, (,)其实只有最后一位有效,(0,1)就是1,因此二维数组我们可以这样写,a[3][2]={1,3,5};因为是三行二列,而{ }中只有三个元素,剩下的既全为0,a[0]在上一篇博客已经讲了,是一维数组{1,3}的数组名,因为p=a[0],所以p[0]=a[0][0],最后结果就应该是1

结果

题目5

假设环境是x86环境,程序输出的结果是什么
#include <stdio.h>
  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)[4]是一个数组指针,因为p=a中a是数组名表示数组首元素的地址,所以a其实就是int( * )[5],而p是int()[4]

因为p中只有4个元素,所以p+1就是跳过4个整形元素,因此绿色是p+4所包含的元素,红色就是a[4][2],对于&p[4][2] - &a[4][2]就是-4,用%p来打印的话就需要将-4的补码写出来

-4的原码:10000000 00000000 00000000 00000100

反码: 111111111 111111111 111111111 111111011

补码: 111111111 111111111 111111111 111111100

因为是打印的%p是地址,所以将补码看成16进制来打印,结果是FFFFFFFC

而用%d打印的话其实就是-4

结果

题目6

#include <stdio.h>
  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+1中&aa是整个二维数组的地址,因此&aa+1是跳过整个二维数组,(int*)将&aa+1强制转换为整形类型的指针

(aa+1)中aa是第一行的地址,(aa+1)就是aa[1],aa[1]就行相当于第二行的数组名,aa[1]=&aa[1][0],这里的强制类型转换其实是多余的,因为第二行第一个元素本来就是整形,取他的地址就是整形类型的指针

所以*(ptr1-1)就是10,*(ptr2-1)就是5

结果

题目7

#include <stdio.h>
  int main()
  {
    char* a[] = { "work","at","alibaba" };
    char** pa = a;
    pa++;
    printf("%s\n", *pa);
    return 0;
  }

解析

这是一道阿里巴巴的笔试题

chara[]是一个数组,数组里面的类型都是char,数组括号里面都是三个字符串,但是这三个字符串是放不下,因为这个数组里面的都指针char*,字符串是放不进去的,所以放进去的是他们的地址,比如work存放在a中的地址是w的地址,at存放的则是a地址…

而pa存放的是a的首元素地址,pa++后就是a的第二个元素如图

结果

题目8

#include <stdio.h>
  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;
  }

解析

上面是没有进行自增自减操作时每个数组元素对应的地址

char*c中存储的分别是

ENTER中E的地址

NEW中N的地址

POINT中P的地址

FIRST中F的地址

而cp中c+3就是第四个元素的地址,c+2就是第三个元素的地址…

cpp是将cp的首元素地址传给cpp,所以cpp就是c+3的地址

上图是经过自增自减操做后的结果,

printf(“%s\n”, **++cpp);对应的颜色是红

printf(“%s\n”, *-- * ++cpp + 3);对应的颜色是绿

printf(“%s\n”, *cpp[-2] + 3);对应的颜色是黑

printf(“%s\n”, cpp[-1][-1] + 1);对应的颜色是粉

我们一个一个的解析

第一次打印: **++cpp先将cpp进行自增,所以cpp中的cp从cp中第一个元素c+3变到第二个元素c+2 然后两次解引用之后就是POINT中P的地址,打印字符串就为POINT

第二次打印:由于++cpp将cpp中cp指向的地址永久变化了,所以第二次的++cpp就是从c+2变到了c+1,解引用再–,c+1就变成了c,所以c+1指向的地址就由1变成0,之后再解引用就是ENTER中E的地址,再+3后,就是箭头值的第二个E的地址,打印字符串就是ER

第三次打印:*cpp[-2]+3我们可以写成 * *(cpp-2)+3,由于上一次打印使cpp指向的c+2变成了c+1,所以这里的cpp-2就使cpp指向的第三个元素c+1变为第一个元素c+3(注意这里不是自增自减),再经过两次解引用后,就是FIRST中F的地址,+3就变成了箭头指向的S的地址,所以打印结果为ST

第四次打印cpp[-1][-1] + 1可以写成 *( *(cpp-1)-1)+1,cpp-1就是从第三个元素c+1变为第二个元素c+2,解引用再-1就是从原来指向的下标2变成指向的下标1,解引用再+1就是NEW中E的地址,打印的结果就是EW

结果

目录
相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
33 3
|
12天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
20天前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
43 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
38 2
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
37 1
|
2月前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
20 2
|
2月前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
2月前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
2月前
|
编译器 C语言
【c语言】指针就该这么学(2)
本文详细介绍了指针与数组的关系,包括指针访问数组、一维数组传参、二级指针、指针数组和数组指针等内容。通过具体代码示例,解释了数组名作为首元素地址的用法,以及如何使用指针数组模拟二维数组和传递二维数组。文章还强调了数组指针与指针数组的区别,并通过调试窗口展示了不同类型指针的差异。最后,总结了指针在数组操作中的重要性和应用场景。
21 0
|
7月前
|
C语言
C语言---指针进阶
C语言---指针进阶
50 0