本试题一共分为12道题,考核点全部以C语言为主,难度有层次划分,希望你尽最大努力完成,我们
不需要你每道题都能得到正确答案,但希望你能有良好的学习态度。我们期待在面试那天与你相
遇!
(本测试题目省略#include…,编程题只用写出核心代码,你也可以在面试时带上U盘或者电脑直接展
示你的结果!)
考点:运算符
#include<stdio.h>
#include<stdlib.h>
int main(void){
int i=3;//3
int k=4;//4
k += (k++) - (--i);//5+ 4(5)- 2
printf("%d",k);
return 0;
}
a)6 b)7 c)8 d)9
考点:运算符<<:位运算左移
<<= 赋值运算符
? : 条件运算符
#include <stdio.h>
int main() {
int a = 2, b = 3;
printf("%d\n", a <<= a < b ? a + b : a - b );
//a < b ? a + b : a - b 为5 a<<=5 --> a=a<<5=2<<5=2*2^5=64
return 0;
}
A)-32 b) 64 c)2*(2^-5) d)1*(2^-5)
考点:运算符的优先级和结合性
下表按照题目中运算符出现顺序排列
优先级 | 运算符 | 含义 | 结合性 |
---|---|---|---|
15 | , | 逗号运算符 | 自左至右 |
2 | ++ | 自增运算符 | 自右至左 |
10 | || | 逻辑或运算符 | 自左至右 |
14 | = | 赋值运算符 | 自右至左 |
2 | -- | 自减运算符 | 自右至左 |
注意:在逻辑表达式的求解中,并不是所有的逻辑运算符都要被执行,只有在必须下一个逻辑运算符才能求出表达式的解时,才执行该运算符。
例如:
int x=-1;
执行++x||++x||++x后,x的值是多少?
分析:根据逻辑“||”自左至右的结合性,先计算第一个“”左边的运算对象++x,得到结果为0。
对于“||”运算符来说还不能确定这个表达式的值,必须再计算右边的++x,得到结果为1。
此时第一个“||”结合的表达式的值就为1,这样无论第二个“||”运算符后面的运算对象值为多少,整个表达式的值已经确定为1。所以不需再计算第三个++x了,因而x的值为1。
说回题目
int main(int argc, char const* argv[])
{
int a = 0, b = 5;
++a || ++b, a - b;//a变成1 ||表达式的值为1,后面的++b不会执行
b = b--;//b=5 --
printf("%d %d\n", a, b);//1 5
return 0;
}
考点:运算符
# include <stdio.h>
int main() {
int a = 0;//a为0
int b = 0 == a;//0==a的值为1 ,b为1
int c = -1;//c为1
if (a = 1) {//a赋值为1
c = a && b;//c=1&&1=1
}
printf("%d%d%d", a, b, c);//111
return 0;
}
考点:struct 的内存对齐
以下引用自https://blog.csdn.net/weixin_30432007/article/details/97729396
1、字节对齐的细节和编译器实现相关,但一般而言,如在windows下,就VC而言,满足一下三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
即:在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量:sizeof(类型)或其倍数
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)
即:最大sizeof(类型)的整数倍
类型
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char 偏移量必须为sizeof(char)即1的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
Short 偏移量必须为sizeof(short)即2的倍数
说回题目
# include <stdio.h>
#pragma pack (8) /*指定按8(默认)字节对齐*/
int main(){
struct x{ //16 2*8
int a; //4 Bytes ,此时偏移量为4
char b; //1 Byte ,偏移量4是1的倍数,此时偏移量为5
double c; //8 Bytes ,此时偏移量5不是8的倍数,填充3,使偏移量为8,然后为c开辟8个空间,此时偏移量为16
};
struct y{ //16 2*8
float b; //4 Bytes ,此时偏移量为4
int a; //4 Bytes ,偏移量4是4的倍数,此时偏移量为8
double c; //8 Bytes ,偏移量8是8的倍数,此时偏移量为16
};
struct z{ //24 3*8
int a; //4 Bytes ,此时偏移量为4
double c; //8 Bytes ,偏移量4不是8的倍数,填充4,此时偏移量为8,然后为c开辟8个空间,此时偏移量为16
char b; //1 Byte , 此时偏移量16是1的倍数,偏移量为17,结构体的总大小为结构体最宽基本类型成员大小的整数倍,即需是8的整数倍,需要编译器会在最末一个成员之后加上填充字节(trailing padding),填充8*3-17=7个,此时偏移量为24
};
printf("%d\n",sizeof(struct x)); //16
printf("%d\n",sizeof(struct y)); //16
printf("%d\n",sizeof(struct z)); //24
}
共用体内存大小:为最大元素的内存大小
指针内存大小:在64bits机器中所有指针内存大小为8字节
数组内存大小:数组和数组长度个单独数组元素类型相等
#include<stdio.h>
union UNode{
char ch; // 1 Byte
int in; // 4 Bytes
char *p; //8 在64bits机器中所有指针8字节
};
struct SNode{
char ch; // 1 Byte
short sh; // 2 Bytes
int in; // 4 Bytes
float f; //4
double db; //8
char *p; //8 在64bits机器中所有指针8字节
char arr[5]; //数组和5个单独类型相等,相当列出5个char在根据原则对齐
};
int main(){
printf("%d",sizeof(struct SNode));//40
printf("%d",sizeof(union UNode));//8
}
考点:指针和数组
*(a+i)==a[i]
数组元素的存储地址计算
# include <stdio.h>
/*
&a+i=a+i*sizeof(a) 偏移的是i个数组长度
a+i=a+i*sizeof(a[0]) 偏移的是i个数组元素长度 */
int main(){
int a[3][4];
int i,j;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
a[i][j]=i*j;
}
}
for(i=0;i<3;i++){
for(j=0;j<4;j++){
printf("%d",a[i][j]);
}
printf("\n");
}
printf("%d\n",&a[1][2]);
printf("%d\n",a[1][2]);
printf("答案\n");
printf("%d\n",*(*(a+1)+2));
printf("%d\n",*(*a+6));
printf("扩展\n");
printf("%d\n",&a[0][0]);
printf("%d\n",a);//a存的是首元素 a[0][0]的首地址 ,其实还存了它的类型 int
printf("%d\n",*a);//*a存的是a[0]的首地址
printf("%d\n",**a);//**a存的是a[0][0]的值
}
考点:scanf的返回值的含义
scanf函数返回 int型 成功读入的数据项数,
读入数据时遇到了“文件结束”则返回EOF -1。
# include <stdio.h>
int main() {
int n;
printf("%d", scanf("%d", &n));//输入非数值型为0,输入数值型为1,输入Ctrl+Z为-1
return 0;
}
#include<stdio.h>
int main(){
int a=43;
printf("%d",printf("%d",printf("%d",a)));//4321
}
在第i趟的记录序列中选取关键字第i小(大)的记录作为有序序列的第i个记录
#include <stdio.h>
#define N 10
int main()
{
int a[N],n,i,k,j,t;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf ("%d",&a[i]);
for(i=0;i<n-1;i++){
k=i;
for(j=i+1;j<n;j++){
if(a[k]<a[j])
k=j;
}
if(k!=i){
t=a[i];
a[i]=a[k];
a[k]=t;
}
}
for (i=0;i<n;i++)
printf("%d ",a[i]);
}
冒泡排序也叫相邻比逆法,即在扫描待排序序列时,顺次比较相邻记录的关键字大小,如果逆序就
交换位置
#include <stdio.h>
#define N 100
int main()
{
int a[N],n,i,j; //输入
scanf("%d",&n);
for(i=0;i<n;i++){
scanf ("%d",&a[i]);
}
for(i=0;i<n;i++){
for(j=0;j<n-1-i;j++){
if(a[j]>a[j+1]){
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
for (i=0;i<n;i++) { //输出
if(i==0)
printf("%d",a[i]);
else
printf(" %d",a[i]);
}
}
#include <stdio.h>
#define N 100
int main()
{
int a[N],n,i,j; //输入
scanf("%d",&n);
for(i=0;i<n;i++){
scanf ("%d",&a[i]);
}
int change=1;
for(i=0;i<n&&change;i++){
change=0;
for(j=0;j<n-1-i;j++){
if(a[j]>a[j+1]){
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
change=1;
}
}
}
for (i=0;i<n;i++) { //输出
if(i==0)
printf("%d",a[i]);
else
printf(" %d",a[i]);
}
}
#include <stdio.h>
#define N 100
int main()
{
int a[N],n,i,j; //输入
scanf("%d",&n);
for(i=0;i<n;i++){
scanf ("%d",&a[i]);
}
int flag;
for(i=0;i<n;i++){
flag=0;
for(j=0;j<n-1-i;j++){
if(a[j]>a[j+1]){
flag=1;
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
if(flag){
break;
}
}
for (i=0;i<n;i++) { //输出
if(i==0)
printf("%d",a[i]);
else
printf(" %d",a[i]);
}
}
简单桶排序:相当于计数器数组
给要排序的数组元素计数
计数器数组的索引为要排序的数组元素
计数器数组元素为要排序的数组元素出现个数
#include<stdio.h>
#define N 9
int main(){
int num[N]={1,2,3,4,2,3,5,4,6};
int i=0;
//输出原数组
for(i;i<N;i++){
printf("%d ",num[i]);
}
printf("\n");
//建立空桶
int count[9]={0};
//桶中放每一个桶的序号count[]的对应于num数组每个数num[i]的个数
for(i=0;i<N;i++){
count[num[i]]++;
}
//输出桶
for(i=0;i<N;i++){
printf("%d-%d ",i,count[i]);
}
printf("\n");
//输出排序
for(i=0;i<N;i++){
int j;
for(j=0;j<count[i];j++){
printf("%d ",i);
}
}
}
设计一个程序实现字符串翻转,即将abcdefg反转成gfedcba,已经为你写好了部分代码,请在规定的区域添加代码来实现程序。
不允许在规定地方之外写代码,不允许删除写过的代码。
代码本来就定义了一个字符串和一个字符变量和一个整型数,不允许声明新的任何类型的变量。
考点:字符串翻转
要求:空间复杂度为O(1),即不允许声明新的任何类型的变量。
实现:字符串内部操作
# include <stdio.h>
# include <string.h>
int main() {
char s[32];
scanf("%s", s);
int n = strlen(s);
char ch;
int i;
/* 规定区域开始 */
for(i = 0;i<=n/2;i++){
ch=s[i];
s[i]=s[n-1-i];
s[n-1-i]=ch;
}
/* 规定区域结束 */
printf("%s", s);
return 0;
}
# include <stdio.h>
# include <string.h>
int main() {
char s[32];
scanf("%s", s);
int n = strlen(s);
int i;
/* 规定区域开始 */
i=0;
n=n-1;
while(i<n){
//交换元素是s[i]与s[n]
s[i]=s[i]+s[n];
s[n]=s[i]-s[n];
s[i]=s[i]-s[n];
i++;
n--;
}
/* 规定区域结束 */
printf("%s", s);
return 0;
}
# include <stdio.h>
# include <string.h>
int main() {
char s[32];
scanf("%s", s);
int n = strlen(s);
int i;
/* 规定区域开始 */
i=0;
n=n-1;
while(i<n){
//交换元素是s[i]与s[n]
s[i]=s[i]^s[n];
s[n]=s[i]^s[n];
s[i]=s[i]^s[n];
i++;
n--;
}
/* 规定区域结束 */
printf("%s", s);
return 0;
}
#include<stdio.h>
void reverseSentence();
int main(){
printf("输入:");
reverseSentence();
return 0;
}
void reverseSentence(){
char c;
scanf("%c",&c);
if(c != '\n'){
reverseSentence();
printf("%c",c);
}
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DataType int
#define ERROR 0
#define TRUE 1
typedef struct node{
DataType data;
struct node *next;
}LNode,*LinkList;
//1.建立单链表
//尾插法建立单链表
LinkList CreatByBear(){
LinkList H=(LinkList)malloc(sizeof(LNode)); //生成头结点
H->next=NULL; //空表
LNode *s, *r=H;
int x;
printf("输入(-1结束)");
scanf("%d",&x);
while(x!=-1){
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s; //r指向新的尾结点
printf("输入(-1结束)");
scanf("%d",&x);
}
r->next=NULL;
return H;
}
//单链表的逆置
void Reverse(LinkList H){
LNode * p,*q;
p=H->next; //p指向第一个数据结点
H->next= NULL; //将原链表置为空表H
while(p){
q=p;
p=p->next;
q->next=H->next; //将当前结点插到头结点的后面(头插)
H->next=q;
}
}
//遍历输出
void OutPut(LinkList head){
LNode *p;
p=head->next;
while(p){
printf("(%d)\n",p->data);
p=p->next;
}
}
void main(){
//建立
LinkList h=CreatByBear();
printf("输出");
OutPut(h);
Reverse(h);
printf("逆置");
OutPut(h);
}