Xiyou Linux_group 2022
0.我的计算器坏了
2^10=1024
对应于十进制的4位,那么2^10000
对应于十进制的多少位呢?
(1)取对数法
log2=0.30102
2^10000–>取对数得10000log2=3010(位数加上首位=3011)
(2)数组法
#include<stdio.h>
int main(){
int arr[4000]={0};//定义一个足够大的数组,每个元素对应一位
int i,j,n=10000;
arr[0]=1;
for(i=0;i<n;i++){
for( j=0;j<4000;j++){//遍历每一个元素
arr[j]*=2;//每一位分别乘2
}
for(j=0;j<4000;j++){//遍历每一个元素
if(arr[j]>9){
arr[j+1]+=1;//满十进位
arr[j]%=10;//只保留个位
}
}
}
for(i=3999;arr[i]==0;i--)//得到最大位下标-1
printf("%d",i+1);//i+1即为最大位
return 0;
}
1.printf还能这么玩?
尝试着解释程序的输出。
int main(){
if((3+2<2)>(3+2>2))//结果为假执行else语句
printf("Welcome to Xiyou Linux Group\n");
else
printf("%d\n",printf("Xiyou Linux Group - 2%d",printf("")));
//printf()函数的返回值是它的内容的长度
//函数存放于栈区,函数调用遵从“先进后出”,即先得到最内层函数的返回值并输出
}
输出结果Xiyou Linux Group - 2022
2.你好你好你好呀!
- 程序的输出有点奇怪,请尝试解释一下程序的输出吧。
- 请谈谈对
sizeof()
及strlen()
的理解吧。
int main(){
char p0[]="Hello,Linux";
char* p1="Hello,Linux";
char p2[11]="Hello,Linux";
printf("p0==p1:%d,strcmp(p0,p2):%d\n",p0==p1,strcmp(p0,p2));
printf("sizeof(p0):%zu,sizeof(p1):%zu,sizeof(*p2):%zu\n",sizeof(p0),sizeof(p1),sizeof(*p2));
printf("strlen(p0):%zu,strlen(p1):%zu\n",strlen(p0),strlen(p1));
return 0;
}
p0[]为不定长度的字符数组;
p1为指针类型指向常量区的字符串Hello,Linux;
p2[11]字符串数组发生越界,字符串后指向不规则的地址;
输出结果:
/* p0==p1:0,strcmp(p0,p2):-72
sizeof(p0):12,sizeof(p1):8,sizeof(*p2):1
strlen(p0):11,strlen(p1):11 */
printf("p0==p1:%d,strcmp(p0,p2):%d\n",p0==p1,strcmp(p0,p2));
p0表示p0[]数组首元素的地址,同理p1表示的是位于常量区字符串Hello,Linux的地址;
p0显然不等于p1,所以p0==p1结果为0;
strcmp(p0,p2)比较p0,p2两个字符串的大小(ASCII码),从两个字符串的首个元素进行比较,若相同则比较下一个,不同则输出第一个字符串中的该位字符与第二个字符串中的该位字符的差值(ASCII码的差值)。
由于p2发生越界,所以得到一个负值。
printf("sizeof(p0):%zu,sizeof(p1):%zu,sizeof(*p2):%zu\n",sizeof(p0),sizeof(p1),sizeof(*p2));
p0的大小计算:1.数据类型为字符型每个字符占一个字节
2.sizeof(p0)=11*1+1=12
p1的大小计算:数据类型为指针变量,固定大小为8
sizeof(*p2)的计算:*p2指的是p2数组的首元素,类型为字符型所以大小为1
printf("strlen(p0):%zu,strlen(p1):%zu\n",strlen(p0),strlen(p1));
输出结果为:
/*strlen(p0):11,strlen(p1):11 */
strlen()函数参数为地址,读取到‘\0’停止,返回结果不计入‘\0’,结果为字符串的长度。
3. 换个变量名不行吗?
请结合本题,分别谈谈你对C语言中「全局变量」和「局部变量」的「生命周期」理解。
int a = 3; //a为全局变量,这里记为a1,下文依次为a2,a3...
void test()
{
int a = 1; //这里的a2的生命周期到本块结束
a += 1;
{
int a = a + 1; //在新的函数块内定义a3,此处的a3只在本块内有生命
printf("a = %d\n", a);//由于a3未初始化,得到一个随机值
}
printf("a = %d\n", a);//输出a2的值:2
}
int main(void)
{
test();
printf("a= %d\n", a);//输出全局变量a1的值:3
}
输出结果:
a = 32701
a = 2
a= 3
4.内存对不齐
union
与struct
各有什么特点呢,你了解他们的内存分配模式吗。
typedef union
{
long l;
int i[5];
char c;
} UNION;
typedef struct
{
int like;
UNION coin;
double collect;
} STRUCT;
int main(void)
{
printf("sizeof (UNION) = %zu \n", sizeof(UNION));
printf("sizeof (STRUCT) = %zu \n", sizeof(STRUCT));
}
union(联合体)内存计算方式:
- 首先我们需要了解什么是对齐数,对齐数是计算机为了提高处理数据的速度而设定的。32位的系统默认对齐数是4,64位的系统默认对齐数是8.
- 结构内的元素称为成员,成员共同占用一片空间,成员相对基地址的偏移量为0.
- 内存大小必须是默认对齐数的倍数.
- 第一个成员是long类型内存大小为8(32位的系统默认是4),将其与默认对齐数比较取最小值,这里是8.接着第二个成员类型为int类型的数组,内存大小为4*5=20.第三个成员为char类型内存大小为1.取所有成员的最大对齐数即为20,20不是8的倍数,扩充到24,最后得到联合体的内存大小为24.
Struct(结构体)内存计算方式:
- 结构体内存大小与成员的顺序有关
- 对齐数是成员大小与默认对齐数较小的那个
- 成员的位置是对齐数的倍数
- 第一个成员为int类型内存大小为4,将其与默认对齐数8比较取较小值4,4是对齐数的倍数所以第二个成员偏移量为4,为UNION类型内存大小上文计算得到是24,将其与默认对齐数8比较取较小值8,4+24=28,28不是8的倍数,扩充到32.第三个成员偏移量是32,内存大小是8,将其与默认对齐数8比较取较小值8,32+8=40,40是8的倍数,所以结构体的内存大小为40
5. Bitwise
- 请使用纸笔推导出程序的输出结果。
- 请谈谈你对位运算的理解。
int main(void)
{
unsigned char a = 4 | 7;//4:0000 0100 7:0000 0111->或运算得a=7
a <<= 3;//左移运算得a=56
unsigned char b = 5 & 7;//5:0000 0101 7:0000 0111->与运算得b=5
b >>= 3;//算术右移得b=0
unsigned char c = 6 ^ 7;//6:0000 0110 7:0000 0111->异或运算得c=1
c = ~c;//按位取反c=254
unsigned short d = (a ^ c) << 3;//a:0011 1000 c:1111 1110->异或运算得1100 0110,左移得d:0011 0000,d=48
signed char e = -63;//原码e:1011 1111 补码:1100 0001
e <<= 2;//左移得e:0000 0100,e=4
printf("a: %d, b: %d, c: %d, d: %d \n", a, b, c, (char)d);
printf("e: %#x \n", e);
}
输出结果:
a: 56, b: 0, c: 254, d: 48
e: 0x4
6. 英译汉
请说说下面数据类型的含义,谈谈
const
的作用。
char *const p
。//const限制的是p,也就是说指针本身不能改变char const *p
。//const限制的是*p,也就是说不能通过指针来改变所指的变量const char *p
。//const限制的是*p,也就是说不能通过指针来改变所指的变量
7. 汉译英
请用变量
p
给出下面的定义:
- 含有10个指向
int
的指针的数组。//int *p[10]- 指向含有10个
int
数组的指针。//int (*p)[10]- 含有3个「指向函数的指针」的数组,被指向的函数有1个
int
参数并返回int
。
//int (*p[3])(int)
8. 混乱中建立秩序
你对排序算法了解多少呢?
请谈谈你所了解的排序算法的思想、稳定性、时间复杂度、空间复杂度。提示:动动你的小手敲出来更好哦~
//冒泡排序 时间复杂度O(N^2) 空间复杂度O(1)
int main(){
int t,i,j;
int arr[5]={1,2,3,4,5};
for( i=0;i<4;i++){
for( j=0;j<5-i-1;j++){
if(arr[j]<arr[j+1]){
t=arr[j];arr[j]=arr[j+1];arr[j+1]=t;
}
}
}
for(i=0;i<5;i++)printf("%d",arr[i]);
}
//选择排序 时间复杂度:O(N^2) 空间复杂度:O(1)
#include<stdio.h>
int main(){
int min,i,j,t;
int arr[5]={1,2,3,4,5};
for(i=0;i<4;i++){
min=0;
for(j=1;j<=5-i-1;j++){
if(arr[min]>arr[j]){
min=j;
}
}t=arr[min];arr[min]=arr[4-i];arr[4-i]=t;
}
for(i=0;i<5;i++)printf("%d",arr[i]);
}
9. 手脑并用
请实现ConvertAndMerge函数:
拼接输入的两个字符串,并翻转拼接后得到的新字符串中所有字母的大小写。提示:你需要为新字符串分配空间。
char* convertAndMerge(/*补全签名*/);
int main(void) {
char words[2][20] = {"Welcome to Xiyou ", "Linux Group 2022"};
printf("%s\n", words[0]);
printf("%s\n", words[1]);
char *str = convertAndMerge(words);
printf("str = %s\n", str);
free(str);
}
代码如下:
char* convertAndMerge(char s1[],char s2[]){
strcat(s1,s2);
for(int i=0;s1[i]!=0;i++){
if(s1[i]>='A'&&s1[i]<='Z'){
s1[i]+=32;
}else if(s1[i]>='a'&&s1[i]<='z'){
s1[i]-=32;
}
}
return s1;
}
10. 给你我的指针,访问我的心声
程序的输出有点奇怪,请尝试解释一下程序的输出吧。
int main(int argc, char **argv) {
int arr[5][5];
int a = 0;
for (int i = 0; i < 5; i++) {
int *temp = *(arr + i);
for (; temp < arr[5]; temp++) *temp = a++;
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%d\t", arr[i][j]);
}
}
}
结果如下:
0 1 2 3 4 25 26 27 28 29 45 46 47 48 49 60 61 62 63 64 70 71 72 73 74
11. 奇怪的参数
你了解argc和argv吗?
直接运行程序argc的值为什么是1?
程序会出现死循环吗?
#include <stdio.h>
int main(int argc, char **argv)
{
printf("argc = %d\n", argc);
while (1)
{
argc++;
if (argc < 0)
{
printf("%s\n", (char *)argv[0]);
break;
}
}
}
argc是传给main()函数命令的参数,argv是命令的表现形式,无命令时系统会输入一条命令因此argc=1.
while循环执行过程中argc会出现数据溢出,数值从正值变为负值从而结束循环。
12. 奇怪的字符
程序的输出有点奇怪,请尝试解释一下程序的输出吧。
int main(int argc, char **argv)
{
int data1[2][3] = {{0x636c6557, 0x20656d6f, 0x58206f74},
// u o y i n i L \0
{0x756f7969, 0x6e694c20, 0x00000000}};
int data2[] = {0x47207875, 0x70756f72, 0x32303220, 0x00000a32};
char *a = (char *)data1;
char *b = (char *)data2;
char buf[1024];
strcpy(buf, a);
strcat(buf, b);
printf("%s \n", buf);
if(*buf='W') printf("LE");
else printf("BE");
}
采用小端存储模式即:低字节存放在低地址处。
13. 小试宏刀
- 请谈谈你对
#define
的理解。- 请尝试着解释程序的输出。
#include <stdio.h>
#define SWAP(a, b, t) t = a; a = b; b = t
#define SQUARE(a) a *a
#define SWAPWHEN(a, b, t, cond) if (cond) SWAP(a, b, t)
int main() {
int tmp;
int x = 1;
int y = 2;
int z = 3;
int w = 3;
SWAP(x, y, tmp);
printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
if (x > y) SWAP(x, y, tmp);
printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
SWAPWHEN(x, y, tmp, SQUARE(1 + 2 + z++ + ++w) == 100);
printf("x = %d, y = %d,tmp=%d\n", x, y, tmp);
printf("z = %d, w = %d ,tmp = %d\n", z, w, tmp);
}
- 宏定义是替换,将内容完全替换成宏的内容。
- #define SWAP(a, b, t) t = a; a = b; b = t这条宏定义的内容包括SWAP()函数,和 a = b; b = t语句
- 即SWAP(a, b, t)函数体是 t = a;而不含 a = b; b = t这两条语句。
14. GNU/Linux命令 (选做)
你知道以下命令的含义和用法吗:
注:
嘿!你或许对Linux命令不是很熟悉,甚至你没听说过Linux。
但别担心,这是选做题,不会对你的面试产生很大的影响!
了解Linux是加分项,但不了解也不扣分哦!
ls
//列出当前目录的文件rm
//删除当前目录的文件whoami
//查看用户名请问你还了解哪些GNU/Linux的命令呢。