西邮Linux兴趣小组2021纳新面试题

1.大小和长度竟然不是一个意思

(1)、sizeof()和strlen()有什么异同之处?

(2)、他们对于不同的参数结果有什么不同?请试举例子说明。

#include<stdio.h>
int main()
{
    char s[]="I Love Linux";
    int a=sizeof(s);
    int b=strlen(s);
    printf("%d %dn",a,b);
    return 0;
}

该程序的输出结果为:16 12

sizeof()是 运算符,返回的是变量声明后所占的内存数(包括字符串的最后一个'')其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等

strlen()是函数,它用来计算指定字符串的长度,但不包括结束字符(即 遇到NULL字符就停止计算)

2.箱子的大小和装入物品的顺序有关

test1和test2都含有一个short、一个int、一个double,那么sizeof(t1)和sizeof(t2)是否相等呢?这是为什么呢?

#include<stdio.h>
struct test1{
    int a;
    short b;
    double c;
};
struct test2{
    short b;
    int a;
    double c;
};
int main()
{
    struct test1 t1;
    struct test2 t2;
    printf("sizeof(t1):%dn",sizeof(t1));
    printf("sizeof(t2):%dn",sizeof(t2));
    return 0;
}

该程序的输出是:

sizeof(t1):16
sizeof(t2):16

该程序中定义了两个结构题t1和t2;根据结构体的内存对齐机制可知:

在t1结构体中,第一个先定义了int类型的变量a,占4个字节(假设地址从0开始),第二个是short类型的变量b,占两个字节,在内存中可以紧跟在变量a之后,第三个定义了一个double类型的变量c占八个字节,因为前两个变量ab在一起一共占用了前面六个字节,c是八个字节就必须从八的倍数处的地址开始存储,因此变量ab之后有两个字节的位置被空了出来,因此结构体t1一共占了16个字节。

如图所示:(t1结构体)

在t2结构体中,内存的如下图所示:

3.哦,又是函数

想必在高数老师的教导下大家十分熟悉函数这个概念。那么你了解计算机程序设计中的函数吗?请编写一个func函数,用来输出二位数组arr中每个元素的值

/*在这里补全func函数的定义*/
int main()
{
    int arr[10][13];
    for(int i=0;i<10;i++){
        for(int j=0;j<13;j++){
            arr[i][j]=rand();
        }
    }
    func(arr);
}

代码如下:

#include<stdio.h>
#include<stdlib.h>

void func(int a[][13], int m, int n);

int main()
{
	int arr[10][13];
	for(int i = 0;i<10;i++){
		for(int j = 0;j<13;j++){
			arr[i][j] = rand();
		}
	}
	func(arr,10,13);
	
	return 0;
}

void func(int a[][13], int m, int n)
{
	for(int i = 0;i<m;i++){
		for(int j = 0;j<n;j++){
			printf("%d ",a[i][j]);
		}
	}
}

4.就不能换个变量名吗?

(1)、请结合下面的程序,简要谈谈传值和传址的区别;

(2)、简要谈谈你对C语言中变量的生命周期的认识:

#include<stdio.h>
int ver=123;
void func1(int ver){
    ver++;
    printf("ver = %dn",ver);
}
void func2(int *pr){
    *pr=1234;
    printf("*pr = %dn",*pr);
    pr=5678;//将int类型的数字赋给指针变量,错误
    printf("ver = %dn",ver);//输出全局变量ver:123
}
int main()
{
    int a=0;
    int ver=1025;
    for(int a=3;a<4;a++){
        static int a=5;
        printf("a=%dn",a);
        a=ver;
        func1(ver);
        int ver=7;
        printf("ver = %dn",ver);
        func2(&ver);
    }
    return 0;
}

该程序的输出结果是:

a = 5
ver = 1026
ver = 7
*pr = 1234
ver = 123

  1. 传值:传值,实际是把实参的值赋值给行参,相当于copy。那么对行参的修改,不会影响实参的值 。
  2. 传址: 实际是传值的一种特殊方式,只是他传递的是地址,不是普通的赋值,那么传地址以后,实参和行参都指向同一个对象,因此对形参的修改会影响到实参。

C语言中的变量及其生命周期:

1、局部变量: 
        生命周期: 从定义开始, 到该模块结束
        作用域: 该模块内

2、全局变量:
        生命周期: 从定义开始, 到程序结束
        作用域: 文件内(用 extern 声明则适用于整个工程)

 3、static修饰的局部变量:
        生命周期:从定义开始,到程序结束
        作用域: 该模块内

4、static修饰全局变量:
        生命周期:从定义开始,到程序结束
        作用域: 被限制在该文件内使用
 

5.套哇真好玩!

请说明下面的程序是如何完成求和的?

#include<stdio.h>
unsigned sum(unsigned n)
{
    return n?sum(n-1)+n:0;
}
int main()
{
    printf("%un",sum(100));
}

利用递归求1+2+3+4........+99+100的值;

第一次调用函数时为100+sum(99);

第二次调用函数时为100+99+sum(98);

以此类推;

直到最后一次100+99+98+.......+1+sum(0)=100+99+98+.......+1+0=5050

6.算不对的算术

#include<stdio.h>
int main()
{
    short a=-2;
    unsigned int b=1;
    b+=a;
    int c=-1;
    unsigned short d=c*256;
    c<<=4;
    int e=2;
    e=~e|6;
    d=(d&0xff)+0x2022;
    printf("a=0x%hxtb=0x%xtd=0x%hxte=0x%xn",a,b,d,e);
    printf("c=0x%hhxtn",(signed char)c);
    return 0;
}

输出为:

a=0xfffe        b=0xffffffff    d=0x2022        e=0xffffffff
c=0xf0

2020的面试题中讲过C按位运算符和移位运算符这里不做过多介绍

C按位运算符:

(1)二进制反码或按位取反:~

(2)按位与:&

(3)按位或:|

(4)按位异或:^

移位运算符:

(1)左移:<<

(2)右移:>>

本题在计算时,应注意必要时把数字转换成unsigned类型再做计算。

7.指针和数组的恩怨情仇

#include<stdio.h>
int main()
{
    int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
    int(*b)[3]=a;
    ++b;
    b[1][1]=10;
    int *ptr=(int *)(&a+1);
    printf("%d %d %dn",a[2][1],**(a+1),*(ptr-1));
    return 0;
}

输出:10 4 9

#include<stdio.h>
int main()
{
    int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
    int(*b)[3]=a;//定义一个数组指针指向一个一维数组
    ++b;         //b+1后指向数组a的第二行
    b[1][1]=10;  //b的第二行也就是a的第三行的第二个数字赋值为10
    int *ptr=(int *)(&a+1);  //&a指的是整个数组,&a+1指的是这个数组后面紧跟着的位置
    printf("%d %d %dn",a[2][1],**(a+1),*(ptr-1));
                             //**(a+1)表示为:数组a首先移动一个int[3]到数组a的第二行,然后双重解引用对二维数组取值即为4
    return 0;
}

8.移形换位之术

下面有a,b,c三个变量和四个相似的函数。

(1)、你能说出使用这三个变量的值或地址作为参数分别调用这五个函数,在语法上正确吗?

(2)、请找出下面代码的错误。

(3)、const int和int const是否有区别?如果有区别,请谈谈他们的区别;

(4)、const int*和int const *是否有区别?如果有区别,请谈谈他们的区别。

int a=1;
int const b=2;
const int c=3;
void func0(int n){
    n+=1;
    n=a;
}
void func1(int *n){
    *n+=1;
    n=&a;
}
void func2(const int *n)
{
    *n+=1;
    n=&a;
}
void func3(int *const n){
    *n+=1;
    n=&a;
}
void func4(const int *const n){
    *n+=1;
    n=&a;
}
  1. const int 和int const没有区别都是指此int类型的变量不能被修改
  2. const int*和int const*也没有区别,都是指指针指向的值不能被改变

上面的五个函数中,func2,func3,func4是错误的;

void func2(const int *n)
{
    *n+=1;//n是只读参数,不能赋值;
    n=&a;
}
void func3(int *const n){
    *n+=1;
    n=&a;//n是只读指针,不能给n赋值
}
void func4(const int *const n){
    *n+=1;//n是只读参数,不能赋值;
    n=&a;//n是只读指针,不能给n赋值
}

9.听说翻转字母大小不影响英文的阅读?

请编写convert函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换成大写字母。返回转换完成得到的新字符串。

char *convert(const char *s);
int main()
{
    char *str="XiyouLinux Group 2022";
    char *temp=convert(str);
    puts(temp);
    return 0;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char *convert(const char *s);

int main()
{
    char *str="XiyouLinux Group 2022";
    char *temp=convert(str);
    puts(temp);
    free(temp);
    return 0;
}
char *convert(const char *s)
{
    int len=strlen(s),i;
    char*ret=(char*)malloc(sizeof(char)*(len+1));
    for(i=0;s[i];i++){
        if(s[i]>='A'&&s[i]<='Z'){
            ret[i]=s[i]+32;
        }else if(s[i]>='a'&&s[i]<='z'){
            ret[i]=s[i]-32;
        }else{
            ret[i]=s[i];
        }
    }
    ret[len]='';

    return ret;
}

10.交换礼物的方式

(1)、请判断下面三种Swap的正误,分别分析他们的优缺点;

(2)、你知道这里的do{,,,}while(0)的作用吗?

(3)、你还有其他方式实现Swap的功能吗?

#define Swap1(a,b,t)    
    do{                 
        t=a;            
        a=b;            
        b=t;            
    }while(0)
#define Swap2(a,b)      
    do{                 
        int t=a;        
        a=b;            
        b=t;            
    }while(0)
void Swap3(int a,int b){
    int t=a;
    a=b;
    b=t;
}

Swap3是错误的;当调用函数的时候仅仅将ab变量的值传进去了,没有传ab的地址,相当于没有对ab做任何操作,函数运行结束后ab的值不变。

Swap1直接从原函数中传递参数,比较方便;

Swap2在参数中创建交换变量t,作用时间短,且占用内存空间小。

do{,,,}while(0)让循环只做一次//交换一次ab的值

其他的交换方式在2019年的面试题中有提到过;如图:

12.人去楼空 

这段代码是否存在错误?谈一谈静态变量与其他变量的异同。

int *func1(void){
    static int n=0;
    n=1;
    return &n;
}
int *func2(void){
    int *p=(int*)malloc(sizeof(int));
    *p=3;
    return p;
}
int *func3(void){
    int n=4;
    return &n;
}
int main(void)
{
    *func1()=4;
    *func2()=5;
    *func3()=6;
}

func3()函数有错误,之前已经定义过静态变量n之后不能对n重新定义;

静态变量属于静态存储方式,其存储空间为内存中的静态数据区(在 静态存储区内分配存储单元),该区域中的数据在整个程序的运行期间一直占用这些存储空间(在程序整个运行期间都不释放),也可以认为是其内存地址不变,直 到整个程序运行结束

13.奇怪的输出

 该题与2020年面试题第八题有异曲同工之妙,可参考2020年第八题解析。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>