选择题
eg1
如下代码输出的是什么( )
char a=101;
int sum=200;
a+=27;sum+=a;
printf("%d\n",sum);
A: 327 B: 99 C: 328 D: 72
答案解析:
正确答案:D
char为有符号类型,占1个字节,也就是8位,其中最高位是符号位,取值范围为-128~127;a=101+27=128,128表示为1000 0000,作为补码放在内存中,符号位为1,在与int类型的sum进行加计算时会整型提升,高位补1,再转成原码为-128,sum=200+(-128)=72
eg2
假设函数原型和变量说明如下,则调用合法的是( )
void f(int **p);
int a[4]={1,2,3,4};
int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *q[3]={b[0],b[1],b[2]};
A: f(a); B: f(b); C: f(q); D: f(&a);
答案解析:
正确答案:C
A选项,f(a)传参时,a会退化成指向其首元素的地址,类型是 int*,不符。B选项,b是二维数组,传参时会退化成指向其首元素的指针,也就是b[0]的地址,b[0]的类型是int [4],故&b[0]类型是int()[4],不符。D选项,&a是数组a的地址,其类型是int()[4],不符。C选项,q是一个指针数组,在初始化时用b[0]、b[1]、b[2], 此时b[0]、b[1]、b[2]会退化成指向各首元素的指针(int* 类型,因此类型符合,可以用它们初始化)。q传参时,退化成指向其首元素的指针,即 int**,符合33
eg3
假设C语言程序里使用 malloc 申请了内存,但是没有 free 掉,那么当该进程被kill之后,操作系统会( )
A: 内存泄露 B: segmentation fault C: core dump D: 以上都不对
答案解析:
正确答案:D
不管用户程序怎么用malloc,在进程结束的时候,用户程序开辟的内存空间都将会被回收
eg4
如下程序输出的结果是什么( )
#include <stdio.h>
typedef struct List_t
{
struct List_t* next;
struct List_t* prev;
char data[0];
}list_t;
int main()
{
printf("%d",sizeof(list_t));
return 0;
}
A: 4byte B: 8byte C: 5byte D: 9byte
答案解析:
正确答案:B
题目中的char data[0]或写成char data[],即为柔性数组成员;在计算机结构体大小的时候data不占用struct的空间,只是作为一个符号地址存在。因此sizeof的值是两个指针所占字节,即4+4=8字节
eg5
以下有关C语言的说法中,错误的是( )
A: 内存泄露一般是指程序申请了一块内存,使用完后,没有及时将这块内存释放,从而导致程序占用大量内存,但又不使用不释
放
B: 可以通过malloc(size_t)函数调用申请超过该机器物理内存大小的内存块
C: 无法通过内存释放函数free(void*)直接将某块已经使用完的内存直接还给操作系统,free函数只是将动态申请内存的使用
权释放
D: 可以通过内存分配函数malloc(size_t)直接申请物理内存
答案解析:
正确答案:D
free释放的内存不一定直接还给操作系统,可能要到进程结束才释放。malloc不能直接申请物理内存,它申请的是虚拟内存
eg6
以下代码的输出结果是( )
#include <stdio.h>
#define a 10
void foo();
int main()
{
printf("%d..", a);
foo();
printf("%d", a);
return 0;
}
void foo()
{
#undef a
#define a 50
}
A: 10..10 B: 10..50 C: Error D: 0
答案解析:
正确答案:A
define在预处理阶段就把main中的a全部替换为10了。另外,不管是在某个函数内,还是在函数外,define都是从定义开始直到文件结尾,所以如果把foo函数的定义放到main上面的话,则结果会是50…50
编程题
eg1
暴力求解:将字符串中的每个字符都与所有字符比较。,断是否相等。
int FirstNotRepeatingChar(char* str ) {
// write code here
for(int i = 0; i < strlen(str); i++)
{
int flag = 0;//判断第i个字符能否在后面找到
for(int j = 0; j < strlen(str)-i; j++)
{
if(j != i && str[i] == str[j])
{
flag = 1;
break;
}
}
if(flag == 0)
{
return i;
}
}
return -1;
}
eg2
解题思路
统计s中每个字符出现的次数,若s能构成回文串,最多只能容许一个字符出现的次数为奇数。
bool canPermutePalindrome(char* s){
char a[256] = {0};
for(int i = 0; i < strlen(s); i++)
{
a[s[i]]++;
}
int count = 0;
for(int i = 0; i < 128; i++)
{
if(a[i] % 2 != 0)
{
count++;
}
if(count > 1)
{
return false;
}
}
return true;
}
eg3
char* replaceSpaces(char* S, int length0)
{
int count = 0;//计算空格出现的次数
int afterLength = 0;//统计将空格替换为%20后的长度
for(int i = 0; i < length0; i++)
{
if(S[i] == ' ')
{
count++;
}
}
afterLength = length0 + 2 * count;
S[afterLength] = '\0';//先设置字符串结尾标志
int j = 1;//记录afterLenth的位置
for(int i = length0 - 1; i >=0; i--)
{
if(S[i] != ' ')
{
S[afterLength - j] = S[i];
j++;
}
else
{
S[afterLength - j] = '0';
S[afterLength - j - 1] = '2';
S[afterLength - j - 2] = '%';
j += 3;
}
}
return S;
}
eg4
【答案解析】:
注意:这道题是二进制的奇数位和偶数位的交换,只需要把偶数位左移一位,把奇数位右移一位即可
int exchangeBits(int num)
{
int odd = 0b10101010101010101010101010101010;//保留偶位数
int even = 0b01010101010101010101010101010101;//保留奇位数
odd &= num;
even &= num;
return (odd >> 1) + (even << 1);
}
eg5
1、【答案解析】:
求一个数的阶乘中有多少个 尾数0 , 这里就需要灵活一点了 尾数0 是怎么来的?是乘以 10 来的,而 10=2*5 ,阶乘中 2 这个因子很多,但是 5 并不多,因此我们只需要统计 5 出现了多少次即可。
- 暴力方法:遍历 5 的倍数,判断每个 5 的倍数中有多少个 5 ,比如 25=5*5 ,因此25是需要被统计两次的,这种方法直接,但是效率不高,因为当数字比较大的时候循环次数就比较多了…
- 更优思想:以 10 的阶乘为例 10!=12345678910 ,每 5 个数字就会出现一次 5 ,所以 10 / 5 就是 5 出现的次数。
但是特殊的是 25,125… 这种其中包含多个 5 的, 25=55, 125=555… ,他们本身只被统计了一次, 25 还剩 1个乘数5 , 125 还剩 1个乘数25 ,因此这时候就需要再次除以 5 ,得到剩余 5 的个数,直到最后结果小于 5 为止
int trailingZeroes(int n)
{
//时间复杂度O(logN)
int count = 0;
while(n >= 5)
{
count += n / 5;
n /= 5;
}
return count;
//时间复杂度O(N*logN)
/*int count = 0;
for(int i = 0; i <= n; i += 5)
{
int num = i;
while(num > 0 && num % 5 == 0)
{
count++;
num /= 5;
}
}
return count;
}
eg6
这道题其实本身并不难,有了具体的公式直接循环往后推导就可以得到结果。但是当测试用例有多个的情况下,每次重新计算第k个数据,效率就要差很多了,毕竟每个数都要从头重新计算一遍。
因此程序进入后首先可以先生成一个较大的数列,后边测试用例中需要第几个直接取出即可
#include <stdio.h>
int main()
{
int arr[1000000] = {1, 2};
for(int i = 2; i < 1000000; i++)
{
arr[i] = (2 * arr[i - 1] + arr[i - 2]) % 32767;
}
int n = 0;
scanf("%d", &n);
int k = 0;
while(n)
{
scanf("%d", &k);
printf("%d\n", arr[k - 1]);
n--;
}
return 0;
}