应用开发工程师A卷
一、单选题共16题,合计80分
1(5分)
手机号正则表达式正确的是( 不会 ) [单选题] *
A. /^[1]([3-9])[0-9]{9}$/
B. /^[1]([3-9])[0-9]?$/
C. / [1]([3-9])[0-9]+/
D. /^[1] [0-9]{10}$/
2(5分)
列出当前目录下所有.h的文件,含子目录( c ) [单选题] *
A. ls *.h
B. find . -name *.h
C. find . -name *.h$
D. find . |grep h
3(5分)
以下最宽松的开源许可证是 ( A ) [单选题] *
A. GPL
B. BSD
C. Apache
D. MIT
4(5分)
假定一个类的构造函数为“A(int i=4, int j=0) {a=i;b=j;}”, 则执行“A x (1);”语 句后,x.a和x.b的值分别为( D )
A. 4和1
B. 4和0
C. 1和4
D. 1和0
5(5分)
对数组名作函数的参数,下面描述正确的是( B )。
A. 数组名作函数的参数,调用时将实参数组复制给形参数组
B. 数组名作函数的参数,主调函数和被调函数共用一段存储单元
C. 数组名作参数时,形参定义的数组长度不能省略
D. 数组名作参数,不能改变主调函数中的数据
6(5分)
进程在从磁盘读取数据时会进入:B
A. 就绪态
B. 阻塞态
C. 运行态
D. 终止态
# 相关知识
# https://www.cnblogs.com/still-smile/p/12052067.html
7(5分)
列出当前目录下所有.h的文件,不含子目录 [单选题] * A
A. ls *.h
B. find . -name *.h
C. find . -name *.h$
D. find . |grep h
8(5分)
执行以下程序段后,m的值为 ( A )。
int a[2][3]={{1,2,3},{4,5,6}};
int m,*p=&a[0][0];
m=(*p)*(*(p+2))*(*(p+4));
A. 15
B. 14
C. 13
D. 12
# 等价于m[2]*m[1],注意数组下角标从0开始,p+4相当于移动到了5
9(5分)
下面哪一个不是一种临界区保护机制:C
A. 互斥锁
B. 信号量
C. 条件变量
D. 读写锁
10(5分)
所谓多态性是指 ( B )。
A. 不同的对象调用不同名称的函数
B. 不同的对象调用相同名称的函数
C. 一个对象调用不同名称的函数
D. 一个对象调用不同名称的对象
11(5分)
2以下程序运行后,循环体运行的次数为( B ) [单选题] *
int i = 10, x;
for( ; i < 10; i++){x = x + i;}
A. 10
B. 0
C. 1
D. 无限
# i = 10 不小于10,循环不执行
12(5分)
下面正则表达式不能匹配的是:a*bc?d+ A
A. aaabdd
B. bcdd
C. bcd
D. abc
13(5分)
以下不是开源许可证的有( C ) [单选题] *
A. MIT
B. GPL
C. CC
D. BSD
14(5分)
以下不是C语言提供的合法关键字为( B ) [单选题] *
A. switch
B. printf
C. case
D. default
# printf 是函数
15(5分)
一个类的友元函数可以访问类的( D )成员。
A. 私有成员
B. 保护
C. 公有
D. 以上都正确
16(5分)
C语言中定义符号常量正确的是( D ) [单选题] *
A. #define PI=3.14
B. define PI 3.14
C. #define PI 3.14;
D. #define PI 3.14
二、多选题共4题,合计20分
1(5分)
unsigned long ul1 = 3,ul2 = 7;下列表达式结果正确的是( B D ) [多选题]
A. ul1 & ul2 = 3;
B. ul1 | ul2 = 7;
C. ul1 && ul2 = 0;
D. ul1 || ul2 = 1;
2(5分)
对比for循环和while循环,下面说法正确的是?( A C )[多选题]
A. 在循环已知的情况下,for循环的形式更加简洁
B. 在循环已知的情况下,while循环的形式更加简洁
C. 在循环次数无法预知时,用while循环实现更加合适
D. 在循环次数无法预知时,用for循环实现更加合适
3(5分)
假设iter的类型是vector::iterator,下面的表达式中合法的有哪些( C D ) [多选题]
A. *iter++;
B. (*iter)++;
C. Iter->empty();
D. Iter++->empty();
# * 优先级高于++, 以string为例,字符串没有++运算
4(5分)
下面哪个定义是不合法的( B D )[多选题]
A. int ival=1.01;
B. int &rvall = 1.01;
C. int &rval2 = ival;
D. int &rval3
第1题:
/***
* -------------------------------------------------------------------------------------------------------------------
* 题目
* -------------------------------------------------------------------------------------------------------------------
* 无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。并将结果按字符串从小到大排序
*
* 示例1:
* - 输入:S = "qwe"
* - 输出:["eqw", "ewq", "qew", "qwe", "weq", "wqe"]
*
* 示例2:
* - 输入:S = "ab"
* - 输出:["ab", "ba"]
*
* 要求:
* 1. 使用纯C语言修改exam.h文件,通过所有单元测试。
* 2. 代码逻辑符合题目要求,判卷评分有更多单元测试项。
* 3. 输出结果按照字典顺序排序。
* 4. exam.h以外的文件不得修改,修改会被覆盖。
*/
#ifndef EXAM_H
#define EXAM_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** permute_string(const char* input);
void sort(char* S,int len);
void DFS(char *S, int *visited, char *buf, char **res, int *index, int idx);
// main用于自己测试用,考试请勿写入。
int main()
{
const char* input = "ab";
char **s = permute_string(input);
int n = 1;
/* 计算输出长度 */
for (int i = 1; i <= strlen(input); i++) {
n *= i;
}
for(int i = 0; i < n; i++)
{
puts(s[i]);
}
return 0;
}
/* 返回一个以空字符串结尾的char*数组 */
char** permute_string(const char* input)
{
// 获取字符串长度。
int len = strlen(input);
int n = 1;
int i;
/* 计算输出长度 */
for (i = 1; i <= len; i++) {
n *= i;
}
/* 因为题目中给的是const char,这里将const char* 改为char*,方便排序 */
char *S = (char*)malloc(sizeof(char) * (len + 1) );
/* 复制字符串并且排序 */
strcpy(S, input);
// 冒泡排序
sort(S, len);
int N = 7; // 应题目要求
// 返回数组
char **res = (char**)malloc(sizeof(char*) * N);
res[N-1] = 0; // 应题目要求。
// 定义一个数组,用来来标识S[i]是否已经选取
int *visited = (int*)malloc(sizeof(int) * len);
memset(visited, 0, sizeof(int) * len);
// 用于临时存储结果
char *buf = (char*)malloc(sizeof(char) * (len + 1));
buf[len] = '\0';
// res的下角标
int *index = (int*)malloc(sizeof(int));
*index = 0;
DFS(S, visited, buf, res, index, 0);
return res;
}
/* 冒泡排序 */
void sort(char* S,int len){
int i =0, j = 0;
char temp = '\0';
for(i = 0 ; i < len-1; i++)
{
for(j = i+1 ; j < len; j++)
{
if(S[i] > S[j])
{
temp = S[i];
S[i] = S[j];
S[j] = temp;
}
}
}
}
/* DFS */
void DFS(char *S, int *visited, char *buf, char **res, int *index, int idx){
// 1. 截止条件
if(strlen(S) == idx){
res[*index] = (char*)malloc(sizeof(char) * (strlen(S) + 1));
strcpy(res[*index], buf);
(*index)++;
return;
}
// 2. 遍历候选节点
for(int i = 0; i < strlen(S); i++){
// 2.1 筛选
if(!visited[i]){
buf[idx] = S[i];
visited[i] = 1;
DFS(S, visited, buf, res, index, idx+1);
visited[i] = 0;
}
}
}
#endif // EXAM_H
第二题:
/**
*
* -------------------------------------------------------------------------------------------------------------------
* 题目
* -------------------------------------------------------------------------------------------------------------------
*
* 遵循 https://specifications.freedesktop.org/desktop-entry-spec/latest/ 标准实现一个desktop文件解析工具
*
* 功能要求
* - desktop文件格式无错误时进程退出码为0
* - 实现对desktop文件Name(程序名称)、Exec(可执行文件)、Icon(图标文件)三个字段的解析
* - 需要检测文件的格式,遇到错误时以退出码 1 退出进程
* - 输入接收一个desktop文件的绝对路径,能够输出程序名称、图标文件(图标文件不考虑从系统图标主题中查找)
* - 能够在指定一个desktop文件后启动进程,且允许为其指定参数
*
* 其它要求
* - 使用cmake构建工程
* - 可执行文件位置和名称为:./src/freedesktop
* - testHelper.sh有很少的测试用例,可以帮助做初步验证
*
* 示例
* - a.desktop文件内容为:
* [Desktop Entry]
* Name=A;
* Name[zh_CN]="我是A";
* Exec=cat %f
* Icon=/tmp/a.png
*
* - 输入参数(-d指定desktop文件的绝对路径,-n表示要获取应用程序名称):
* freedesktop -d /home/a/a.desktop -n
* - 输出结果:
* A或我是A(中文环境下,注意应该去掉引号)
*
* - 输入参数(-i表示要获取应用程序的图标)
* freedesktop -d /home/a/a.desktop -i
* - 输出结果(如图标数据不是一个文件路径,则先将图标文件保存为文件后再返回此文件的绝对路径):
* /tmp/a.png
*
* - 输入参数(-e表示要启动此应用程序,其后可根一个或多个传入参数)
* freedesktop -d /home/a/a.desktop -e /home/a/test.txt
* - 输出结果:
* 输出结果为 /home/a/test.txt 文件的内容,也就是Exec命令执行时对标准输出通道所写入的全部数据
*
*/
#include<iostream>
#include<unistd.h>
#include<cstring>
#include<string>
/* 定义了一个字符串拷贝函数。将str2从beg开始到end赋值给str1; beg和end为下角标 */
void strcopy(char* str1, char*str2, int beg, int end);
int main(int argc, char** argv)
{
char tmp[1024];
int flag[5] = {0};
char *name, *exec, *icon;
int i;
for(i = 1;i < argc; i++)
{
/* -d 文件绝对路径带解析功能 */
if( strcmp( argv[i], "-d" ) == 0 )
{
FILE *p_file = fopen(argv[i+1], "r");
while(fgets(tmp, sizeof(tmp), p_file) != NULL )
{
tmp[strlen(tmp)-1] = '\0';
if( strncmp( tmp, "[Desktop Entry]", 15) == 0 ) flag[0] = 1;
if( strncmp( tmp, "Name=", 5) == 0)
{
char *Name = (char*)malloc(sizeof(char) * ( strlen(tmp) - 5 ) );
strcopy(Name, tmp, 5, strlen(tmp));
if( Name[strlen(Name) - 1 ] == ';' || Name[strlen(Name) - 1 ] == '\n' ) Name[strlen(Name) -1] = '\0';
name = Name;
flag[1] = 1;
}
if( strncmp( tmp, "Exec=", 5) == 0)
{
char *Exec = (char*)malloc(sizeof(char) * ( strlen(tmp) - 5 ) );
strcopy(Exec, tmp, 5, strlen(tmp));
if(Exec[strlen(Exec) - 1 ] == ';' || Exec[strlen(Exec) - 1 ] == '\n') Exec[strlen(Exec) -1] = '\0';
exec = Exec;
flag[2] = 1;
}
if( strncmp( tmp, "Icon=", 5) == 0)
{
char *Icon = (char*)malloc(sizeof(char) * ( strlen(tmp) - 5 ) );
strcopy(Icon, tmp, 5, strlen(tmp));
if(Icon[strlen(Icon) - 1 ] == ';' || Icon[strlen(Icon) - 1 ] == '\n') Icon[strlen(Icon) - 1] = '\0';
flag[3] = 1;
icon = Icon;
}
if( strncmp( tmp, "Name[zh_CN]=", 5) == 0)
{
flag[4] = 1;
}
}
fclose(p_file);
// 遇到错误时以退出码 1
if( ! ( flag[0] == 1 && flag[2] == 1 && flag[3] == 1 && (flag[4] == 1 || flag[1] == 1) ) )
exit(1);
}
}
for(i = 1 ; i < argc; i++)
{
/* -n 获取名称 */
if( strcmp( argv[i], "-n" ) == 0 )
{
std::cout << name << std::endl;
}
/* -i Icon 路径获取 */
if( strcmp( argv[i], "-i" ) == 0 )
{
std::cout << icon << std::endl;
}
/* -e 运行 */
if( strcmp( argv[i], "-e" ) == 0 )
{
std::string s = "cat ";
std::string temp;
int j = i + 1;
while( argv[j] != NULL )
{
temp = argv[j];
s += temp;
s += " ";
j++;
}
char cmdTemp[1024];
strcpy(cmdTemp,s.c_str());
FILE *pp = popen(cmdTemp, "r");
char tmp[1024];
while(fgets(tmp, sizeof(tmp), pp) != NULL)
{
std::cout << tmp ;
}
pclose(pp);
}
}
return 0;
}
void strcopy(char* str1, char*str2, int beg, int end)
{
int i;
for( i = 0; i < end - beg + 1 ; i++ )
{
str1[i] = str2[ beg + i];
}
}
第三题:
/**
* 编写一个颜色列表程序,功能及要求如下:
*
* - 实现的功能是:添加、删除颜色项。
* - 颜色列表继承QListView,不许使用QListWidget。数据Model继承QAbstractItemModel。
* - 界面上有这几个元素(如何布局不做强制要求):
* - 颜色列表控件:按行显示每个颜色条目。每个条目显示添加时指定的颜色。
* - 一个QComboBox,可以下拉选择这几种颜色:red, green, blue, cyan, yellow, purple, white, black
* - 一个QPushButton实现’添加‘新的颜色项。添加QComboBox当前的颜色到列表中。
* - 一个QPushButton实现’删除‘选择的颜色项。如果没有选择一个列表中的项,disabled状态
*/
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QAbstractItemModel>
#include <QStyledItemDelegate>
#include <QListView>
namespace Ui {
class MainWindow;
}
class ItemDelegate : public QStyledItemDelegate
{
public:
ItemDelegate(QObject *parent = nullptr);
};
class ListModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit ListModel();
~ListModel();
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
virtual QModelIndex parent(const QModelIndex &child) const override;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
};
class ListView : public QListView
{
Q_OBJECT
public:
explicit ListView(QWidget *parent = nullptr);
~ListView();
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
friend class autoTest;
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
ListModel *m_Model;
ItemDelegate *m_Delegate;
ListView *m_ListView;
};
#endif // MAINWINDOW_H
// Mianwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QVBoxLayout"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_Model=new ListModel();
m_ListView=new ListView();
m_Delegate=new ItemDelegate();
m_ListView->setModel(m_Model);
m_ListView->setItemDelegate(m_Delegate);
QVBoxLayout * layout = new QVBoxLayout(ui->widget);
layout->addWidget(m_ListView);
}
MainWindow::~MainWindow()
{
delete ui;
}
ListView::ListView(QWidget *parent)
{
}
ListView::~ListView()
{
}
ListModel::ListModel():
QAbstractItemModel()
{
}
ListModel::~ListModel()
{
}
QVariant ListModel::data(const QModelIndex &index, int role) const
{
// // 节点内容:左对齐,显示行列号
// if (role == Qt::TextAlignmentRole)
// return int(Qt::AlignLeft | Qt::AlignVCenter);
// else if (role == Qt::DisplayRole)
// return QString("row=%1,col=%2").arg(index.row()).arg(index.column());
// else
// return QVariant();
}
int ListModel::columnCount(const QModelIndex &parent) const
{
// 每行有量列
// return 2;
}
int ListModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
{
return 0;
}
else
{
return parent.row();
}
}
QModelIndex ListModel::parent(const QModelIndex &child) const
{
// 父节点均为跟节点
return QModelIndex();
}
QModelIndex ListModel::index(int row, int column, const QModelIndex &parent) const
{
// 创建普通索引
return createIndex(row, column);
}
ItemDelegate::ItemDelegate(QObject *parent)
{
}
第1题:
* -------------------------------------------------------------------------------------------------------------------
* 题目
* -------------------------------------------------------------------------------------------------------------------
* 输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
*
* 示例 1:
* 给定二叉树 [3,9,20,null,null,15,7]
* 3
* / \
* 9 20
* / \
* 15 7
* 返回 true 。
*
* 示例 2:
* 给定二叉树 [1,2,2,3,3,null,null,4,4]
* 1
* / \
* 2 2
* / \
* 3 3
* / \
* 4 4
* 返回 false 。
*
* 要求:
* 1. 使用纯C语言完善exam.h文件,通过所有单元测试
* 2. 代码逻辑符合题目要求,判卷评分有更多单元测试项
* 3. 除exam.h以外的文件不得修改,修改会被覆盖
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
};
int getTreeDepth(struct TreeNode* node)
{
int rightDepth = 1;
int leftDepth = 1;
if(node == NULL)
{
return 0;
}
//查找左子树
if(node->left != NULL)
{
leftDepth = rightDepth + getTreeDepth(node->left);
}
//查找右子树
if(node->right != NULL)
{
rightDepth = rightDepth + getTreeDepth(node->right) ;
}
if(leftDepth >= rightDepth)
{
return leftDepth;
}
else
{
return rightDepth;
}
}
static int tree_is_balanced(TreeNode* root) {
if(root == NULL || (root->left == NULL && root->right == NULL))
{
//当到达叶子结点时候
return 1;
}
if(abs (getTreeDepth(root->left) - getTreeDepth(root->right)) > 1)
{
return 0;
}
//检查左子树 和 右子树
return tree_is_balanced(root->left) && tree_is_balanced(root->right) ;
}
第二题:
* -------------------------------------------------------------------------------------------------------------------
* 题目
* -------------------------------------------------------------------------------------------------------------------
* 编写一个程序,从命令行读取一个软件包的名称,调用“dpkg -L”命令获得该软件包的文件列表,并检查所有文件。
* 要求:
* 1. 使用cmake和c/c++开发
* 2. 可执行文件名称和位置是./src/pkgverify
* 3. 检查该软件包所有文件,确认:
* - 路径存在
* - 文件存在
* - 如果是符号链接,链接的文件也存在
* - /usr路径下的文件,确认文件属主都是root
* 4. 输出所有有问题的文件或路径名
* 5. 由于qDebug/qInfo等输出方式会添加多余字符,且不在标准输出上,与考试要求不符,请谨慎使用
* 6. testHelper.sh有很少的测试用例,可以帮助做初步验证
*
* 示例:
* 如果/etc/cups路径被删除了,则运行结果如下:
* pkgverify cups
* /etc/cups
* /etc/cups/snmp.conf
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <cstring>
int main(int argc, char** argv)
{
// 调用系统命令,最小化数组,节省空间
int len = strlen(argv[1]) + 9;
char str1[len] = "dpkg -L ";
strcat(str1, argv[1]);
// 调用系统命令,并取得返回值
FILE *pp = popen(str1, "r");
if (!pp)
return 1;
// 返回值数组
char tmp[1024];
// 初始化stat结构体buf、返回值(retRes用于判断文件是否存在);
// buf2 用于链接文件的返回存储。事实上这里仅仅为了调用,并不进行实际上的作用;
int retRes = 0;
struct stat buf;
char buf2[1024];
// 逐行读取所有的dpkg -L返回值
while(fgets(tmp, sizeof(tmp), pp) != NULL)
{
// 末尾包含 "\n",更改为"\0"结束,后面可能会有问题。
tmp[strlen(tmp)-1] = '\0';
retRes = lstat(tmp, &buf);
// 判断 文件和文件路径 是否存在;
if(retRes == 0) // 存在
{
// - 如果是符号链接
if( S_ISLNK(buf.st_mode) )
{
// 检测链接文件是否存在,不存在输出
int retResult = readlink(tmp,buf2,sizeof(buf2));
if(retResult == -1)
{
std::cout << tmp << std::endl;
}
}
// - /usr路径下的文件,确认文件属主都是root
if( strncmp("/usr", tmp, 4) == 0 )
{
if( buf.st_uid !=0 && buf.st_gid != 0)
{
std::cout << tmp << std::endl;
}
}
}
else // 文件不存在
{
std::cout << tmp << std::endl; // can join each line as string
}
}
pclose(pp);
return 0;
}
/**
* 编写一个todo程序,功能及要求如下:
*
* - 实现的功能是:添加、删除、修改todo项目。
* - todo列表继承QListView,不许使用QListWidget。数据Model继承QAbstractItemModel。
* - 界面上有这几个元素(如何布局不做强制要求):
* - todo列表控件:按行显示todo items。单击选中一个todo,双击原地修改todo的内容
* - 一个QLineEdit用于输入todo条目的内容
* - 一个QPushButton实现’添加‘新的todo,QLineEdit为空,disabled
* - 一个QPushButton实现’删除‘选择的todo,没有选择一个todo,disabled
*/
# .H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStringListModel>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
QStringListModel *theModel;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_lineEdit_textChanged(const QString &arg1);
void on_listView_clicked(const QModelIndex &index);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
main.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QStringListModel"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
theModel=new QStringListModel(this);
ui->listView->setModel(theModel);
ui->listView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
theModel->insertRows(theModel->rowCount(),1);
QModelIndex index=theModel->index(theModel->rowCount()-1,0);
theModel->setData(index,ui->lineEdit->text(),Qt::DisplayRole);
ui->listView->setCurrentIndex(index);
}
void MainWindow::on_pushButton_2_clicked()
{
QModelIndex index=ui->listView->currentIndex();
theModel->removeRows(index.row(),1);
if(index.row()<0)
{
ui->pushButton_2->setEnabled(false);
}
}
void MainWindow::on_lineEdit_textChanged(const QString &arg1)
{
if(arg1=="")
{
ui->pushButton->setEnabled(false);
}
else {
ui->pushButton->setEnabled(true);
}
}
void MainWindow::on_listView_clicked(const QModelIndex &index)
{
if(index.row()>=0)
{
ui->pushButton_2->setEnabled(true);
}
else {
ui->pushButton_2->setEnabled(false);
}
}