2024Linux一面题解0. 聪明的吗喽一个小猴子边上有 100 根香蕉,它要走过 50 米才能到家,每次它最多搬 50 根香蕉,(多了就拿不动了),它每走 1 米就要吃掉一根,请问它最多能把多少根香蕉搬到家里。(提示:他可以把香蕉放下往返走,但是必须保证它每走一米都能有香蕉吃。也可以走到 n 米时,放下一些香蕉,拿着 n 根香蕉走回去重新搬 50 根。)分析由于每次只能搬50根香蕉,当香蕉数大于50时,不可能一次搬完,需要往返走,为了每次往返走消耗的香蕉最少,最好走一步就把剩余香蕉全部搬完,即从起点开始搬50根香蕉走一步放下回去把剩下的50根拿上,一次消耗三根香蕉,直到把总香蕉数消耗到50以下,当走到17米时,消耗51根香蕉,此时可以一次走回家,即用49-33=16根香蕉搬完,所以最多搬16根香蕉。1. 西邮Linux欢迎你啊请解释以下代码的运行结果。intmain(){unsignedinta=2024;for(;a>=0;a--)printf("%d\n",printf("Hi guys! Join Linux - 2%d",printf("")));return0;}分析for循环执行第一次从最内层的printf开始,返回0,然后打印Hi guys! Join Linux - 20,最后打印并返回24,即打印Hi guys! Join Linux - 2024。由于a是无符号整形变为0后再减不会变为-1,而是回绕为最大正值,所以循环会一直执行,每次循环都会打印Hi guys! Join Linux - 2024。2. 眼见不一定为实输出为什么和想象中不太一样?你了解 sizeof() 和 strlen() 吗?他们的区别是什么?intmain(){charp0[]="I love Linux";constchar*p1="I love Linux\0Group";charp2[]="I love Linux\0";printf("%d\n%d\n",strcmp(p0,p1),strcmp(p0,p2));printf("%d\n%d\n",sizeof(p0)==sizeof(p1),strlen(p0)==strlen(p1));return0;}分析const固定了p1指向的内容,strcmp是比较两个字符串的大小,直到遇到‘\0’,sizeof是测量字符串大小知道遇到隐式‘\0’并算上隐式‘\0’,strlen是测量字符串大小直到遇到第一个‘\0’。解答由于strcmp遇到‘\0’就测算就结束了,所以三个字符串大小是一样的,都返回0。sizaof的测算下p0是13,p1是指针大小为8,返回0,strlen的测算下p0是12,p1是12,返回1。3. 1.1 - 1.0 != 0.1为什么会这样,除了下面给出的一种方法,还有什么方法可以避免这个问题?intmain(){floata=1.0,b=1.1,ex=0.1;printf("b - a == ex is %s\n",(b-a==ex)?"true":"false");intA=a*10,B=b*10,EX=ex*10;printf("B - A == EX is %s\n",(B-A==EX)?"true":"false");}分析浮点数在计算机中存储是不精准的(二进制无法精确表示小数),所以进行计算时会有误差。而整形的存储是精准的可以进行计算的。解答定义一个epsilon(一般为1e-6)来描绘误差,当b-a的绝对值小于epsilon时,认为b-a等于ex。4. 听说爱用位运算的人技术都不太差解释函数的原理,并分析使用位运算求平均值的优缺点。intaverage(intnums[],intstart,intend){if(start==end)returnnums[start];intmid=(start+end)/2;intleftAvg=average(nums,start,mid);intrightAvg=average(nums,mid+1,end);return(leftAvg&rightAvg)+((leftAvg^rightAvg)>>1);}分析按位与的作用是将两个数同为1的位置找出来,就是两数相加要进位的位置,本来应该向右移一位,但和求平均除2抵消,按位异或的作用是将两个数不同为1的位置找出来,就是两数相加不用进位的位置,异或结果就是不用进位的数相加的结果,由于要除2就向右移一位,所以这个返回的就是求平均数的结果。average函数通过递归将数组分为两部分,再在两部分分割直到两部分分别返回nums[start]和nums[end],然后返回这两部分元素的平均值,直到返回第一层,返回了两部分的平均值,再求两部分的平均值就是整体的平均值。优点:这样的运算避免了相加溢出的的结果且位运算的效率更高。缺点:只有在左右元素数量相同的情况逻辑才正确,若数量不同,则结果会出错。5. 全局还是局部!!!先思考输出是什么,再动动小手运行下代码,看跟自己想得结果一样不一样 >-<inti=1;staticintj=15;intfunc(){inti=10;if(i>5)i++;printf("i = %d, j = %d\n",i,j);returni%j;}intmain(){inta=func();printf("a = %d\n",a);printf("i = %d, j = %d\n",i,j);return0;}分析i和j是全局变量生命周期一直存在,在函数中又定义了局部变量i会遮掩全局变量i,此时i=10,自增后为11,打印11 15返回11。func函数结束了之后,局部定义的i生命周期结束,i又回到全局变量1,主函数中a接受了返回值11,所以打印结果为11 1 15.6. 指针的修罗场:改还是不改,这是个问题指出以下代码中存在的问题,并帮粗心的学长改正问题。intmain(intargc,char**argv){inta=1,b=2;constint*p=&a;int*constq=&b;*p=3,q=&a;constint*constr=&a;*r=4,r=&b;return0;}分析主要是const修饰的位置,p指向的内容被const修饰不可改变,q的指向不可改变,r的指向和指向的内容都不可改变。p=a,由于p指向的内容被const修饰,所以不能改变,所以p=3不合法,q的只想被固定所以q=&a不合法,r是指向和指向的内容均不可改变,所以*r=4和r=&b均不合法。如果要改可以把p的const去掉或变为给p的指向const修饰,将q的const去掉或移到int前修饰指向内容,r将两个const均去掉就可以。7. 物极必反?你了解 argc 和 argv 吗,这个程序里的 argc 和 argv 是什么?程序输出是什么?解释一下为什么。intmain(intargc,char*argv[]){while(argc++>0);inta=1,b=argc,c=0;if(--a||b++&&c--)for(inti=0;argv[i]!=NULL;i++)printf("argv[%d] = %s\n",i,argv[i]);printf("a = %d, b = %d, c = %d\n",a,b,c);return0;}分析argc是命令行参数个数(包括程序名所以默认是一),argv是一个指向字符串数组的指针,里面是参数的具体内容(argv[0]就是程序的文件名/路径)。argc会先判断大于一在自增,直到agrc溢出,溢出按理来说变为负的的最小值,但argc参数为负不太合理不应该有负的索引,所以argc溢出应该提前设置为0了,判断为假再自增为1后退出while,a=1,b=1,c=0。进入if–a=0为假,b=1为真自增为2,c=0为假自减为-1,1&&0为假,所以0||0为假不进入for,最后打印a=0,b=2,c=-1。8. 指针?数组?数组指针?指针数组?在主函数中定义如下变量:intmain(){inta[2]={4,8};int(*b)[2]=&a;int*c[2]={a,a+1};return0;}说说这些输出分别是什么?a, a + 1, &a, &a + 1, *(a + 1), sizeof(a), sizeof(&a)*b, *b + 1, b, b + 1, *(*b + 1), sizeof(*b), sizeof(b)c, c + 1, &c, &c + 1, **(c + 1), sizeof©, sizeof(&c)分析a为整型数组,b是指向数组的指针,c为指针数组(装指针的数组)。a本身为数组,在表达式中为a首元素地址,*b的是数组a,数组a在表达式中退化为首元素地址,c是指针数组在表达式中退化为首元素地址,即指向数组a首元素地址的指针(二级指针)。数组c中装的分别是两个元素的地址。解答第一行的输出为,数组a的首元素地址,a+1在表达式中数组a表示首元素地址,输出是a[1]的地址,&a是数组a的首地址,&a+1此时a代表整个数组步长为两个int加1表示偏移8个字节,*(a+1)表示a[1]的值,a表示数组sizeof(a)表示数组长度8个字节,&a是数组a的首地址表示一个指针,sizeof(&a)为8个字节。*b表示数组a在表达式中为数组a的首元素地址,*b+1与a+1同理为a[1]的地址,b表示指向数组a的指针步长为8个字节,所以b,b+1输出分别是数组a的首地址和数组a首地址加8个字节。后面三个和第一行的最后三个一样。c在表达式中是首元素的地址即arr[0]的二级指针,c+1表示a[1]的二级指针,&c表示数组c的首地址步长为两个指针长度16,&c+1就是数组c的首地址加上16。c+1就是a[1]的二级指解引两次表示a[1]的值,c表示指针数组sizeof(c)就是16个字节,&c表示数组c的首地址即一个指针长度为8个字节。9. 嘻嘻哈哈,好玩好玩在宏的魔法下,数字与文字交织,猜猜结果是什么?#defineSQUARE(x)x*x#defineMAX(a,b)(a>b)?a:b;#definePRINT(x)printf("嘻嘻,结果你猜对了吗,包%d滴\n",x);#defineCONCAT(a,b)a##bintmain(){intCONCAT(x,1)=5;intCONCAT(y,2)=3;intmax=MAX(SQUARE(x1+1),SQUARE(y2))PRINT(max)return0;}分析首先用了两个CONCAT,##就是记号拼接运算符将两个记号拼接。所以CONCAT(x, 1)=5就是x1=5,CONCAT(y, 2)=3就是y2=3。SQUARE(x+1)就是x1+1x1+1=11,SQUARE(y2)就是33=9,MAX(11,9)就是11。PRINT(11)就是printf(“嘻嘻,结果你猜对了吗,包%d滴\n”,11)。最终打印嘻嘻,结果你猜对了吗,包11滴。10. 我写的排序最快写一个 your_sort 函数,要求不能改动 main 函数里的代码,对 arr1 和 arr2 两个数组进行升序排序并剔除相同元素,最后将排序结果放入 result 结构体中。intmain(){intarr1[]={2,3,1,3,2,4,6,7,9,2,10};intarr2[]={2,1,4,3,9,6,8};intlen1=sizeof(arr1)/sizeof(arr1[0]);intlen2=sizeof(arr2)/sizeof(arr2[0]);result result;your_sort(arr1,len1,arr2,len2,&result);for(inti=0;i<result.len;i++){printf("%d ",result.arr[i]);}free(result.arr);return0;}分析函数your_sort作用就是将两个数组合并,排序去重。观察到free(result.arr)说明result.arr是动态分配的,所以在该函数中需要动态分配result的空间。这里结构体还用到了别名result所以要定义typedef struct{int *arr;int len;}result。定义指针变量arr是为了接收动态内存分配的首地址。合并并申请动态内存、排序、去重、放在结构体中。voidyour_sort(int*arr1,intlen1,int*arr2,intlen2,result*res){intlen=len1+len2;res->len=len.res->arr=(int*)malloc(sizeof(int)*len);//合并for(inti=0;i<len1;i++){res->arr[i]=arr1[i];}for(inti=0;i<len2;i++){res->arr[i+len1]=arr2[i];}//排序for(inti=0;i<len-1;i++){for(intj=i+1;j<len;j++){if(res->arr[i]>res->arr[j]){inttemp=res->arr[i];res->arr[i]=res->arr[j];res->arr[j]=temp;}}}}//去重intk=0;for(inti=0;i<len;i++){if(i==0||res->arr[i]!=res->arr[i-1]){res->arr[k++]=res->arr[i];}}res->len=k;//更新内存res->arr=(int*)realloc(res->arr,sizeof(int)*k);11. 猜猜我是谁在指针的迷宫中,五个数字化身为神秘的符号,等待被逐一揭示。intmain(){void*a[]={(void*)1,(void*)2,(void*)3,(void*)4,(void*)5};printf("%d\n",*((char*)a+1));printf("%d\n",*(int*)(char*)a+1);printf("%d\n",*((int*)a+2));printf("%lld\n",*((longlong*)a+3));printf("%d\n",*((short*)a+4));return0;}分析定义了一个指针数组a,里面装的是五个void指针,void指针可以指向任意类型的数据,1是整型占4个字节,强转后为8个字节例a[0]=0x1000000000000000(小端序),一个指针占8个字节。第一行printf,(char*)a将a强制转换成了char类型的指针,+1就表示偏移一个字节,假设a的首地址为0x1000,(char *)a + 1就是将其强转为char类型指针步长变为1,所以地航打印的就是地址0x1001处的值00,即0。第二行printf,先转为char指针类型再转为int类型指针,此时步长为4,所以打印的是地址0x1004处的值00,即0。第三行printf,强转为int类型指针,步长为4,所以打印的是地址0x1008处的值10,即2。第四行printf,强转为long long类型指针,步长为8,所以打印地址0x1018处的值04,即4。第五行printf,强转为short类型指针,步长为2,所以打印地址为0x1008处的值10,即2。12. 结构体变小写奇遇记计算出 Node 结构体的大小,并解释以下代码的运行结果。uniondata{inta;doubleb;shortc;};typedefstructnode{longlonga;uniondata b;void(*change)(structnode*n);charstring[0];}Node;voidfunc(Node*node){for(size_ti=0;node->string[i]!='\0';i++)node->string[i]=tolower(node->string[i]);}intmain(){constchar*s="WELCOME TO XIYOULINUX_GROUP!";Node*P=(Node*)malloc(sizeof(Node)+(strlen(s)+1)*sizeof(char));strcpy(P->string,s);P->change=func;P->change(P);printf("%s\n",P->string);return0;}分析先看共同体的大小,int为四个字节,double为8个字节,short为两个字节,最大成员大小为8个字节且满足double的内存对齐,所以data大小为八个字节。再看结构体Node的大小,long long为8个字节,date为八个字节且此时满足double的内存对齐,此时整体为16个字节,void(change)(struct node)为函数指针,占8个字节,满足内存对齐,char[0]为柔性数组,不占空间,所以Node大小为24个字节。开辟了一个结构体动态内存空间,并将s装进string,strlen(s)+1是因为要算上字符串结束符‘\0’,将函数指针指向func,并执行func§,遍历字符数组string并将其中大写字母转为小写字母(tolowwer函数的作用)。所以最后打印出welcome to xiyoulinux_group!
2024Linux一面题解0. 聪明的吗喽一个小猴子边上有 100 根香蕉,它要走过 50 米才能到家,每次它最多搬 50 根香蕉,(多了就拿不动了),它每走 1 米就要吃掉一根,请问它最多能把多少根香蕉搬到家里。(提示:他可以把香蕉放下往返走,但是必须保证它每走一米都能有香蕉吃。也可以走到 n 米时,放下一些香蕉,拿着 n 根香蕉走回去重新搬 50 根。)分析由于每次只能搬50根香蕉,当香蕉数大于50时,不可能一次搬完,需要往返走,为了每次往返走消耗的香蕉最少,最好走一步就把剩余香蕉全部搬完,即从起点开始搬50根香蕉走一步放下回去把剩下的50根拿上,一次消耗三根香蕉,直到把总香蕉数消耗到50以下,当走到17米时,消耗51根香蕉,此时可以一次走回家,即用49-33=16根香蕉搬完,所以最多搬16根香蕉。1. 西邮Linux欢迎你啊请解释以下代码的运行结果。intmain(){unsignedinta=2024;for(;a>=0;a--)printf("%d\n",printf("Hi guys! Join Linux - 2%d",printf("")));return0;}分析for循环执行第一次从最内层的printf开始,返回0,然后打印Hi guys! Join Linux - 20,最后打印并返回24,即打印Hi guys! Join Linux - 2024。由于a是无符号整形变为0后再减不会变为-1,而是回绕为最大正值,所以循环会一直执行,每次循环都会打印Hi guys! Join Linux - 2024。2. 眼见不一定为实输出为什么和想象中不太一样?你了解 sizeof() 和 strlen() 吗?他们的区别是什么?intmain(){charp0[]="I love Linux";constchar*p1="I love Linux\0Group";charp2[]="I love Linux\0";printf("%d\n%d\n",strcmp(p0,p1),strcmp(p0,p2));printf("%d\n%d\n",sizeof(p0)==sizeof(p1),strlen(p0)==strlen(p1));return0;}分析const固定了p1指向的内容,strcmp是比较两个字符串的大小,直到遇到‘\0’,sizeof是测量字符串大小知道遇到隐式‘\0’并算上隐式‘\0’,strlen是测量字符串大小直到遇到第一个‘\0’。解答由于strcmp遇到‘\0’就测算就结束了,所以三个字符串大小是一样的,都返回0。sizaof的测算下p0是13,p1是指针大小为8,返回0,strlen的测算下p0是12,p1是12,返回1。3. 1.1 - 1.0 != 0.1为什么会这样,除了下面给出的一种方法,还有什么方法可以避免这个问题?intmain(){floata=1.0,b=1.1,ex=0.1;printf("b - a == ex is %s\n",(b-a==ex)?"true":"false");intA=a*10,B=b*10,EX=ex*10;printf("B - A == EX is %s\n",(B-A==EX)?"true":"false");}分析浮点数在计算机中存储是不精准的(二进制无法精确表示小数),所以进行计算时会有误差。而整形的存储是精准的可以进行计算的。解答定义一个epsilon(一般为1e-6)来描绘误差,当b-a的绝对值小于epsilon时,认为b-a等于ex。4. 听说爱用位运算的人技术都不太差解释函数的原理,并分析使用位运算求平均值的优缺点。intaverage(intnums[],intstart,intend){if(start==end)returnnums[start];intmid=(start+end)/2;intleftAvg=average(nums,start,mid);intrightAvg=average(nums,mid+1,end);return(leftAvg&rightAvg)+((leftAvg^rightAvg)>>1);}分析按位与的作用是将两个数同为1的位置找出来,就是两数相加要进位的位置,本来应该向右移一位,但和求平均除2抵消,按位异或的作用是将两个数不同为1的位置找出来,就是两数相加不用进位的位置,异或结果就是不用进位的数相加的结果,由于要除2就向右移一位,所以这个返回的就是求平均数的结果。average函数通过递归将数组分为两部分,再在两部分分割直到两部分分别返回nums[start]和nums[end],然后返回这两部分元素的平均值,直到返回第一层,返回了两部分的平均值,再求两部分的平均值就是整体的平均值。优点:这样的运算避免了相加溢出的的结果且位运算的效率更高。缺点:只有在左右元素数量相同的情况逻辑才正确,若数量不同,则结果会出错。5. 全局还是局部!!!先思考输出是什么,再动动小手运行下代码,看跟自己想得结果一样不一样 >-<inti=1;staticintj=15;intfunc(){inti=10;if(i>5)i++;printf("i = %d, j = %d\n",i,j);returni%j;}intmain(){inta=func();printf("a = %d\n",a);printf("i = %d, j = %d\n",i,j);return0;}分析i和j是全局变量生命周期一直存在,在函数中又定义了局部变量i会遮掩全局变量i,此时i=10,自增后为11,打印11 15返回11。func函数结束了之后,局部定义的i生命周期结束,i又回到全局变量1,主函数中a接受了返回值11,所以打印结果为11 1 15.6. 指针的修罗场:改还是不改,这是个问题指出以下代码中存在的问题,并帮粗心的学长改正问题。intmain(intargc,char**argv){inta=1,b=2;constint*p=&a;int*constq=&b;*p=3,q=&a;constint*constr=&a;*r=4,r=&b;return0;}分析主要是const修饰的位置,p指向的内容被const修饰不可改变,q的指向不可改变,r的指向和指向的内容都不可改变。p=a,由于p指向的内容被const修饰,所以不能改变,所以p=3不合法,q的只想被固定所以q=&a不合法,r是指向和指向的内容均不可改变,所以*r=4和r=&b均不合法。如果要改可以把p的const去掉或变为给p的指向const修饰,将q的const去掉或移到int前修饰指向内容,r将两个const均去掉就可以。7. 物极必反?你了解 argc 和 argv 吗,这个程序里的 argc 和 argv 是什么?程序输出是什么?解释一下为什么。intmain(intargc,char*argv[]){while(argc++>0);inta=1,b=argc,c=0;if(--a||b++&&c--)for(inti=0;argv[i]!=NULL;i++)printf("argv[%d] = %s\n",i,argv[i]);printf("a = %d, b = %d, c = %d\n",a,b,c);return0;}分析argc是命令行参数个数(包括程序名所以默认是一),argv是一个指向字符串数组的指针,里面是参数的具体内容(argv[0]就是程序的文件名/路径)。argc会先判断大于一在自增,直到agrc溢出,溢出按理来说变为负的的最小值,但argc参数为负不太合理不应该有负的索引,所以argc溢出应该提前设置为0了,判断为假再自增为1后退出while,a=1,b=1,c=0。进入if–a=0为假,b=1为真自增为2,c=0为假自减为-1,1&&0为假,所以0||0为假不进入for,最后打印a=0,b=2,c=-1。8. 指针?数组?数组指针?指针数组?在主函数中定义如下变量:intmain(){inta[2]={4,8};int(*b)[2]=&a;int*c[2]={a,a+1};return0;}说说这些输出分别是什么?a, a + 1, &a, &a + 1, *(a + 1), sizeof(a), sizeof(&a)*b, *b + 1, b, b + 1, *(*b + 1), sizeof(*b), sizeof(b)c, c + 1, &c, &c + 1, **(c + 1), sizeof©, sizeof(&c)分析a为整型数组,b是指向数组的指针,c为指针数组(装指针的数组)。a本身为数组,在表达式中为a首元素地址,*b的是数组a,数组a在表达式中退化为首元素地址,c是指针数组在表达式中退化为首元素地址,即指向数组a首元素地址的指针(二级指针)。数组c中装的分别是两个元素的地址。解答第一行的输出为,数组a的首元素地址,a+1在表达式中数组a表示首元素地址,输出是a[1]的地址,&a是数组a的首地址,&a+1此时a代表整个数组步长为两个int加1表示偏移8个字节,*(a+1)表示a[1]的值,a表示数组sizeof(a)表示数组长度8个字节,&a是数组a的首地址表示一个指针,sizeof(&a)为8个字节。*b表示数组a在表达式中为数组a的首元素地址,*b+1与a+1同理为a[1]的地址,b表示指向数组a的指针步长为8个字节,所以b,b+1输出分别是数组a的首地址和数组a首地址加8个字节。后面三个和第一行的最后三个一样。c在表达式中是首元素的地址即arr[0]的二级指针,c+1表示a[1]的二级指针,&c表示数组c的首地址步长为两个指针长度16,&c+1就是数组c的首地址加上16。c+1就是a[1]的二级指解引两次表示a[1]的值,c表示指针数组sizeof(c)就是16个字节,&c表示数组c的首地址即一个指针长度为8个字节。9. 嘻嘻哈哈,好玩好玩在宏的魔法下,数字与文字交织,猜猜结果是什么?#defineSQUARE(x)x*x#defineMAX(a,b)(a>b)?a:b;#definePRINT(x)printf("嘻嘻,结果你猜对了吗,包%d滴\n",x);#defineCONCAT(a,b)a##bintmain(){intCONCAT(x,1)=5;intCONCAT(y,2)=3;intmax=MAX(SQUARE(x1+1),SQUARE(y2))PRINT(max)return0;}分析首先用了两个CONCAT,##就是记号拼接运算符将两个记号拼接。所以CONCAT(x, 1)=5就是x1=5,CONCAT(y, 2)=3就是y2=3。SQUARE(x+1)就是x1+1x1+1=11,SQUARE(y2)就是33=9,MAX(11,9)就是11。PRINT(11)就是printf(“嘻嘻,结果你猜对了吗,包%d滴\n”,11)。最终打印嘻嘻,结果你猜对了吗,包11滴。10. 我写的排序最快写一个 your_sort 函数,要求不能改动 main 函数里的代码,对 arr1 和 arr2 两个数组进行升序排序并剔除相同元素,最后将排序结果放入 result 结构体中。intmain(){intarr1[]={2,3,1,3,2,4,6,7,9,2,10};intarr2[]={2,1,4,3,9,6,8};intlen1=sizeof(arr1)/sizeof(arr1[0]);intlen2=sizeof(arr2)/sizeof(arr2[0]);result result;your_sort(arr1,len1,arr2,len2,&result);for(inti=0;i<result.len;i++){printf("%d ",result.arr[i]);}free(result.arr);return0;}分析函数your_sort作用就是将两个数组合并,排序去重。观察到free(result.arr)说明result.arr是动态分配的,所以在该函数中需要动态分配result的空间。这里结构体还用到了别名result所以要定义typedef struct{int *arr;int len;}result。定义指针变量arr是为了接收动态内存分配的首地址。合并并申请动态内存、排序、去重、放在结构体中。voidyour_sort(int*arr1,intlen1,int*arr2,intlen2,result*res){intlen=len1+len2;res->len=len.res->arr=(int*)malloc(sizeof(int)*len);//合并for(inti=0;i<len1;i++){res->arr[i]=arr1[i];}for(inti=0;i<len2;i++){res->arr[i+len1]=arr2[i];}//排序for(inti=0;i<len-1;i++){for(intj=i+1;j<len;j++){if(res->arr[i]>res->arr[j]){inttemp=res->arr[i];res->arr[i]=res->arr[j];res->arr[j]=temp;}}}}//去重intk=0;for(inti=0;i<len;i++){if(i==0||res->arr[i]!=res->arr[i-1]){res->arr[k++]=res->arr[i];}}res->len=k;//更新内存res->arr=(int*)realloc(res->arr,sizeof(int)*k);11. 猜猜我是谁在指针的迷宫中,五个数字化身为神秘的符号,等待被逐一揭示。intmain(){void*a[]={(void*)1,(void*)2,(void*)3,(void*)4,(void*)5};printf("%d\n",*((char*)a+1));printf("%d\n",*(int*)(char*)a+1);printf("%d\n",*((int*)a+2));printf("%lld\n",*((longlong*)a+3));printf("%d\n",*((short*)a+4));return0;}分析定义了一个指针数组a,里面装的是五个void指针,void指针可以指向任意类型的数据,1是整型占4个字节,强转后为8个字节例a[0]=0x1000000000000000(小端序),一个指针占8个字节。第一行printf,(char*)a将a强制转换成了char类型的指针,+1就表示偏移一个字节,假设a的首地址为0x1000,(char *)a + 1就是将其强转为char类型指针步长变为1,所以地航打印的就是地址0x1001处的值00,即0。第二行printf,先转为char指针类型再转为int类型指针,此时步长为4,所以打印的是地址0x1004处的值00,即0。第三行printf,强转为int类型指针,步长为4,所以打印的是地址0x1008处的值10,即2。第四行printf,强转为long long类型指针,步长为8,所以打印地址0x1018处的值04,即4。第五行printf,强转为short类型指针,步长为2,所以打印地址为0x1008处的值10,即2。12. 结构体变小写奇遇记计算出 Node 结构体的大小,并解释以下代码的运行结果。uniondata{inta;doubleb;shortc;};typedefstructnode{longlonga;uniondata b;void(*change)(structnode*n);charstring[0];}Node;voidfunc(Node*node){for(size_ti=0;node->string[i]!='\0';i++)node->string[i]=tolower(node->string[i]);}intmain(){constchar*s="WELCOME TO XIYOULINUX_GROUP!";Node*P=(Node*)malloc(sizeof(Node)+(strlen(s)+1)*sizeof(char));strcpy(P->string,s);P->change=func;P->change(P);printf("%s\n",P->string);return0;}分析先看共同体的大小,int为四个字节,double为8个字节,short为两个字节,最大成员大小为8个字节且满足double的内存对齐,所以data大小为八个字节。再看结构体Node的大小,long long为8个字节,date为八个字节且此时满足double的内存对齐,此时整体为16个字节,void(change)(struct node)为函数指针,占8个字节,满足内存对齐,char[0]为柔性数组,不占空间,所以Node大小为24个字节。开辟了一个结构体动态内存空间,并将s装进string,strlen(s)+1是因为要算上字符串结束符‘\0’,将函数指针指向func,并执行func§,遍历字符数组string并将其中大写字母转为小写字母(tolowwer函数的作用)。所以最后打印出welcome to xiyoulinux_group!