目录
题目一:二维数组传参
题目二: malloc开辟二维数组
题目三: 位段
题目四: 联合体
题目五:位段
题目六:找单身狗2
题目一:二维数组传参
下面代码中print_arr函数参数设计哪个是正确的?( )
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
print_arr(arr, 3, 5);
A.void print_arr(int arr[][],int row, int col);
B.void print_arr(int* arr, int row, int col);
C.void print_arr(int (*arr)[5], int row, int col);
D.void print_arr(int (*arr)[3], int row, int col);
答案解析:二维数组相当于数组的数组,传到子函数变成数组的指针。int arr[3][5]相当于是3个元素的arr,每个元素是int [5],所以int [5]是类型说明不能省略。丢失的信息只有数组的元素个数,也就是3,存放一维数组,要使用指向数组的指针,这样才能存放一维数组的地址。A丢了类型中的5,B选项指针层级都错了,D选项5写成了3,故选C。
题目二: malloc开辟二维数组
#include<stdio.h>
#include <stdlib.h>
int main()
{
//动态开辟的方式,模拟实现了二维数组
int **arr = (int**)malloc(3*sizeof(int*));
int i = 0;
for (i = 0; i < 3; i++)
{
*(arr + i) = (int*)malloc(5*sizeof(int));
}
//初始化
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
arr[i][j] = 1;
}
}
//打印
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
//释放
for (i = 0; i < 3; i++)
{
free(arr[i]);
}
free(arr);
arr = NULL;
return 0;
}
答案解析:这种方法每一行元素地址连续,但是不能保证上一行的尾和下一行的开头连续
题目三: 位段
有如下宏定义和结构定义
#define MAX_SIZE A+B
struct _Record_Struct
{
unsigned char Env_Alarm_ID : 4;
unsigned char Para1 : 2;
unsigned char state;
unsigned char avail : 1;
}*Env_Alarm_Record;
struct _Record_Struct* pointer = (struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * MAX_SIZE);
当A=2, B=3时,pointer分配( )个字节的空间。
A.20 B.15 C.11 D.9
答案解析:结构体向最长的char对齐,前两个位段元素一共4+2位,不足8位,合起来占1字节,最后一个单独1字节,一共3字节。另外,#define执行的是查找替换, sizeof(struct _Record_Struct) * MAX_SIZE这个语句其实是3*2+3,结果为9,故选D。
题目四: 联合体
在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.不确定
答案解析:union只有2字节,2字节的十六进制只有4位,所以答案CD排除。而位顺序类似小端,低地址在低处,所以39是低地址,在低位,38在高位,所以是3839,故选A。
题目五:位段
下面代码的结果是( )
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。
题目六:找单身狗2
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6.
void findTwoNum(int arr[], int n, int* pnum1, int* pnum2)
{
int i;
int sum = 0;
for (i = 0; i < 9; i++)
{
sum ^= arr[i];
} //先找到两个数互相异或的结果
int pos;
for (i = 0; i < 32; i++)
{
if (sum & 1 << i)
{
pos = i;
break;
}
} //再找到有分歧的一位。在这一位上,两个数一定是一个1一个0
* pnum1 = *pnum2 = 0;
for (i = 0; i < 10; i++)
{
if (arr[i] & 1 << pos)
{
*pnum1 ^= arr[i]; //这一位是1的,放在数1里
}
else
{
*pnum2 ^= arr[i]; //这一位是0的,放在数2里
}
}
}
答案解析:找出一个只出现过一次的数字的问题处理方法就是找一个数字把里面所有的数字都异或一遍,利用异或两次等于没异或的特点来处理。那么如果有两个数字都只出现了一次,那么如此得到的应该是两个数异或的结果。首先这个结果肯定不是0(要不然就全都配对了),所以里面一定至少一位是一。找出值为1的一位,以这一位的值将结果分为两组。例如1 2 3 4 1 2,异或完的结果应该是3^4得到的111,那么随便找一位就行了。例如找最低位,那么这一位是1的有1 3 1,是0的有2 4 2,由于是利用异或结果为1的某一位分的组,所以两个待查询数字一定分别在两组中。所以再找两个变量,分别异或两组数,即可找到这两个数。