xiyoulinux面试题总结

刚开始写面试题的时候,提不上来兴趣,感觉应该没多难,一会就能写完 , 但是看了 面试题之后 ,才发现自己好多东西都没有理解透彻,这才静下心来慢慢写面试题,写完感觉收获特别大 ,面试题里的每一道题往深里研究都能搞一个下午,面试题的质量还是很高的.

1 . 分析一下代码段,并解释输出结果和原因

#include
int main(int argc,char *argv[])
{
	int nums[3][3] = {1,2,3,4,5,6,7,8,9};
	printf("%d\n",nums[1][-2]);
 	printf("%d\n",(-1)[nums][5]);
 	printf("%d\n",-1[nums][5]);
 	return 0;
}
输出结果 : 2,3,-9   

数组操作 可以转换为 指针操作更容易理解.
第一个输出可以理解为 * ( * (nums + 1) - 2)
nums 是一个二级指针,它的的单个元素 是一维数组,所以它 + 1 是 + 一 个 一维数组的字节(3 个int)
而 *(nums+1) 则是一级指针 ,它的单个元素 为 一个 int ,所以 它 -2 是 减 2 个 int 字节,所以最终就是 + 1个 int 也就是 a[1]
第二个 (-1)[nums][5] = nums[-1][5] 之后原理同上
第三个 -1[nums][5] = -(1)[nums][5] = - nums[1][5] 之后原理 同上
2. 分析一下代码段,并解释输出结果和原因

#include
#include
#include
int main()
{ 
  int a[3][2] = {2,0,1,8};
  char *str = (char *)malloc(sizeof(char)*20);
  strcpy(str,"\0101\\xb2");
  printf("%zu\n",sizeof(a));
  printf("%zu %d\n",sizeof(a[1][1] = 0),a[1][1]);
  printf("%d\n",a[1][1]);

  return 0;
}
输出结果  : 24   ,4 , 8   ,     8

这里的%zu 没错 ,在linux下,%zu 是 size_t 的输出类型

这里有个亮点,是a[1][1] = 8; sizeof的 括号里边的是 表达式,在表达式中取到类型名之后,表达式在运行过程中就不再进行运算,也就不会改变 a[1][1] 的值.
3. 谈一谈 static 的 关键字

      static 变量 只完成一次初始化,如果未被初始化,则系统会给 这个变量在 bss 分配一块空间。并且初始化为 0.
      static 修饰的变量 在整个程序运行阶段,只被初始化一次,直到程序结束,这块空间才会被释放.

      static 修饰函数时, 这个函数就只能被本函数调用,其他外部文件 是不能 够调用 这个函数的.

4.一个 c 语言程序从源代码到形成可执行文件的过程,请解释在每个阶段分别完成了什么工作 ?

      从 .c 文件首先进行预处理 生成 .i 文件,.i 文件在经过 编译 生成 .s 文件,.s 文件经过 汇编 生成 .o文件,最后.o 文件生成 连接文件 a.out

5.根据所给代码,说明const关键字的用法

#include 
int main()
{
	 char y[] = "xiyoulinuxgroup",x[] = "2018"
	 char *const p1 = y;     //(1)
	 const char * p2 = y;    //(2)
	 
	 return 0;
}

(1) const 修饰的是 p1 ,则 p1 这个指针变量不能修改
(2) const 修饰的是 *p2 , *p2 所指向的变量不能修改

6.说明下面的两个结构体所占的字节相等吗 ?

	 struct icd
	 {
		  int a;
		  char b;
		  double c; 
	 }st1;

	  struct cdi
	 {
		  char a;
		  double b;
		  int c; 
	 }st2;

结果当然是不想等的.

sizeof(st1) = 16
sizeof(st2) = 24

这里有一个结构体字节对齐的问题.
这里引用一下大佬的 讲解 结构体字节对齐问题

7.分析一下代码段,解释输出的结果.

#define YEAR 2018
#define LEVELONE(x) "xiyoulinux"#x"\n"
#define LEVELTWO(x) LEVELONE(x)
#define MULTIPLY(x,y) x*y

int main(int argc, char *argv[])
{
	int x = MULTIPLY(1+2,3);
	printf("%d\n",x);
	printf(LEVELONE(YEAR));
	printf(LEVETWO(YEAR));
}

输出结果 : 7
           xiyoulinuxYEAR
           xiyoulinux2018

7 的原因是: 1 + 2 * 3 直接将1 + 2 替换为 x ,将 3 替换为 y
第二 个结果 是 因为第二个 宏中有 个 # , # 在宏定义中 能将后面的参数字符串化
第三个结果 就是正常的宏替换.

8.谈谈你对main 函数的理解,从参数,返回值等角度分析, int main(int argc ,char *argv[]) {}

返回值 : 如果 main 函数的 返回值为 0 就代表程序正常结束 ,返回的其他值(不同的系统返回值可能不同)则代表程序异常退出.

参数 : argc 是命令的 个数, argv 代表 参数,可以通过argv[i] 引用

9.解释下面程序的输出结果

#include
#include                                                              
int main( )
{
        int c;
        memcpy(&c,"linux",4);
        printf( "%d\n",c);

        return 0;
}

输出结果 : 1970170220

第 6 行 是将 linux 中的 4 个字节复制给 c ;

二进制 : 1110101011011100110100101101100
十进制 : 1970170220
因为现在的 电脑大多都是 小端序, 所以 将 unil 复制过去,通过 二进制存进 c 中 ,最后在以 十进制输出.

10.解释程序的运行结果

#include
#include
void func(char *a) 
{
        printf( "%lu\n",sizeof(a));
        printf( "%lu\n",strlen(a));
}
int main( )
{
        char a[] = "hello world";                                  
        func(a);
        printf( "%lu\n",sizeof(a));
        printf( "%lu\n",strlen(a));
        return 0;
}
8     字符类型 的指针 ,我的电脑是 8  个字节
11	长度 为11 个字符
12  因为字符串最后会 补上一个 /0 ,所以字节为  12;
11  和 上面的  11  一样

%lu 无符号长整型
%u 以无符号十进制形式输出
%x 以无符号 16 进制形式输出
%o 无符号 8 进制输出

11.解释该函数的输出结果

#include
void func(void)
{
        unsigned int a = 6;
        int b = -20;
        (a+b > 6) ? puts(">6") : puts("<6");                                    
}
int main( )
{
        func();
}
输出 :  >6 

为什么是 > 6 呢? 刚开始的时候特别纳闷. 想了半天才发现 a 是无符号的.
无符号 和 有符号 相加的时候 ,有符号 会自动转化为无符号 之后在进行运算.
而 -20 用补码存的,转化为 无符号的 取反 + 1, 会变成一个 特别大的整数,所以a + b > 6

12 .解释程序的运行结果

#include
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main( )
{
        printf("%s\n",h(f(1,2)));
        printf( "%s\n",g(f(1,2)));
        return 0;                                                               
}
输出结果  : 12
		    f(1,2)

#,@ 单字符化操作符
##是字符连接符号,将 2 个参数链接到一块
13.分析下列程序的输出

#include
int main( )
{
        int t = 4;
        printf( "%lu\n",sizeof(t--));
        printf( "%d\n",t);                                                      
        printf( "%lu\n",sizeof("ab c\nt\012\xa1*2"));
        
        return 0;
}
4
4
11

第二个 4 上面已经讲过了,这就不浪费时间了
/012 8进制 为 1 个字节
/xa 16进制 为 1 个字节

14 .解释下面代码的输出

#include

int main( )
{
        int a = 10,b = 20,c = 30; 
        printf("%d %d\n",b = b*c,c = c*2);
        printf( "%d\n",printf( "%d",a+b+c));

        return 0;                                                               
}

输出结果:
1200 60
12704

printf 是一个入栈的过程,先进后出,也就是说 ,printf 的操作符是 从右往左开始算

先算 c = c * 2,然后再算 b = b*c

15 .对比下面程序在 linux 和 windows 上的输出结果,并思考原因

#include
int main( )
{
        while(1)
        {
                fprintf(stdout,"Group");
                fprintf(stderr,"Xiyoulinux");                                   

                getchar( );
        }
        return 0;
}

输出结果:
linux : xiyoulinuxGroup
win : Groupxiyoulinux

因为在 linux 下 stderr 不带行缓冲 ,stdout 是 带行缓冲 ,遇到 \n 才开始从 缓冲区 读取数据
       win下 stderr 是 不带行缓冲,stdout 是 不带行缓冲. 运行到这一条代码,直接从缓冲区读取数据.

16 .请说出 a 在不同平台的值,并思考此种方式的优点

#ifdef_linux_
	int a  = 1;
#elif _WIN32
	int a = 2;
#elif _APPLE_
	int a = 3;
#else
	int a = 4;
#endif
输出结果 : 
	linux : 1
	WIN32 : 2
	APPLE : 3
	其他 : 4

优点 :防止在多平台编译下,出现相互影响的状况

13 .观察程序的运行结果,说明出现这种情况的原因

#include
#include
int main( )
{
        char str[512];
        int i;
        for(i = 0;i < 512;++i)
        {
                str[i] = -1 - i;
        }
	printf("%lu\n",strlen(str));
}
输出结果: 255

-128 - 1 ------   11111111 - 1 = 01111111 = 127
一直减至 -128 再减为 0
strlen 遇到 0 就停止计算  
所以输出为 255 
14.分析以下函数,给出f(2018)的值,推测并验证函数的作用

int f(unsigned int num)
{
        unsigned int i;
        printf( "%d\n",num);
        for(i = 0;num;i++)     num &= (num-1);
        
        return i;
}
输出结果: i = 7

& 运算符,两个数对应的二进制位 都为 1 结果为 1 ,否则 为 0

第一次循环 num = 2018 & 2017 等价于 11111100010 &  11111100001 结果为 11111100000
                                       即 num = 2016
第二次循环 num = 2016 & 2015 等价于 11111100000 & 11111011111 结果为 11111000000
                                      即 num = 1984
依次类推  直到 num  为0时退出循环

你可能感兴趣的:(C语言)