当前位置: 首页 > 工具软件 > ACAT > 使用案例 >

ACAT2021纳新题解(C语言)

经骁
2023-12-01

说明:

本试题一共分为12道题,考核点全部以C语言为主,难度有层次划分,希望你尽最大努力完成,我们
不需要你每道题都能得到正确答案,但希望你能有良好的学习态度。我们期待在面试那天与你相
遇!
(本测试题目省略#include…,编程题只用写出核心代码,你也可以在面试时带上U盘或者电脑直接展
示你的结果!)

题目

ACAT2021纳新题目(C语言)

参考

1. 下列选项正确的是(B.7)

考点:运算符
#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

2.下列选项正确的是(B.64)

考点:运算符<<:位运算左移
<<= 赋值运算符
? : 条件运算符
#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)

3.请分析下列代码的运行结果(1 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;
}

4.请分析下列代码的运行结果(111),并解释其原因。

考点:运算符
# 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;

}

5. 分析下列代码,请计算 x,y,z的大小(16 16 24)

考点: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
 }

6.已知 int a[3] [4],请不用中括号使用数组索引值打印出a[1] [2],printf("%d",((a+1)+2));printf("%d",*(*a+6));

考点:指针和数组
*(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]的值

} 

7.请分析以下代码的运行结果(-1或0或1),并解释其原因。

考点:scanf的返回值的含义
scanf函数返回 int型 成功读入的数据项数,
读入数据时遇到了“文件结束”则返回EOF -1。

答案

# include <stdio.h>
int main() {
	int n;
	printf("%d", scanf("%d", &n));//输入非数值型为0,输入数值型为1,输入Ctrl+Z为-1
	return 0;
}

补充:printf的返回值的含义:输出字符的数量

#include<stdio.h> 
int main(){
	int a=43;
	printf("%d",printf("%d",printf("%d",a)));//4321
}

8.你知道哪些排序算法?你知道它们是怎样实现的吗?(大致思路)

简单选择排序

在第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]);
	
 } 

冒泡排序

冒泡排序也叫相邻比逆法,即在扫描待排序序列时,顺次比较相邻记录的关键字大小,如果逆序就
交换位置

冒泡排序1.0版

#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]);
	} 
 } 
	

冒泡排序2.1版

#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]);
	} 
 } 
	

冒泡排序2.2版

#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);
		}		
	}
}

9.字符串翻转

设计一个程序实现字符串翻转,即将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;

}

扩展:去掉ch变量

用加减法实现交换

# 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);
	}
}

10. 单链表逆置,要求在原有空间进行逆置。

答案

#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); 
} 
 类似资料: