大道五十,天衍四十九,人遁其一!
# 写在前面
智能涂鸦整体感觉还好,没有想象中的难。涉及到 linux 基础,c 语言,makefile 方向的知识
# Linux 方向
linux 这一块考了 一个 malloc 是系统那部分提供的方法,一个 linux 端口占用查看
这一方面我的知识比较欠缺,端口查看是 netstat -tunlp
, malloc 的提供方盲猜了个 glibc
, 事实也就是这个。当时是想 malloc
也是个库函数,八成和 GUN 有关系。还真就是 gun libraries c
.
PS: glibc 是 linux 下面 c 标准库的实现,即 GNU C Library
# makefile
这个就考了一个问题:
定义一个可以跨文件的 makefile 变量的关键字
很巧,我就会这一个,考其他的。我还真不一定能能记得,因为 makefile
也是大一的时候学的,都忘完了つ﹏⊂
答案是 export
# C 语言
余下的都是 C 语言的题目,毕竟这个才是重头戏.
老生常谈的考了 static 的作用,这个在这篇文中说过我就不再细说
接下去就说一些不一样的
# 字节对齐
#pragma pack(x)
的作用和一字节对齐.
题目大概是这样的:
求 下面结构体的大小
#pragma pack(1)
struct node{char a
int b; double c; };
结构体大小必然需要考虑到 内存对齐,但是这里比较有意思的就是 有一句 #pragma pack(1)
, 这表示结构体按一字节对齐
如果没有这句宏那么,结果就是 32 位机下 1+4+8+(3) 字节,后面 这三个字节是补全 char
类型 4 字节对齐.
但是因为有 就变成的 1 字节对齐,所以结果是 13 字节
PS: #pragma pack () 是解除 1 字节对齐
实际测试代码如下 (偷个懒,用 cpp 输出比较快):
#include <iostream> | |
using namespace std; | |
#pragma pack(1) // 一字节 对齐 | |
struct node | |
{ | |
char a; | |
int b; | |
double c; | |
}; | |
#pragma pack() // 解除 1 字节对齐 | |
struct Node | |
{ | |
char a; | |
int b; | |
double c; | |
}; | |
int main(int, char **) | |
{ | |
cout << sizeof(node) << endl; | |
cout << sizeof(Node) << endl; | |
} |
# 柔性数组 (0 长数组)
这道题是我唯一不确定的题目,应为用到的太少了 (个人)
题目大致如下:
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
typedef struct Data_t | |
{ | |
char value; | |
int temp; | |
short len; | |
char arr[0]; | |
} Flex_Array_t; | |
int main(void) | |
{ | |
int len = 2; | |
char *buf = (char *)malloc(sizeof(Flex_Array_t) + len); | |
for (int i = 0; i < sizeof(Flex_Array_t) + len; i++) | |
{ | |
buf[i] = i; | |
} | |
Flex_Array_t *Array = buf; | |
printf("array.value = %x\n", Array->value); | |
printf("array.temp = %x\n", Array->temp); | |
printf("array.len = %x\n", Array->len); | |
printf("array.arr[0] = %x\n", Array->arr[0]); | |
printf("array.arr[1] = %x\n", Array->arr[1]); | |
return 0; | |
} |
这里考了两个知识点,一个是字节对齐,另一个是柔性数组.
在 32 位机的条件下,4 字节对齐,所以大小是 1+4+2 +(3+2)= 12 字节,0 长数组不占空间,
0 长数组,在 ISO 标准里是不支持的,但是 gcc 在 c99 中预先提供了支持。相关文档再此:"Arrays of Length Zero."
我感觉 0 长数组的结构体其实就和 extern int arr[]
极其类似 (不过没有跨文件作用域的效果), 在没有定义变量之前都不会产生存储, sizeof
的结果下他们并不占用空间。对于 Flex_Array_t
也是同一个道理.
其实,严格意义上来说,0 长就类似数组首地址,而数组的首地址仅仅是一个标签,不占用空间,例如
#include <stdio.h> | |
int arr[10]; | |
int main(int argc, char const *argv[]) | |
{ | |
arr[9] = 0xff; | |
return 0; | |
} |
其汇编代码如下
arr 存储在 为一个内存标签,和 main 标签作用类似 (.comm 是声明未初始化的内存段空间)
PS: 这也是指针和数组首地址的最大不同
回到题目,这道题目在弄清楚这两个问题和就变简单了, buf
的大小为 14, 那么 buf
被 赋给 Array
的时候,就是从 arr[0]
开始赋值到 arr[13]
为止
那么就可以先得出 Array.arr[0]
和 Array.arr[1]
分别为 0x0a
和 0x0b
, 因为结构体的数组不占空间,多出的那 len
必然是给 arr[0]
的.
余下的就很好推断了 Array.value = 0
, 补齐 3 字节, Array.temp = 0x07060504
, int
本为 4 字节不用补齐. Array.len = 0x0908
, short
类型补齐 2 字节.
嗯?!到这里就有一个大问题了既然补齐了 short
两个字节,那么为什么 arr
数值不是未知数呢?前面说过 柔性数组 大小为 0, 我们开辟的空间大小为 结构体大小大再多上 2 字节.
我们使用 malloc
函数开辟出的空间是连续的所以对于 柔性数组来说,不管前面补没补齐,都从上一个数据类型结束初开始计算,算是一个 c99 的特性吧.
具体原因我以后在琢磨琢磨.
# 冒泡排序
冒泡排序的实现难度较低,我之前写过一遍介绍冒泡排序及其优化的文章,感兴趣的可以去看看传送门.
# memmove 实现
这就是面完没两个小时的丙甲,刚问过这就直接撞上了,都是缘分啊。感兴趣可以去看看传送门.
大道五十,天衍四十九,人遁其一!