西邮Linux2021年面试题

本文深入解析了C语言中的各种编程实践,包括类型转换、指针操作、数组与指针的关系、递归与循环在计算斐波那契数列中的应用、字符串处理及内存操作等。通过实例代码分析,帮助读者理解C语言的底层工作原理和编程技巧。
摘要由CSDN通过智能技术生成

请试着解释其输出。

int main(int argc, char *argv[])
{
    unsigned char a = 255;
    char ch = 128;
    a -= ch;
    printf("a = %d ch = %d\n", a, ch);
}

char的范围是-128~127,所以给一个char赋128时,实际上计算机会把它当作-127。

unsigned char的范围是0~256。 

下面代码的运行输出结果是什么,并说说你的理解。 

int main(int argc, char *argv[])
{
    char *str = "Xi You Linux Group 20";
    printf("%d\n", printf(str));
    return 0;
}

 Xi You Linux Group 2021

printf的嵌套使用,会先输出内部的printf,然后printf的返回值为输出的字符的多少,即在外层的printf输出的内容。

这段代码的输出结果是什么?为什么会出现这样的结果? 

int i = 2;
void func()
{
    if (i != 0)
    {
        static int m = 0;
        int n = 0;
        n++;
        m++;
        printf("m = %d, n = %d\n", m, n);
        i--;
        func();
    }
    else
    {
        return;
    }
}
int main(int argc, char *argv[])
{
    func();
    return 0;
}

m = 1, n = 1
m = 2, n = 1

使用static修饰符定义静态局部变量,它的生命周期是整个应用程序的运行时间,它只会被初始化一次。

下面程序会出现什么结果?为什么会出现这样的结果?

int main(int argc, char *argv[])
{
    char ch = 'A';
    int i = 65;
    unsigned int f = 33554433;
    *(int *)&f >>= 24;
    *(int *)&f = *(int *)&f + '?';
    printf("ch = %c i = %c f = %c\n", ch, i, *(int *)&f);
    return 0;
}

ch = A    i = A    f = A

65是'A'的ASCII码。

*(int *)&f相当于作强制类型转换,在左移24位之后对应的10进制数字再加上'?'对应的ASCII码,即为'A'的ASCII码。

 下面代码的运行输出结果是什么,并说说你的理解。

int main(int argc, char *argv[])
{
    int a[2][2];
    printf("&a = %p\t&a[0] = %p\t&a[0][0] = %p\n", &a, &a[0],
           &a[0][0]);
    printf("&a+1 = %p\t&a[0]+1 = %p\t&a[0][0]+1= %p\n", &a + 1,
           &a[0] + 1, &a[0][0] + 1);
    return 0;
}

&a = 0x7fff765fd630     &a[0] = 0x7fff765fd630  &a[0][0] = 0x7fff765fd630
&a+1 = 0x7fff765fd640   &a[0]+1 = 0x7fff765fd638        &a[0][0]+1= 0x7fff765fd634

(本机,本次)

数组的地址是数组内第一个元素的地址,地址+1则相当于指向下一个元素。在&a[0]中的元素是一维数组。 

 下列程序的功能是什么?有什么问题,你能找出问题并解决它吗?

int *get_array()
{
    int array[1121];
    for (int i = 0; i < sizeof(array) / sizeof(int); i++)
    {
        array[i] = i;
    }
    return array;
}
int main(int argc, char *argv[])
{
    int *p = get_array();
}

该程序返回的是一个本地数组,出了该函数,就出了该数组的生命周期,可能导致出错。用指针创建该数组即可。

 下面代码的运行输出结果是什么,并说说你的理解。

int main(int argc, char *argv[])
{
    char str[] = "XiyouLinuxGroup";
    char *p = str;
    char x[] = "XiyouLinuxGroup\t\106F\bamily";
    printf("%zu %zu %zu %zu\n", sizeof(str), sizeof(p),
           sizeof(x), strlen(x));
    return 0;
}

16 8 25 24

sizeof计算的是所占内存的大小。而strlen计算的是字符串的长度(不包含结尾的'\0')。

如下程序,根据打印结果,你有什么思考?

int add(int *x, int y)
{
    return *x = (*x ^ y) + ((*x & y) << 1);
}
int a;
int main(int argc, char *argv[])
{
    int b = 2020;
    if (add(&b, 1) || add(&a, 1))
    {
        printf("XiyouLinuxGroup%d\n", b);
        printf("Waiting for y%du!\n", a);
    }
    if (add(&b, 1) && a++)
    {
        printf("XiyouLinuxGroup%d\n", b);
        printf("Waiting for y%du!\n", a);
    }
    return 0;
}

 

XiyouLinuxGroup2021
Waiting for y0u!

^或运算,&与运算,<<右移 

||在第一个式子成立后,不再进行第二个式子的判断,

&&在第一个式子不成立后,不再进行第二个式子的判断。

 在下段程序中,我们可以通过第一步打印出 a 的地址,假如在你的机器上面打印结果是 0x7ffd737c6db4;我们在第二步用 scanf 函数将这个地址值输入变量 c 中;第三步,随机输入一个数字,请问最终输出了什么结果,你知道其中的原理吗?

void func()
{
    int a = 2020;
    unsigned long c;
    printf("%p\n", &a);
    printf("我们想要修改的地址:");
    scanf("%lx", &c);
    printf("请随便输入一个数字:");
    scanf("%d", (int *)c);
    printf("a = %d\n", a);
}
int main(int argc, char *argv[])
{
    func();
}
运行开始输出的是a所在的地址,通过修改该地址的内容来达到修改a的值的作用。

请问一个 C 语言程序从源代码到可执行文件中间会进行哪些过程,你能简单描述一下每个环节都做了什么事情吗?

1、预处理

在预处理阶段,编译器主要作加载头文件、宏替换、条件编译的作用。一般处理带“#”的语句。

2、编译

在编译过程中,编译器主要作语法检查和词法分析。我们可以通过使用 -S 选项来进行查看,该选项预处理之后的结果翻译成汇编代码。

3、汇编

在汇编过程中,编译器把汇编代码转化为机器代码。

4、链接

链接就是将目标文件、启动代码、库文件链接成可执行文件的过程,这个文件可被加载或拷贝到存储器执行。

 请解释一下这行代码做了什么?

puts((char *)(int const[]){
    0X6F796958, 0X6E694C75, 0X72477875,
    0X3270756F, 0X313230, 0X00000A});

定义了一个新数组const,并初始化。之后强制类型转换为char类型指针,其内容被作为char类型输出了出来。 

请随机输入一串字符串,你能解释一下输出结果吗?

int main(int argc, char *argv[])
{
    char str[1121];
    int key;
    char t;
    fgets(str, 1121, stdin);
    for (int i = 0; i < strlen(str) - 1; i++)
    {
        key = i;
        for (int j = i + 1; j < strlen(str); j++)
        {
            if (str[key] > str[j])
            {
                key = j;
            }
        }
        t = str[key];
        str[key] = str[i];
        str[i] = t;
    }
    puts(str);
    return 0;
}

通过冒泡排序实现对字符的排序。其中使用fgets来读取用户的输入。 

 用循环和递归求 Fibonacci 数列,你觉得这两种方式那种更好?说说你的看法。如果让你求 Fibonacci 数列的第 100 项,你觉得还可以用常规的方法求解吗?请试着求出前 100 项的值(tip 大数运算)。

递归代码简洁,但时间复杂度高。循环代码较递归繁琐,但耗时短。

使用大数加法实现斐波那契数列

#include <stdio.h>
#include <string.h>
int a[1005][1005];
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n;
		scanf("%d",&n);
		int c;
		int d=0;
		memset(a,0,sizeof(a));
		a[1][0]=1;a[2][0]=1;
		for(int i=3;i<=n;i++)
		{
			c=0;
			for(int j=0;j<=d;j++)
			{
		    	a[i][j]=a[i-1][j]+a[i-2][j]+c;
				c=a[i][j]/10;
				a[i][j]%=10;
			}
			while(c!=0)
			{
				a[i][++d]=c%10;
				c/=10;
			}
		}
		for(int i=d;i>=0;i--)
		{
			printf("%d",a[n][i]);
		}
		printf("\n");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

binary~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值