三年考点总结


数组类问题
分析一下代码段,并解释输出结果和原因

#include<stdio.h>
int main(int argc,char *argv[])
{int nums[3][3] = {1,2,3,4,5,6,7,8,9};printf("%d\n",nums[1][-2]);printf("%d\n",(-1)[nums][5]);printf("%d\n",-1[nums][5]);return 0;
}输出结果2,3,-9

这个题的关键是理解数据在数组中是如何存储的
。 0 1 2
0:1 2 3
1:4 5 6
3:7 8 9
第一个可以换成如此格式,*( *(nums + 1)-2)//由此可见指针和多维数组的关系不言而瑜
ps:(-1)[nums][5]) 和 nums[-1][5] 是一样的
-1[nums][5]和 -nums[1][5](这个-1没括号)

nums是二维数组,它的的单个元素是一维数组,所以它+1是+一个一维数组的字节。现在我们把这个二维数组抽象为二维指针,*(nums+1) 则是一级指针,它的单个元素为一个 int,所以它-2是 减2个int字节,所以最终就是+1个int也就是答案2。

对于这道题,还有一个问题是关于数组名具体代表的是什么的问题

int a[3][4]

  1. sizeof(a),a的类型: int [3][4],所以它返回整个数组的长度
  2. fun(int *a),作为函数形参,a的类型为int *
  3. &a,它的类型为int (*)[3][4],是一个数组指针
  4. 在表达式中,它的类型为int (const*)[4],即指向数组首元素a[0]的常量指针,a[0]它是一个int[4]。
  5. c语言中严格来说没有什么二维数组,它只有那种普通的一维数组,二维数组可以看做数组的数组,即对于a来说,它有3个元素,每个元素都是一个具有4个整形元素的一维数组(int[4])。我们可以把a[0]看做第一个元素的数组名,其他类推。
  6. 显然*a = *(a + 0) = (0 + a) = a[0] = 0[a],加法具有交换律嘛。那么,a = &a[0],这时就验证了我们上面的说法,此时(在表达式中),a是一个int()[4]
  7. a + 1 <==> &a[0] + 1,就是跨过第一行,即一个int[4]。a[0] + 1就是跨过第一行的第一个元素,即&a[0][1]。&a + 1自然就跨过整个数组喽。

然后我们在看一下指针和多维数组的关系
我的理解简单的说,就是一层数组等于一个 *

例如:*( *(a+x)+y) 所指向的值就是 a[x][y]

看下题

#include<stdio.h>
int main(){int a[4][2] = {{2,4},{6,8},{1,3},{5,7}};printf("    a = %p,    a + 1 = %p\n",a,a+1);printf(" a[0] = %p, a[0] + 1 = %p\n",a[0],a[0]+1);printf("   *a = %p,    * a+1 = %p\n",*a,*a+1);printf("    a[0][0] = %d\n",a[0][0]);                                       printf("      *a[0] = %d\n",*a[0]);printf("        **a = %d\n",**a);printf("    a[2][1] = %d\n",a[2][1]);printf("*(*(a+2)+1) = %d\n",*(*(a+2)+1));return 0;
}

结果如下

    a = 0x7fff19a496f0,    a + 1 = 0x7fff19a496f8a[0] = 0x7fff19a496f0, a[0] + 1 = 0x7fff19a496f4*a = 0x7fff19a496f0,    * a+1 = 0x7fff19a496f4a[0][0] = 2*a[0] = 2**a = 2a[2][1] = 3
*(*(a+2)+1) = 3

紧接着我们看一下sizeof于strlen的区别
sizeof是求数组或指针的最大容量
strlen计算的是一个对象或者类型的实际有效的内存长度。
ps:和上面做比较,strlen是c的库函数返回值是在运行时计算出来的,sizeof是一个关键字,结果类型为size_t
由此下面这个题基本就解决了

 #include<stdio.h>#include<string.h>#include<stdlib.h>                                                          int main(int argc[],char *argv[]){int a[3][2] = {2,0,1,8};char *str = (char*)malloc(sizeof(char)*20);strcpy(str,"\0101\\xb2");printf("%zu\n",sizeof(a));printf("%zu %d\n",sizeof(a[1][1] = 0),a[1][1]);printf("%zu %zu\n",sizeof(str),strlen(str));return 0;}
输出结果
24
4 8
8 6

ps:%zu 是size_t输出类型,可以当它为整形变量
用%zu的原因:sizeof()不是函数,是一个关键字,不可扩展。sizeof()的结果类型为size_t,用int也行。

第一行的输出是24,计算的是a数组内存的长度。
第二行的第一个输出,a数组是一个int类型的数组,输出为4。
对str的内存计算
指针变量的大小在32位机和64位是不同
32位为4字节,64位为8字节。

再来解释下一道题
分析一下代码段,并解释输出结果和原因

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{ int a[3][2] = {2,0,1,8};char *str = (char *)malloc(sizeof(char)*20);strcpy(str,"\0101\\xb2");printf("%zu\n",sizeof(a));printf("%zu %d\n",sizeof(a[1][1] = 0),a[1][1]);printf("%d\n",a[1][1]);return 0;
}
输出结果  : 24,4,8,8

第一个24,int形二维数组a,sizeof求容量,324 = 24
第二个4,是求单个a[1][1]的容量,所以是4,在sizeof括号中进行的语句,不会实现,所以后面的8就没有被赋新值,还是8。

附
unsigned int   0~4294967295
int   2147483648~2147483647
unsigned long 0~4294967295
long   2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:1844674407370955161
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:1844674407370955161

程序关于编译实现的问题
1.对于main()函数的理解

一个什么也不做的main函数如下:
void main() {} //早期C语言写法,如今使用下一种写法

我们可以让main函数返回一个状态值,表示最终执行的状态。
int main() { return 0; }

main函数可以有两个输入参数:

**argc:**指明参数的个数(即argv数组元素的个数)

**argv:**字符串数组表示的具体参数(一个包含多个字符串的数组)

我暂时只在文件操作用过这两个参数,我太菜了

2.下面是一个c语言程序从源代码到形成可执行文件的过程,请解释图中的ABCD分别表示什么,在每个阶段分别完成了什么工作?

暂时对这些不是非常理解,等我以后学习多了再来认真解释
此题答案详细解释


字节对齐问题
计算机是非常聪明的(不想看我的戳一下),他对数据存储有自己的方式,通过将内存“对齐”这一方式让变量的地址拥有一定的特性,使CPU对内存的访问效率得到了提高。以下题结构体为例

类型对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char 偏移量必须为sizeof(char)即1的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
Short 偏移量必须为sizeof(short)即2的倍数

    #include<stdio.h>struct icd{int a;char b;double c;};struct cdi {char a;double b;int c;};int main(int argc,char *argv[]){printf("%zu %zu\n",sizeof(struct icd),sizeof(struct cdi));            return 0;}输出结果
16 24

第一个的图形解释

第二个的图形解释

所以为了节省内存,结构体中数据顺序也是十分重要的,另外,共用体的字节对齐就更简单了,我在此不做过多赘述。

既然都说到这里了,那就在来说一下大端和小端
现在的个人pc一般都是小端序,低地址存低字节,高地址存高字节,大端序则相反。
那什么又是高地址低地址呢?
我们设一个数组buf[4];

Big-Endian: 低地址存放高位,如下:

栈底 (高地址)
buf[3] (0x78) – 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) – 高位
栈顶 (低地址)
Little-Endian: 低地址存放低位,如下:

栈底 (高地址)
buf[3] (0x12) – 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) 低位
栈顶 (低地址)
这里还有一个思考问题是关于,如何编写一个程序来证明大小端序。
tip:可以用union

stdout, stdin, stderr问题

stdout, stdin, stderr的中文名字分别是标准输出,标准输入和标准错误。
在Linux下,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据流,也就是题目中所提到的这三个。那么什么是数据流呢(stream)?我们知道,一个程序要运行,需要有输入、输出,如果出错,还要能表现出自身的错误。这是就要从某个地方读入数据、将数据输出到某个地方,这就够成了数据流。

例:fprintf(stdout,“hello world!\n”);
屏幕上将打印出"hello world!"

对于这一方面的学习,我推荐去这个网站,内容比较丰富各种函数快查

问题:下面程序的输出是什么?

int main(){
fprintf(stdout,"xiyou");
fprintf(stderr,"linux!");
return0;
}

解答:这段代码的输出是什么呢?在linux环境下和windows环境下有何异同?

在linux下的结果是
linux!xiyou
在windows下是
xiyoulinux!

这是为什么呢?在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲的,会直接输出,举例来说就是printf(stdout, “xxxx”) 和 printf(stdout, “xxxx\n”),前者会憋住,直到遇到新行才会一起输出。而printf(stderr, “xxxxx”),不管有么有\n,都输出。
但是这种情况是出现在linux系统之下的,而对于windows系统来说,stderr和stdout是都没有行缓冲的
所以输出结果是xiyoulinux!

通过自己写的函数写出一个交换操作,可实现任何数据类型
方法1:宏函数

#define swap(a,b){a=a+b;  b=a-b;  a=a-b;}

方法2:通过void指针,增加一个参变量来判断他的数据类型实现


void swap(int f, void* x, void* y){ if(f == 1) {int *p1;int *p2;int tmp;p1 = (int *) x;p2 = (int *) y;temp = *p1;*p1 = *p2;*p2 = temp;}else if (f == 2) {double *p1;double *p2;double tmp;p1 = (double *) x;p2 = (double *) y;temp = *p1;*p1 = *p2;*p2 = temp;}else if(f == 3) {char *p1;char *p2;char temp;p1 = (char *) x;p2 = (char *) y;temp = *p1;*p1 = *p2;*p2 = temp;}else if(f == 4) {short *p1;short *p2;short tmp;p1 = (short *) x;p2 = (short *) y;temp = *p1;*p1 = *p2;*p2 = temp;}else if(f == 5) {float *p1;float *p2;float tmp;p1 = (float *) x;p2 = (float *) y;temp = *p1;*p1 = *p2;*p2 = temp;}//等等等
}

是不是感觉很难受
当然只要学了c++,可以直接用swap函数,STL大法好

const指针用法
const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一定帮助。另外CONST在其它编程语言中也有出现,例如Pascal、C++、PHP5、B#.net、HC08 C、C#等
ps:定义某一个数值是多大时,个人感觉用const更好,感觉值不能改变,更安全,而且在算法比赛中,你如果要多次对某个数取余,不如定义一个固定的const形变量在去对他取余,程序运行速度会大大提高,玄学我不懂,但是的确是。
扯远了
对面试题来说

#include<stdio.h>
int main()
{char y[] = "xiyoulinuxgroup",x[] = "2018"char *const p1 = y;     //(1)const char * p2 = y;    //(2)return 0;
}

简单的来看const后面紧跟的是不能改变,记住这一点
所以第一个p1指向不可以改变
第二个*p2指的变量不能改变

宏定义的坑点
无参宏定义 //最常见用法
无参数宏定义的格式为:#define 标识符 替换列表
例:
#define PI 3.1416

由于宏定义仅是做简单的文本替换,故替换列表中如有表达式,必须把该表达式用括号括起来,否则可能会出现逻辑上的“错误”
比如面试题中的坑点

#define A  2+3
int z = A*A;
事实上z = 2+3*3+2

并不是你所需的结果,所以宏函数慎用,用就都加括号,括号大法好

带参数宏定义
带参数的宏定义格式为:#define 标识符(参数1,参数2,…,参数n) 替换列表

#define MAX(a,b) ((a)>(b)?(a) : (b))

括号必须加,不然肯定会出岔子的

宏展开
我这里的理解也非常浅薄,不是很懂
只能说
(1) 当宏中有#运算符时,参数不再被展开;
(2) 当宏中有##运算符时,则先展开函数,再展开里面的参数;##运算符用于把参数连接到一起。
最近抽时间在看看这方面的东西,算法比赛花费时间有点多

#define YEAR 2018
#define LEVELONE(x) "xiyoulinux"#x"\n"
#define LEVELTWO(x) LEVELONE(x)
#define MULTIPLY(x,y) x*yint main(int argc, char *argv[])
{int x = MULTIPLY(1+2,3);printf("%d\n",x);printf(LEVELONE(YEAR));printf(LEVETWO(YEAR));
}
输出结果 : 7xiyoulinuxYEARxiyoulinux2018

答案7同上
后面两个第一个因为在LEVELONE(x) “xiyoulinux”#x"\n"中含有#,所以不展开宏参数,直接输出的YEAR
但是第二个就是正常的宏替换,所以就输出 xiyoulinux2018

#include<stdio.h>
#define f(a,b) a##b
#define g(a)   #a
#define h(a)  g(a)
int main()
{printf("%s\n",h(f(1,2)));     printf("%s\n",g(f(1,2)));   return 0;
}输出结果  : 12f(1,2)

宏h(a) 是g(a),没有#,所以需要进行宏展开,两个##连接1和2,所以输出12
宏g(a) 有#,所以不展开直接输出f(1,2)

解释以下语句

#ifdef_linux_int a  = 1;
#elif _WIN32int a = 2;
#elif _APPLE_int a = 3;
#elseint a = 4;
#endif

我在网上查了这几个宏的意思,有一篇博客是这样说的
这几个宏是为了进行条件编译。一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。
所以这三句在不同系统的电脑下运行的结果也是不同的
在linux下a=1
在win32下a=2
在Apple下a=3
在其他a=4

注意:宏定义不是语句,是预处理指令,故结尾不加分号。

补码反码原码问题

小组这几年的面试题都出到了原码反码补码,连2019西工大acm邀请赛的热身赛c题也考察到了这个点(现在网上可能题还没出来)。
我在这里贴一篇帖子点一哈
对于这一类的运算题,先来一道面试题

#include<cstdio>
void func(void)
{unsigned int a = 6;int b = -20;(a+b > 6) ? puts(">6") : puts("<6");
}
int main( )
{func();
}
输出>6

C语言中有符号数和无符号数进行运算(包括逻辑运算和算术运算)默认会将有符号数看成无符号数进行运算,其中算术运算默认返回无符号数,逻辑运算返回0或1。

这道题,因为a是无符号的,无符号数a和有符号b进行加法运算,计算机将b看做无符号数,b的符号位也计数了,所以这两个数相加肯定大于6,所以答案也肯定大于6

我以后补充其他难的呜呜呜呜呜呜呜

XiyouLinuxgroup 2015 2017 2018面试题相关推荐

  1. adobe CC 2015/2017/2018安装失败

    Adobe Effect 2015/2017/2018全系统软件已经可以从官网下载了,相信又将有一大波设计师会更新安装adobe CC 2015/2017软件.本着尝鲜的精神,本人也下载了Illust ...

  2. Xiyou Linux Group 2017,2018,2019面试题

    西邮Linux2017纳新题 1. //分析下列程序的输出 int main(int argc, char *argv[]) {int t = 4; printf("%lu\n", ...

  3. 2017~2018学年《信息安全》考试试题(A2卷)

    北京信息科技大学,2017~2018 学年第二学期<信息安全>考试试题(A 卷) 适用专业班级:计科15级 重修课程所在学院:计算机学院 考试形式:闭卷 一.单选题(本题满分20分,共含1 ...

  4. 2017~2018学年《信息安全》考试试题(A3卷)

    北京信息科技大学 2017 ~2018 学年第一学期 <信息安全>考试试题 (A3 卷) 课程所在学院:计算机学院 适用专业班级: - 考试形式:闭卷 一.单选题(本题满分 20 分,共含 ...

  5. 2017~2018学年《信息安全》考试试题(A1卷)

    北京信息科技大学 2017 ~2018 学年第二学期<信息安全>考试试题 (A 卷) 课程所在学院:计算机学院 适用专业班级:计科 1504-6.重修 考试形式:闭卷 一.单选题(本题满分 ...

  6. 安徽大学java期末_安微大学2017~2018年度期末考试题卷

    原标题:安微大学2017~2018年度期末考试题卷 备考备考备考! 六月来啦,期末考还会远吗? 别人家的形势与政策课试题又一次刷新三观 你会做这样的题吗 怎么判断自己是不是个合格的AHUer? 锵锵锵 ...

  7. 河南会考操作题计算机考试试题,2017河南会考试题及答案

    2017河南会考试题及答案,2017年1月河南省2015级普通高中学生学业水平考试试题答案汇总 河南:郑州 信阳 周口 驻马店 安阳 开封 洛阳 平顶山 焦作 鹤壁 新乡 濮阳 许昌 漯河 三门峡 南 ...

  8. 2017计算机应用+简答,2017计算机应用基础试题及答案

    2017计算机应用基础试题及答案 三.双项选择题(每小题1分,共5分) 1.计算机的存储系统一般指( ) A.ROM B.内存(主存) C.RAM D.外存(辅存) E.控制器 2.微型计算机采用总线 ...

  9. ai不同形状的拼版插件_AI矩形/异型自动排料插件AINester 16.0(支持Illustrator CC 2015/2017)...

    AI矩形/异型自动排料插件AINester 16.0(支持Illustrator CC 2015/2017) 书法字体2017.07.31AINester 分享一款支持AI CS6/CC 2015/2 ...

最新文章

  1. day03-字符编码与转换
  2. php项目自动布署mysql_如何自动化一键部署PHP项目
  3. 机器人简化图画手绘图_床上用的扫地机器人,彻底清除细菌,不再担心酒店卫生问题...
  4. 内存管理中的几种地址类型
  5. Docker部署OpenProject
  6. X Window Messing With The Mouse Cursor
  7. 【EntityFramework系列教程五,翻译】在ASP.NET MVC程序中借助EntityFramework读取相关数据...
  8. ambari安装中常见的问题
  9. python 代码行数统计工具_Python实现一个代码行数统计工具
  10. php redis hscan 示例,phpredis到底该如何使用hScan(范例)
  11. 客户端的云桌面平台配置与开启(附,登录“云电脑”与切换登录账号)
  12. eclipse插件下载速度慢,可以这样解决
  13. 零成本学arduino教程——光敏电阻传感器
  14. python中msg是什么意思_MSG是什么意思?
  15. 解决onebot提示当前QQ版本过低,请升级到最新版在登录!
  16. postgresql安装报错
  17. 干货!史上最全数据分析学习路线(附资源链接)
  18. 结合Java和机器学习技术,如何驾驭大数据提升业务效率和竞争力?
  19. java第三方登录总结
  20. 安装类Excel开发工具设计器

热门文章

  1. 石像鬼(Gargoyle)1.8.1 ar71xx SS + pdnsd 实现代理
  2. 「开眼」,让你非常开眼的一个开源项目
  3. 惯性导航原理之姿态算法-四元数欧拉角等效转动矢量
  4. Artificial Intelligence A Modern Approach 第二版笔记(二)
  5. 做什么,怎么做?(20210615)
  6. 利用django做毕业设计
  7. 从AndFix源码看Android热修复
  8. 由于找不到msvcp140.dll,一键解决电脑缺失msvcp140.dll
  9. pyaudio音频录制及基础音频知识理解
  10. 汇编语言程序设计读书笔记(4)- 程序设计基础之一