C语言经典面试笔试题

总结几道C语言经典面试笔试题,涉及联合体,位段,大小端等知识点,有兴趣的可以刷刷。

1.联合体大小问题

#include <stdio.h>
union Un
{
	short s[7];
	int n;
};
int main()
{
  printf("%d\n", sizeof(union Un));
  return 0;
}

联合体大小至少是最大成员大小,而最大成员大小是 short s[7],14字节。
而联合体大小又要求内存对齐,所以要求是最大对齐数4的倍数。所以浪费两个字节
最终大小为16.

结构体向int对齐,7个short一共是14字节,对齐后是16字节。n是单独的4字节,由于是union,所以n与s共用空间,只取最长的元素,故占用16字节。

2.联合体+大小端问题

在X86下,小端字节序存储,有下列程序

#include<stdio.h>
int main()
{
  union
  {
    short k;
    char i[2];
  }*s, a;
  s = &a;
  s->i[0] = 0x39;
  s->i[1] = 0x38;
  printf(%x\n”,a.k);
  return 0;
}

输出结果是(
A.3839
B.3938
C.380039
D.不确定
结果:
在这里插入图片描述
分析:

在这里插入图片描述

3.形参与实参关系+内存开辟问题

关于下面代码描述正确的是(

void GetMemory(char *p)
{
	p = (char *)malloc(100);
}
void Test(void)
{
	char *str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

A.上面代码没问题
B.上面代码存在内存泄露
C.上面代码可能会崩溃,即使GetMemory函数返回,str依然为NULL
D.GetMemory函数无法把malloc开辟的100个字节带回来

在这里插入图片描述

4.位段使用问题

关于下面答案正确的是(

int main()
{
  unsigned char puc[4];
  struct tagPIM
  {
    unsigned char ucPim1;
    unsigned char ucData0 : 1;
    unsigned char ucData1 : 2;
    unsigned char ucData2 : 3;
  }*pstPimData;
  pstPimData = (struct tagPIM*)puc;
  memset(puc,0,4);
  pstPimData->ucPim1 = 2; 
  pstPimData->ucData0 = 3;
  pstPimData->ucData1 = 4;
  pstPimData->ucData2 = 5;
  printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
  return 0;
}

A.02 03 04 05
B.02 29 00 00
C.02 25 00 00
D.02 29 04 00
在这里插入图片描述
puc是一个char数组,每次跳转一个字节,结构体不是,它只有第一个元素单独享用一字节,其他三个元素一起共用一字节,所以puc被结构体填充后,本身只有两个字节会被写入,后两个字节肯定是0,至此AD排除,然后第一个字节是2就是2了,第二个字节比较麻烦,首先ucData0给了3其实是越界了,1位的数字只能是0或1,所以11截断后只有1,同理ucData1给的4也是越界的,100截断后是00,只有5的101是正常的。填充序列是类似小端的低地址在低位,所以排列顺序是00 101 00 1。也就是0010 1001,即0x29,故选B。

5.返回栈空间地址问题

关于下面代码描述正确的是(

char *GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char *str = NULL;
	str = GetMemory();
	printf(str);
}

A.printf函数使用有问题
B.程序正常打印hello world
C.GetMemory函数返回的地址无法正常使用
D.程序存在内存泄露

A.printf函数正常使用
B.程序不一定能打印出来hello world
C是正确的,.GetMemory函数返回的地址赋给str,然后打印这块地址的内容,但要注意局部变量的生命域是在函数内部的,当出了函数,变量就不存在了,那块空间就销毁了,不再受p指针维护。
而str仍然去访问这块空间,就会出问题
D没有动态申请空间,哪里的内存泄漏呢?

说明:此题考的是“局部变量的指针不能做返回值,因为函数内的空间在函数返回后就会释放调”这一点。

6.找单身狗问题1

在这里插入图片描述

int Find1(int arr[],int sz)
{
	int num = 0;
	int i = 0;
	for (i = 0; i < sz; i++)//相同的数异或为0  异或的特点是相同为0,相异为1
	{
		num ^= arr[i];//  1^2^3^4^5^1^2^3^4=5
	}
	return num;
}
int main()
{
	int arr[] = { 1,2,3,4,5,1,2,3,4 };
	//找只出现1次的单身狗
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
    int ret=Find1(arr,sz);//查找
	printf("%d", ret);
	return 0;
}

解题关键:利用异或特点:相同的数异或为0

7.找单身狗问题2

在这里插入图片描述

思路:
找出一个只出现过一次的数字的问题处理方法就是找一个数字把里面所有的数字都异或一遍,利用异或两次等于没异或的特点来处理。那么如果有两个数字都只出现了一次,那么如此得到的应该是两个数异或的结果。首先这个结果肯定不是0(要不然就全都配对了),所以里面一定至少一位是一。找出值为1的一位,以这一位的值将结果分为两组。例如1 2 3 4 1 2,异或完的结果应该是3^4得到的111,那么随便找一位就行了。例如找最低位,那么这一位是1的有1 3 1,是0的有2 4 2,由于是利用异或结果为1的某一位分的组,所以两个待查询数字一定分别在两组中。所以再找两个变量,分别异或两组数,即可找到这两个数。

void Find_single_dog(int arr[], int sz,int single_dog[2])
{
	int ret = 0;
	int i;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	//再找到ret哪位为1,根据1来分类
	int pos = 0;//记录哪个二进制位为1
	for (i = 0; i < 32; i++)
	{
		if (((ret >> i) & 1) == 1)
		{
			pos = i;
			break;
		}
	}
	int num1 = 0;
	int num2 = 0;
	//分类,要将两个单身狗分到不同的组里
	for (i = 0; i < sz; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			num1 ^= arr[i];
		}
		else
		{
			num2 ^= arr[i];
		}
	}
	single_dog[0] = num1;
	single_dog[1] = num2;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
	//有两个数只出现1次,其他数都出现2次,找到这两个数
	//我们可以将这两个数分到两个组里。
	//根据异或,将全部都异或,最后的结果就是两个数异或的结果,异或的结果肯定不为0。那二进制位上肯定有1
	//而出现1是因为这两个数在相同的二进制位上不同而产生的,所以我们可以根据低位为1来区分两个数
	//肯定是一个数是1而另一个数该位为0
	//1.首先全部异或
	int sz = sizeof(arr) / sizeof(arr[0]);
	int single_dog[2] = { 0 };
	Find_single_dog(arr, sz,single_dog);
	printf("%d %d", single_dog[0],single_dog[1]);
	return 0;
}

结果:
在这里插入图片描述

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,下面是c语言笔试面试100: 1. C语言中有哪些数据类型? 2. 如何声明一个整型变量? 3. 如何声明一个字符型变量? 4. 如何声明一个浮点型变量? 5. 如何声明一个双精度型变量? 6. 如何声明一个布尔型变量? 7. 如何声明一个指针变量? 8. 如何定义一个常量? 9. 如何定义一个宏? 10. 什么是变量作用域? 11. 什么是局部变量? 12. 什么是全局变量? 13. 如何定义一个函数? 14. 如何调用一个函数? 15. 什么是指针? 16. 如何定义一个指针? 17. 如何使用指针访问变量? 18. 如何使用指针访问数组元素? 19. 如何使用指针访问结构体成员? 20. 如何使用指针作为函数参数? 21. 如何使用指针返回函数值? 22. 什么是动态内存分配? 23. 如何使用malloc函数分配内存? 24. 如何使用free函数释放内存? 25. 什么是数组? 26. 如何定义一个数组? 27. 如何访问数组元素? 28. 如何使用数组作为函数参数? 29. 如何使用数组作为函数返回值? 30. 什么是字符串? 31. 如何定义一个字符串? 32. 如何初始化一个字符串? 33. 如何比较两个字符串? 34. 如何连接两个字符串? 35. 如何复制一个字符串? 36. 什么是结构体? 37. 如何定义一个结构体? 38. 如何访问结构体成员? 39. 如何使用结构体作为函数参数? 40. 如何使用结构体作为函数返回值? 41. 什么是联合体? 42. 如何定义一个联合体? 43. 如何访问联合体成员? 44. 什么是枚举? 45. 如何定义一个枚举? 46. 如何使用枚举? 47. 什么是位运算? 48. 如何使用位运算? 49. 什么是条件语句? 50. 如何使用if语句? 51. 如何使用switch语句? 52. 什么是循环语句? 53. 如何使用while循环? 54. 如何使用do-while循环? 55. 如何使用for循环? 56. 如何使用break语句? 57. 如何使用continue语句? 58. 什么是函数指针? 59. 如何定义一个函数指针? 60. 如何使用函数指针调用函数? 61. 什么是文件操作? 62. 如何打开一个文件? 63. 如何关闭一个文件? 64. 如何读取一个文件? 65. 如何写入一个文件? 66. 如何复制一个文件? 67. 什么是数据结构? 68. 什么是链表? 69. 如何定义一个链表? 70. 如何遍历一个链表? 71. 如何插入一个节点到链表中? 72. 如何删除一个节点从链表中? 73. 什么是栈? 74. 如何定义一个栈? 75. 如何入栈? 76. 如何出栈? 77. 什么是队列? 78. 如何定义一个队列? 79. 如何入队? 80. 如何出队? 81. 什么是递归? 82. 如何使用递归? 83. 什么是排序? 84. 什么是冒泡排序? 85. 什么是选择排序? 86. 什么是插入排序? 87. 什么是快速排序? 88. 什么是归并排序? 89. 什么是堆排序? 90. 什么是查找? 91. 什么是线性查找? 92. 什么是二分查找? 93. 什么是哈希查找? 94. 什么是图? 95. 什么是有向图? 96. 什么是无向图? 97. 什么是拓扑排序? 98. 什么是最短路径? 99. 什么是最小生成树? 100. 什么是动态规划? 希望这些目能够帮助你更好地准备C语言笔试面试

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小陶来咯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值