2019面试题
- 1.下面代码段将打印出多少个‘=’?运用相关知识解释该输出。
int main(int argc, char *argv[]) {
for (unsigned int i = 3; i >= 0; i--)
putchar('=');
}
打印无穷个=,死循环 因为无符号整形一定大于等于0,所以判断条件恒成立
- 2.下列三种交换整数的方式是如何实现交换的?
/* (1) */ int c = a; a = b ; b = c;
/* (2) */ a = a - b; b = b + a; a = b - a;
/* (3) */ a ^= b ; b ^= a ; a ^= b;
(1)通过中间变量交换 (2)a = a - b; b = b + a - b = a; a = a - a + b = b; (3)a
^= b; b ^= (a ^ b); a ^= b;
- 3.有如下代码段所示的函数 f,当我们执行该函数时,会产生什么样的输出结果?在同一程序中 多次执行该函数,输出结果是否一致?
void f() {
static int a = 0;
int b = 0;
printf("%d, %d\n", ++a, ++b);
}
1, 1 不相同,a为静态变量,再次调用f函数是a为上一次函数调用结束时的值,b与上次相同
- 4.下面程序段的输出是什么?请解释该现象并说出与之相关尽可能多的知识。
int main(void) {
printf("%d\n", printf("Xiyou Linux Group2%d", printf("")));
}
Xiyou Linux Group2019 第三个printf输出0个字符,空字符不算在输出内,返回值为0
第二个printf输出了18个字符加上第三个printf的返回值0共19个字符,Xiyou Linux Group20
第一个printf输出第二个printf的返回值19 Xiyou Linux Group2019
- 5.执行下面的代码段,会输出什么?请试着解释其原因,并叙述相关知识。
int main(int argc, char *argv[]) {
char ch = 255;
int d = 'a' + 1;
printf("%d %d", ch, d);
}
-1, 98 char类型占1个字节,一般为有符号,255的ascii为8个1 第一个1为符号位代表负,减一按位取反 'a’的ascii码为97+1等于98
- 6.执行以下代码段,将产生什么样的输出?请对输出加以解释,并手动计算代码中 t 的值。
int main(int argc, char *argv[]) {
char x = -2, y = 3;
char t = (++x) | (y++);
printf("x = %d, y = %d, t = %d\n", x, y, t);
t = (++x) || (y++);
printf("x = %d, y = %d, t = %d\n", x, y, t);
}
x = -1, y = 4, t = -1 x = 0, y = 5, t = 1
++x先x+1再运算,y++,先取y的值运算然后y递增1 |按位与,x与y的ascii有1为1,否则为0 ||条件左右两边有一个真为1,否则为0,左为真,右不执行 char类型以%d输出,最高位为1则前面补1,最高位为0则前面补0
- 7.下面代码段的输出结果是什么?输出该结果的原因是?
#define X a+b
int main(int argc, char *argv[]) {
int a = 1, b = 1;
printf("%d\n", X*X);
}
3
#define为替换,将所有出现X的地方替换为a+b X*X == a + b * b + a
- 8.请解释下面代码段中每一句的效果。
int val = 2018; // 定义一个名为val的变量,并赋值2018 int *pi = 2019;
//定义一个指针变量,指向地址名为2019的字节,指针越界,该内存并未分配给该程序 pi = &val; //
将val的地址赋给pi
*pi = 0; //使用指针变量修改val的值(*解引用)
- 9.执行下列程序段,并输入“Xiyou Linux”(不含引号),那么程序的输出结果是什么?请解释 其原因。
int main(int argc, char *argv[]) {
char *p = (char *)malloc(sizeof(char) * 20),
*q = p;
scanf("%s %s", p, q);
printf("%s %s\n", p, q);
}
Linux Linux p, q指向同一块内存空间,scanf输入字符串遇到空白字符结束,先存入Xiyou后存入Linux将Xiyou覆盖了
- 10.执行下面的程序段,每次执行的输出结果一致吗,整理并解释输出结果。
int main(int argc, char *argv[]) {
int a[4] = {
2, 0, 1, 9 };
printf("%p, %p\n", a, &a);
printf("%p, %p\n", a + 1, &a + 1);
}
不一致,每次内存分配都是随机的 数组名代表数组元素的首地址,第一行输出a[0]的地址,&a等价于&&a[0]输出的是整行元素的地址
a+1输出a[1]的地址,&a+1输出整行元素下一行的首地址 c语言保证数组最后一个元素的下一个元素的指针是有效的
- 11.斐波那契数列是这样的一串数列:1,1,2,3,5,8,13,…。在这串数列中,第一项、第二项 为 1,其他项为前两项之和,该数列的第 x 项可以表示为下面的函数。请根据描述,写出一个程 序,使之输入 x
后,能够输出斐波那契数列的第 x 项(其中 x<30)。当你完成之后,你可以尝试 使用递归解决这个问题。 𝑓(𝑥) = {
1, 𝑥 = 1 𝑜𝑟 𝑥 = 2 𝑓(𝑥 − 1) + 𝑓(𝑥 − 2), 𝑥 ≥ 3 (𝑥 ∈ 𝑁+)
int fib(int n)
{
if (n == 1 || n== 2)
return 1;
int f1, f2, f3, i;
f1 = 1;
f2 = 1;
for (i = 2; i < n; ++i)
{
f3 = f1 + f2;
f1 = f2;
f2 = f3;
}
return f3;
}
int fib(int n)
{
if (n == 1 || n == 2)
return 1;
else
return fib(n-1) + fib(n-2);
}
- 12.下面代码段是某一种排序算法的简单实现,你知道它是什么吗?请讲解其原理,并尝试改进 它。你还知道哪些排序算法?试着详细描述这些算法。
int main(int argc, char *argv[]) {
int nums[6] = {
6, 3, 2, 4, 5, 1 };
for (int i = 0; i < 6; i++) {
for (int j = i; j < 6; j++) {
if (nums[i] > nums[j]) {
int c = nums[i];
nums[i] = nums[j];
nums[j] = c;
}
}
}
}
选择排序,第一个元素和所有元素比,比其他大,就交换,比完第一个元素为最小的,然后第二个和所有元素比 比完第二个为次小,类推
//优化
void sort(int *a, int len)
{
int begin, end, i, t;
begin = 0;
end = len - 1;
while(begin < end)
{
int maxi, mini;
maxi = mini = begin;
for (i = begin; i <= end; ++i)
{
if (a[i] < a[mini])
{
mini = i;
}
if (a[i] > a[maxi])
{
maxi = i;
}
}
swap(&a[mini], &a[begin]);
if (begin == maxi)
{
maxi = mini;
}
swap(&a[maxi], &a[end]);
end--;
begin++;
}
}
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
- 13.请简单叙述两种字节序(大端、小端)的概念,你的机器是什么字节序?试着写一个 C 语言程 序来验证,如果你没有思路,你可以尝试着使用联合体或者指针。
小端存储:低字节存储到低地址 大端存储:低字节存储到高地址 小端存储
union
{
int i;
char arr[4];
}p;
int main(void)
{
p.i = 0x12345678;
printf("%d %c %c %c %c\n", p.i, p.arr[0], p.arr[1], p.arr[2], p.arr[3]);
return 0;
}
- 14.以下是在某机器下执行 Linux 命令 ls 的部分输出(有删节),参考该输出,你可以说出哪些关 于该命令以及其他 Linux 的相关知识?
total 36
drwxr-xr-x 17 root root 4096 Sep 21 23:45 .
drwxr-xr-x 17 root root 4096 Sep 21 23:45 …
lrwxrwxrwx 1 root root 7 Aug 21 22:21 bin -> usr/bin
drwxr-xr-x 4 root root 2048 Jan 1 1970 boot
drwxr-xr-x 21 root root 3580 Nov 21 21:16 dev
drwxr-xr-x 83 root root 4096 Nov 21 22:12 etc
drwxr-xr-x 4 root root 4096 Sep 22 00:07 home
drwxr-xr-x 2 root root 4096 Aug 21 22:21 mnt
drwxr-x— 9 root root 4096 Nov 19 19:15 root
dr-xr-xr-x 13 root root 0 Nov 21 21:15 sys
drwxrwxrwt 10 root root 380 Nov 21 22:30 tmp
drwxr-xr-x 9 root root 4096 Nov 21 22:12 usr
ls显示文件目录 ls-a显示文件及文件夹包括隐藏的 ls-la显示文件和文件夹及其隐藏的,还有详细信息
2020年纳新题
- 1.运行下面代码,输出什么结果,请解释说明
int i;
int main(int argc, char *argv[])
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
输出>,因为sizeof(i),求i的字节数,返回无符号整形4,然后i要与无符号整形4进行比较,i被自动转换为无符号整形,i的ascii码全1,所以最后是2的32次方减1个4比较
- 2.执行下面代码段,输出结果和你预想的一样吗,谈谈你对宏的理解
#define A 2 + 2
#define B 3 + 3
#define C A * B
int main(int argc, char *argv[])
{
printf("%d\n", C);
return 0;
}
11,因为宏属于替换所有出现A的地方替换为2 + 2,出现B的地方替换为3 + 3,出现C的地方替换为A * B,即2 + 2 *3 + 3
- 3.分析下面程序的输出结果
int main(int argc, char *argv[])
{
char str[] = "Welcome to XiyouLinuxGroup";
printf("%zu %zu\n", strlen(str), sizeof(str));
return 0;
}
26 27 因为strlen()求字符串长度,不算’\0’,sizeof()求数组长度,算’\0’
- 4.在程序中执行此函数输出结果是什么,多次执行是否相同
void fun()
{
int x = 0;
static int num = 0;
for (int i = 0; i < 5; i++)
{
x++;
num++;
}
printf("x = %d num = %d\n", x, num);
}
x = 5 num = 5 不相同,num是静态变量,下次函数调用时使用的是上次函数结束时num的值
- 5.分析下列程序,推测并验证其作用
int main(int argc, char *argv[])
{
int number;
unsigned mask;
mask = 1u << 31;
scanf("%d", &number);
while (mask)
{
printf("%d", (number & mask) ? 1 : 0);
mask >>= 1;
}
return 0;
}
先将1u左移31位即乘2的31次方,然后输入number,当mask不为0时执行循环,number&mask,即number按位与mask,当他们的ascii码同一位都为1时为真,输出1,否则输出0,然后mask右移1位,即除2,循环共执行32次
- 6.下面程序的运行结果是什么,请解释说明
int main(int argc, char *argv[])
{
char *str = "Xiyou Linux Group";
printf("%c\n", *str + 1);
return 0;
}
Y,“Xiyou Linux Group”,将其首字符的地址赋给了str,*str即他的首字符X,然后加1变为Y
- 7.以下程序段运行结果是什么,你知道怎么判断两个浮点数是否相同吗
int main(int argc, char *argv[])
{
double a = 3.14;
float b = a;
if ((float)a == b)
{
printf("Xiyou");
}
if (a != b)
{
printf("LinuxGroup\n");
}
return 0;
}
XiyouLinuxGroup,因为将a赋给b发生精度损失,然后将a强制转换为float类型与a比较,俩相同,然后不转换的话a != b,因为有精度损失
只要两个浮点数之差的绝对值小于一个特别小的数(如1e-8),我们就认为他们相同
- 9.运行下面代码,解释运行结果并谈谈自己的理解
int main(int argc, char *argv[])
{
int a[6] = {
0x6f796958, 0x694c2075, 0x2078756e, 0x756f7247, 0x30322070,
0};
printf("%d\n", printf("%s", (char *)a));
return 0;
}
Xiyou Linux Group 2020
小端存储,即低字节存至低地址,将指针常量a强制转换成字符指针,然后通过%s输出,指导最后一个0结束
- [ ] 10.执行下面程序段,其输出结果是什么,并解释
int main(int argc, char *argv[])
{
int a = 1;
printf("%d\n", *(char *)&a);
}
1,小端存储,然后取a的地址,强制转换成char*类型的地址,即指向int类型第一个字节的指针,然后通过解引用,就代表第一个字节存储的内容,然后输出,因为是小端存储所以输出1
- 11.下面程序的输出结果是什么,若取消第三行const注释,a数组还能被修改吗?如果取消6,8行注释,程序还能运行吗?试解释说明
int main(int argc, char *argv[])
{
/*const*/ char a[] = "XiyouLinux\0";
char *b = "XiyouLinux\0";
a[5] = '\0';
// b[5] = '\0';
printf("%s\n", a);
// printf("%s\n",b);
return 0;
}
取消const注释,无法通过a[5]修改,但可以将a赋给char*类型的指针变量,然后通过该指针变量修改
不能正常运行,会发生段错误,第四行将字符串常量的首地址赋给了b,字符串常量的值是不能更改的
- 一个c源文件到c可执行文件经历了一系列步骤,你知道这个步骤吗?请说明
1、预处理 在这一阶段,源码中的所有预处理语句得到处理,例如#include语句所包含的文件内容替换掉语句本身,所有已定义的宏被展开根据#ifdef,#if等语句的条件是否成立取舍相应的部分,预处理之后源码中不再包含任何预处理语句。
2、编译
这一阶段,编译器对源码进行词法分析、语法分析、优化等操作,最后生成汇编代码。这是整个过程中最重要的一步,因此也常把整个过程称为编译。
3、汇编 这一阶段使用汇编器对汇编代码进行处理,生成机器语言代码,保存在后缀为.o的目标文件中。
4、链接,链接的主要内容是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确地衔接。 链接完成之后就形成了(*.exe)文件
14.你能看懂下面函数的原理?解释并优化它
void sort(int arr[], int size)
{
int i, j, tmp;
for (i = 0; i < size - 1; i++)
{
for (j = 0; j < size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
冒泡排序,排序时左边总比右边小,排序完一遍,最右边为最大的数,然后第二次排序,右边数倒数第二个为最大的数,类推
void sort3(int *arr, int len)
{
int i, j, k;
int flag, pos;
k = len - 1;
pos = 0;
for (i = 0; i < len-1; ++i)
{
flag = 0;
for (j = 0; j < k; ++j)
{
if (arr[j] < arr[j+1])
{
arr[j] = arr[j] ^ arr[j+1];
arr[j+1] = arr[j] ^ arr[j+1];
arr[j] = arr[j] ^ arr[j+1];
flag = 1;
pos = j;
}
}
k = pos;
if (flag == 0)
{
return;
}
}
}
(1)pwd
(2)ls
(3)mkdir test touch ./A/test1.c
(4)cp
2021年纳新题
sizeof是一个运算符,求字节数
strlen()求字符串长度,遇到\0结束,不算\016 12
相等,都是16 结构体内存对齐,将它们中字节数最大的当做一块,每次分配内存都是一块一块分配,一块中放得下就直接放,放不下就重新开辟空间
void func(int (*arr)[13])
{
int len1 = 10;
int len2 = sizeof(arr[0])/sizeof(arr[0][0]);
int i, j;
for (i=0; i<len1; ++i)
{
for (j=0; j<len2; ++j)
{
printf("%d\t", arr[i][j]);
}
printf("\n");
}
return;
}
传值会重新分配空间,将发送的数据拷贝一份,存入新变量中,无法修改实参,函数调用结束,内存释放
传址可以通过指针指向实参所代表的内存空间,通过指针可以修改主调函数中的实参通过static修饰代表静态变量,编译时分配内存空间,每次调用时都是上一次所保存的值,函数调用结束不会被释放,函数调用结束后其他函数不能再使用该变量,程序运行完才释放
正常的变量都是自动变量,函数调用时分配内存空间,函数运行结束,空间释放
当n==0时直接返回0,n不等于0时,层层递归调用,规模逐渐缩小,直到n等于0逐层返回,先返回0,然后退出此层,再返回0 + 1,再退出,再返回0 + 1 + 2,类推到1+2+…+n
a=0xfffe b=0xffffffff d=0x2022 e=0xffffffff c=0xf0
10 4 9
先定义一个二维数组,二维数组名为首元素地址,即第一个一维数组的地址,再定义一个指向一维数组的数组指针,保存a,然后b也指向了a所指向的一维数组,++b,指向二维数组的第二行,b[1][1]即二维数组第三行第二个元素,&a+1即找到整个二维数组的首地址,可以看做是一个指向二维数组的指针,+1移到下一个二维数组,C语言保证指针越界1有效,然后强制转换成int型,最后输出10 4 9
const int 和int const一样,都代表定义一个整形常量
const int* 和 int const *一样,都代表定义一个指向整形常量的指针
void func0(int n)是发送变量的值给n,a,b,c都√
void func1(int *n)发送地址给n,然后通过指针间接修改原变量的值,a,b,c都√
void func2(const int *n)向n发送一个地址,该指针所指向的是个常量,不能更改,a,b,c都×
void func3(int *const n)向n发送一个地址,然后n的值不能改变,a,b,c都错×
void func4(const int *const n)向n发送一个地址,n不能改变,n所指向的变量也不能改变,a,b,c都×
char *convert(const char *s)
{
int i;
char *p = (char*)s;
char * arr = (char *)malloc(sizeof(char) * 50);
for (i=0; *p; i++, p++)
{
arr[i] = *p;
}
arr[i] = '\0';
i=0;
while(arr[i])
{
if (arr[i]>='A' && arr[i]<='Z')
{
arr[i] += 32;
}
else if (arr[i]>='a' && arr[i]<='z')
{
arr[i] -= 32;
}
i++;
}
return arr;
}
#define Swap1(a, b, t)可以完成交换,出现Swap1的地方直接替换。
#define Swap2(a, b)可以完成交换,宏定义结束中间那个t就被释放了,出现Swap2的地方直接替换。
void swap3(int a, int b)不能完成交换 通过函数调用,会新开辟内存,将a,b的值拷贝一份,不能完成交换
方式1,2没有函数调用,不需要压栈出栈速度快,
通过指针完成交换,通过全局变量完成交换,通过位运算交换,通过加减完成交换
argc是向main函数传递的参数的个数,argc是向main函数传递的字符串,是一个指针数组,每一个元素指向一个字符串,一般argv[0]都是文件夹名,后面开始才是向main传递的参数
静态变量在静态区,编译分配内存,程序结束释放内存,只初始化一次,再次调用是上一次的值,只能在定义它的函数内使用
自动变量在动态区,函数运行结束内存释放,再次调用重新分配空间,值不确定
动态内存分配可以跨函数使用,需要手动释放。
*fun3()自动变量n,函数调用结束释放,不能在main函数中使用,*func1()静态变量n,内存空间一直存在,但是到main函数中时,func1()调用已经结束,不能再使用n
大小端问题,强制类型转换
上文有
栈是自动释放内存,自动分配,局部变量形参都是自动变量,在栈中,函数调用也是在栈中,根据变量定义的顺序,依次将变量函数压入栈中,调用结束依次释放
堆是malloc等函数分配内存,由程序要手动分配,手动释放,从分配到释放期间一直存在
exturn
touch
mkdir
ls显示文件和文件夹
stat